1 //===-- Breakpoint.cpp ----------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Support/Casting.h"
11 #include "lldb/Breakpoint/Breakpoint.h"
12 #include "lldb/Breakpoint/BreakpointLocation.h"
13 #include "lldb/Breakpoint/BreakpointLocationCollection.h"
14 #include "lldb/Breakpoint/BreakpointPrecondition.h"
15 #include "lldb/Breakpoint/BreakpointResolver.h"
16 #include "lldb/Breakpoint/BreakpointResolverFileLine.h"
17 #include "lldb/Core/Address.h"
18 #include "lldb/Core/Module.h"
19 #include "lldb/Core/ModuleList.h"
20 #include "lldb/Core/SearchFilter.h"
21 #include "lldb/Core/Section.h"
22 #include "lldb/Symbol/CompileUnit.h"
23 #include "lldb/Symbol/Function.h"
24 #include "lldb/Symbol/Symbol.h"
25 #include "lldb/Symbol/SymbolContext.h"
26 #include "lldb/Target/SectionLoadList.h"
27 #include "lldb/Target/Target.h"
28 #include "lldb/Target/ThreadSpec.h"
29 #include "lldb/Utility/LLDBLog.h"
30 #include "lldb/Utility/Log.h"
31 #include "lldb/Utility/Stream.h"
32 #include "lldb/Utility/StreamString.h"
37 using namespace lldb_private
;
40 const char *Breakpoint::g_option_names
[static_cast<uint32_t>(
41 Breakpoint::OptionNames::LastOptionName
)]{"Names", "Hardware"};
43 // Breakpoint constructor
44 Breakpoint::Breakpoint(Target
&target
, SearchFilterSP
&filter_sp
,
45 BreakpointResolverSP
&resolver_sp
, bool hardware
,
46 bool resolve_indirect_symbols
)
47 : m_hardware(hardware
), m_target(target
), m_filter_sp(filter_sp
),
48 m_resolver_sp(resolver_sp
), m_options(true), m_locations(*this),
49 m_resolve_indirect_symbols(resolve_indirect_symbols
), m_hit_counter() {}
51 Breakpoint::Breakpoint(Target
&new_target
, const Breakpoint
&source_bp
)
52 : m_hardware(source_bp
.m_hardware
), m_target(new_target
),
53 m_name_list(source_bp
.m_name_list
), m_options(source_bp
.m_options
),
55 m_resolve_indirect_symbols(source_bp
.m_resolve_indirect_symbols
),
59 Breakpoint::~Breakpoint() = default;
61 BreakpointSP
Breakpoint::CopyFromBreakpoint(TargetSP new_target
,
62 const Breakpoint
& bp_to_copy_from
) {
64 return BreakpointSP();
66 BreakpointSP
bp(new Breakpoint(*new_target
, bp_to_copy_from
));
67 // Now go through and copy the filter & resolver:
68 bp
->m_resolver_sp
= bp_to_copy_from
.m_resolver_sp
->CopyForBreakpoint(bp
);
69 bp
->m_filter_sp
= bp_to_copy_from
.m_filter_sp
->CreateCopy(new_target
);
74 StructuredData::ObjectSP
Breakpoint::SerializeToStructuredData() {
75 // Serialize the resolver:
76 StructuredData::DictionarySP
breakpoint_dict_sp(
77 new StructuredData::Dictionary());
78 StructuredData::DictionarySP
breakpoint_contents_sp(
79 new StructuredData::Dictionary());
81 if (!m_name_list
.empty()) {
82 StructuredData::ArraySP
names_array_sp(new StructuredData::Array());
83 for (auto name
: m_name_list
) {
84 names_array_sp
->AddItem(
85 StructuredData::StringSP(new StructuredData::String(name
)));
87 breakpoint_contents_sp
->AddItem(Breakpoint::GetKey(OptionNames::Names
),
91 breakpoint_contents_sp
->AddBooleanItem(
92 Breakpoint::GetKey(OptionNames::Hardware
), m_hardware
);
94 StructuredData::ObjectSP
resolver_dict_sp(
95 m_resolver_sp
->SerializeToStructuredData());
96 if (!resolver_dict_sp
)
97 return StructuredData::ObjectSP();
99 breakpoint_contents_sp
->AddItem(BreakpointResolver::GetSerializationKey(),
102 StructuredData::ObjectSP
filter_dict_sp(
103 m_filter_sp
->SerializeToStructuredData());
105 return StructuredData::ObjectSP();
107 breakpoint_contents_sp
->AddItem(SearchFilter::GetSerializationKey(),
110 StructuredData::ObjectSP
options_dict_sp(
111 m_options
.SerializeToStructuredData());
112 if (!options_dict_sp
)
113 return StructuredData::ObjectSP();
115 breakpoint_contents_sp
->AddItem(BreakpointOptions::GetSerializationKey(),
118 breakpoint_dict_sp
->AddItem(GetSerializationKey(), breakpoint_contents_sp
);
119 return breakpoint_dict_sp
;
122 lldb::BreakpointSP
Breakpoint::CreateFromStructuredData(
123 TargetSP target_sp
, StructuredData::ObjectSP
&object_data
, Status
&error
) {
124 BreakpointSP result_sp
;
128 StructuredData::Dictionary
*breakpoint_dict
= object_data
->GetAsDictionary();
130 if (!breakpoint_dict
|| !breakpoint_dict
->IsValid()) {
131 error
= Status::FromErrorString(
132 "Can't deserialize from an invalid data object.");
136 StructuredData::Dictionary
*resolver_dict
;
137 bool success
= breakpoint_dict
->GetValueForKeyAsDictionary(
138 BreakpointResolver::GetSerializationKey(), resolver_dict
);
140 error
= Status::FromErrorString(
141 "Breakpoint data missing toplevel resolver key");
146 BreakpointResolverSP resolver_sp
=
147 BreakpointResolver::CreateFromStructuredData(*resolver_dict
,
149 if (create_error
.Fail()) {
150 error
= Status::FromErrorStringWithFormatv(
151 "Error creating breakpoint resolver from data: {0}.", create_error
);
155 StructuredData::Dictionary
*filter_dict
;
156 success
= breakpoint_dict
->GetValueForKeyAsDictionary(
157 SearchFilter::GetSerializationKey(), filter_dict
);
158 SearchFilterSP filter_sp
;
161 std::make_shared
<SearchFilterForUnconstrainedSearches
>(target_sp
);
163 filter_sp
= SearchFilter::CreateFromStructuredData(target_sp
, *filter_dict
,
165 if (create_error
.Fail()) {
166 error
= Status::FromErrorStringWithFormat(
167 "Error creating breakpoint filter from data: %s.",
168 create_error
.AsCString());
173 std::unique_ptr
<BreakpointOptions
> options_up
;
174 StructuredData::Dictionary
*options_dict
;
175 Target
& target
= *target_sp
;
176 success
= breakpoint_dict
->GetValueForKeyAsDictionary(
177 BreakpointOptions::GetSerializationKey(), options_dict
);
179 options_up
= BreakpointOptions::CreateFromStructuredData(
180 target
, *options_dict
, create_error
);
181 if (create_error
.Fail()) {
182 error
= Status::FromErrorStringWithFormat(
183 "Error creating breakpoint options from data: %s.",
184 create_error
.AsCString());
189 bool hardware
= false;
190 success
= breakpoint_dict
->GetValueForKeyAsBoolean(
191 Breakpoint::GetKey(OptionNames::Hardware
), hardware
);
193 result_sp
= target
.CreateBreakpoint(filter_sp
, resolver_sp
, false,
196 if (result_sp
&& options_up
) {
197 result_sp
->m_options
= *options_up
;
200 StructuredData::Array
*names_array
;
201 success
= breakpoint_dict
->GetValueForKeyAsArray(
202 Breakpoint::GetKey(OptionNames::Names
), names_array
);
203 if (success
&& names_array
) {
204 size_t num_names
= names_array
->GetSize();
205 for (size_t i
= 0; i
< num_names
; i
++) {
206 if (std::optional
<llvm::StringRef
> maybe_name
=
207 names_array
->GetItemAtIndexAsString(i
))
208 target
.AddNameToBreakpoint(result_sp
, *maybe_name
, error
);
215 bool Breakpoint::SerializedBreakpointMatchesNames(
216 StructuredData::ObjectSP
&bkpt_object_sp
, std::vector
<std::string
> &names
) {
220 StructuredData::Dictionary
*bkpt_dict
= bkpt_object_sp
->GetAsDictionary();
227 StructuredData::Array
*names_array
;
230 bkpt_dict
->GetValueForKeyAsArray(GetKey(OptionNames::Names
), names_array
);
231 // If there are no names, it can't match these names;
235 size_t num_names
= names_array
->GetSize();
237 for (size_t i
= 0; i
< num_names
; i
++) {
238 std::optional
<llvm::StringRef
> maybe_name
=
239 names_array
->GetItemAtIndexAsString(i
);
240 if (maybe_name
&& llvm::is_contained(names
, *maybe_name
))
246 const lldb::TargetSP
Breakpoint::GetTargetSP() {
247 return m_target
.shared_from_this();
250 bool Breakpoint::IsInternal() const { return LLDB_BREAK_ID_IS_INTERNAL(m_bid
); }
252 BreakpointLocationSP
Breakpoint::AddLocation(const Address
&addr
,
253 bool *new_location
) {
254 return m_locations
.AddLocation(addr
, m_resolve_indirect_symbols
,
258 BreakpointLocationSP
Breakpoint::FindLocationByAddress(const Address
&addr
) {
259 return m_locations
.FindByAddress(addr
);
262 break_id_t
Breakpoint::FindLocationIDByAddress(const Address
&addr
) {
263 return m_locations
.FindIDByAddress(addr
);
266 BreakpointLocationSP
Breakpoint::FindLocationByID(break_id_t bp_loc_id
) {
267 return m_locations
.FindByID(bp_loc_id
);
270 BreakpointLocationSP
Breakpoint::GetLocationAtIndex(size_t index
) {
271 return m_locations
.GetByIndex(index
);
274 void Breakpoint::RemoveInvalidLocations(const ArchSpec
&arch
) {
275 m_locations
.RemoveInvalidLocations(arch
);
278 // For each of the overall options we need to decide how they propagate to the
279 // location options. This will determine the precedence of options on the
280 // breakpoint vs. its locations.
282 // Disable at the breakpoint level should override the location settings. That
283 // way you can conveniently turn off a whole breakpoint without messing up the
284 // individual settings.
286 void Breakpoint::SetEnabled(bool enable
) {
287 if (enable
== m_options
.IsEnabled())
290 m_options
.SetEnabled(enable
);
292 m_locations
.ResolveAllBreakpointSites();
294 m_locations
.ClearAllBreakpointSites();
296 SendBreakpointChangedEvent(enable
? eBreakpointEventTypeEnabled
297 : eBreakpointEventTypeDisabled
);
300 bool Breakpoint::IsEnabled() { return m_options
.IsEnabled(); }
302 void Breakpoint::SetIgnoreCount(uint32_t n
) {
303 if (m_options
.GetIgnoreCount() == n
)
306 m_options
.SetIgnoreCount(n
);
307 SendBreakpointChangedEvent(eBreakpointEventTypeIgnoreChanged
);
310 void Breakpoint::DecrementIgnoreCount() {
311 uint32_t ignore
= m_options
.GetIgnoreCount();
313 m_options
.SetIgnoreCount(ignore
- 1);
316 uint32_t Breakpoint::GetIgnoreCount() const {
317 return m_options
.GetIgnoreCount();
320 uint32_t Breakpoint::GetHitCount() const { return m_hit_counter
.GetValue(); }
322 void Breakpoint::ResetHitCount() {
323 m_hit_counter
.Reset();
324 m_locations
.ResetHitCount();
327 bool Breakpoint::IsOneShot() const { return m_options
.IsOneShot(); }
329 void Breakpoint::SetOneShot(bool one_shot
) { m_options
.SetOneShot(one_shot
); }
331 bool Breakpoint::IsAutoContinue() const { return m_options
.IsAutoContinue(); }
333 void Breakpoint::SetAutoContinue(bool auto_continue
) {
334 m_options
.SetAutoContinue(auto_continue
);
337 void Breakpoint::SetThreadID(lldb::tid_t thread_id
) {
338 if (m_options
.GetThreadSpec()->GetTID() == thread_id
)
341 m_options
.GetThreadSpec()->SetTID(thread_id
);
342 SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged
);
345 lldb::tid_t
Breakpoint::GetThreadID() const {
346 if (m_options
.GetThreadSpecNoCreate() == nullptr)
347 return LLDB_INVALID_THREAD_ID
;
349 return m_options
.GetThreadSpecNoCreate()->GetTID();
352 void Breakpoint::SetThreadIndex(uint32_t index
) {
353 if (m_options
.GetThreadSpec()->GetIndex() == index
)
356 m_options
.GetThreadSpec()->SetIndex(index
);
357 SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged
);
360 uint32_t Breakpoint::GetThreadIndex() const {
361 if (m_options
.GetThreadSpecNoCreate() == nullptr)
364 return m_options
.GetThreadSpecNoCreate()->GetIndex();
367 void Breakpoint::SetThreadName(const char *thread_name
) {
368 if (m_options
.GetThreadSpec()->GetName() != nullptr &&
369 ::strcmp(m_options
.GetThreadSpec()->GetName(), thread_name
) == 0)
372 m_options
.GetThreadSpec()->SetName(thread_name
);
373 SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged
);
376 const char *Breakpoint::GetThreadName() const {
377 if (m_options
.GetThreadSpecNoCreate() == nullptr)
380 return m_options
.GetThreadSpecNoCreate()->GetName();
383 void Breakpoint::SetQueueName(const char *queue_name
) {
384 if (m_options
.GetThreadSpec()->GetQueueName() != nullptr &&
385 ::strcmp(m_options
.GetThreadSpec()->GetQueueName(), queue_name
) == 0)
388 m_options
.GetThreadSpec()->SetQueueName(queue_name
);
389 SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged
);
392 const char *Breakpoint::GetQueueName() const {
393 if (m_options
.GetThreadSpecNoCreate() == nullptr)
396 return m_options
.GetThreadSpecNoCreate()->GetQueueName();
399 void Breakpoint::SetCondition(const char *condition
) {
400 m_options
.SetCondition(condition
);
401 SendBreakpointChangedEvent(eBreakpointEventTypeConditionChanged
);
404 const char *Breakpoint::GetConditionText() const {
405 return m_options
.GetConditionText();
408 // This function is used when "baton" doesn't need to be freed
409 void Breakpoint::SetCallback(BreakpointHitCallback callback
, void *baton
,
410 bool is_synchronous
) {
411 // The default "Baton" class will keep a copy of "baton" and won't free or
412 // delete it when it goes out of scope.
413 m_options
.SetCallback(callback
, std::make_shared
<UntypedBaton
>(baton
),
416 SendBreakpointChangedEvent(eBreakpointEventTypeCommandChanged
);
419 // This function is used when a baton needs to be freed and therefore is
420 // contained in a "Baton" subclass.
421 void Breakpoint::SetCallback(BreakpointHitCallback callback
,
422 const BatonSP
&callback_baton_sp
,
423 bool is_synchronous
) {
424 m_options
.SetCallback(callback
, callback_baton_sp
, is_synchronous
);
427 void Breakpoint::ClearCallback() { m_options
.ClearCallback(); }
429 bool Breakpoint::InvokeCallback(StoppointCallbackContext
*context
,
430 break_id_t bp_loc_id
) {
431 return m_options
.InvokeCallback(context
, GetID(), bp_loc_id
);
434 BreakpointOptions
&Breakpoint::GetOptions() { return m_options
; }
436 const BreakpointOptions
&Breakpoint::GetOptions() const { return m_options
; }
438 void Breakpoint::ResolveBreakpoint() {
440 ElapsedTime
elapsed(m_resolve_time
);
441 m_resolver_sp
->ResolveBreakpoint(*m_filter_sp
);
445 void Breakpoint::ResolveBreakpointInModules(
446 ModuleList
&module_list
, BreakpointLocationCollection
&new_locations
) {
447 ElapsedTime
elapsed(m_resolve_time
);
448 m_locations
.StartRecordingNewLocations(new_locations
);
450 m_resolver_sp
->ResolveBreakpointInModules(*m_filter_sp
, module_list
);
452 m_locations
.StopRecordingNewLocations();
455 void Breakpoint::ResolveBreakpointInModules(ModuleList
&module_list
,
458 // If this is not an internal breakpoint, set up to record the new
459 // locations, then dispatch an event with the new locations.
460 if (!IsInternal() && send_event
) {
461 std::shared_ptr
<BreakpointEventData
> new_locations_event
=
462 std::make_shared
<BreakpointEventData
>(
463 eBreakpointEventTypeLocationsAdded
, shared_from_this());
464 ResolveBreakpointInModules(
465 module_list
, new_locations_event
->GetBreakpointLocationCollection());
466 if (new_locations_event
->GetBreakpointLocationCollection().GetSize() != 0)
467 SendBreakpointChangedEvent(new_locations_event
);
469 ElapsedTime
elapsed(m_resolve_time
);
470 m_resolver_sp
->ResolveBreakpointInModules(*m_filter_sp
, module_list
);
475 void Breakpoint::ClearAllBreakpointSites() {
476 m_locations
.ClearAllBreakpointSites();
479 // ModulesChanged: Pass in a list of new modules, and
481 void Breakpoint::ModulesChanged(ModuleList
&module_list
, bool load
,
482 bool delete_locations
) {
483 Log
*log
= GetLog(LLDBLog::Breakpoints
);
485 "Breakpoint::ModulesChanged: num_modules: %zu load: %i "
486 "delete_locations: %i\n",
487 module_list
.GetSize(), load
, delete_locations
);
490 // The logic for handling new modules is:
491 // 1) If the filter rejects this module, then skip it. 2) Run through the
492 // current location list and if there are any locations
493 // for that module, we mark the module as "seen" and we don't try to
495 // breakpoint locations for that module.
496 // However, we do add breakpoint sites to these locations if needed.
497 // 3) If we don't see this module in our breakpoint location list, call
500 ModuleList new_modules
; // We'll stuff the "unseen" modules in this list,
502 // them after the locations pass. Have to do it this way because resolving
503 // breakpoints will add new locations potentially.
505 for (ModuleSP module_sp
: module_list
.Modules()) {
507 if (!m_filter_sp
->ModulePasses(module_sp
))
510 BreakpointLocationCollection locations_with_no_section
;
511 for (BreakpointLocationSP break_loc_sp
:
512 m_locations
.BreakpointLocations()) {
514 // If the section for this location was deleted, that means it's Module
515 // has gone away but somebody forgot to tell us. Let's clean it up
517 Address
section_addr(break_loc_sp
->GetAddress());
518 if (section_addr
.SectionWasDeleted()) {
519 locations_with_no_section
.Add(break_loc_sp
);
523 if (!break_loc_sp
->IsEnabled())
526 SectionSP
section_sp(section_addr
.GetSection());
528 // If we don't have a Section, that means this location is a raw
529 // address that we haven't resolved to a section yet. So we'll have to
530 // look in all the new modules to resolve this location. Otherwise, if
531 // it was set in this module, re-resolve it here.
532 if (section_sp
&& section_sp
->GetModule() == module_sp
) {
536 if (!break_loc_sp
->ResolveBreakpointSite()) {
538 "Warning: could not set breakpoint site for "
539 "breakpoint location %d of breakpoint %d.\n",
540 break_loc_sp
->GetID(), GetID());
545 size_t num_to_delete
= locations_with_no_section
.GetSize();
547 for (size_t i
= 0; i
< num_to_delete
; i
++)
548 m_locations
.RemoveLocation(locations_with_no_section
.GetByIndex(i
));
551 new_modules
.AppendIfNeeded(module_sp
);
554 if (new_modules
.GetSize() > 0) {
555 ResolveBreakpointInModules(new_modules
);
558 // Go through the currently set locations and if any have breakpoints in
559 // the module list, then remove their breakpoint sites, and their locations
562 std::shared_ptr
<BreakpointEventData
> removed_locations_event
;
564 removed_locations_event
= std::make_shared
<BreakpointEventData
>(
565 eBreakpointEventTypeLocationsRemoved
, shared_from_this());
567 for (ModuleSP module_sp
: module_list
.Modules()) {
568 if (m_filter_sp
->ModulePasses(module_sp
)) {
570 size_t num_locations
= m_locations
.GetSize();
571 BreakpointLocationCollection locations_to_remove
;
572 for (loc_idx
= 0; loc_idx
< num_locations
; loc_idx
++) {
573 BreakpointLocationSP
break_loc_sp(m_locations
.GetByIndex(loc_idx
));
574 SectionSP
section_sp(break_loc_sp
->GetAddress().GetSection());
575 if (section_sp
&& section_sp
->GetModule() == module_sp
) {
576 // Remove this breakpoint since the shared library is unloaded, but
577 // keep the breakpoint location around so we always get complete
578 // hit count and breakpoint lifetime info
579 break_loc_sp
->ClearBreakpointSite();
580 if (removed_locations_event
) {
581 removed_locations_event
->GetBreakpointLocationCollection().Add(
584 if (delete_locations
)
585 locations_to_remove
.Add(break_loc_sp
);
589 if (delete_locations
) {
590 size_t num_locations_to_remove
= locations_to_remove
.GetSize();
591 for (loc_idx
= 0; loc_idx
< num_locations_to_remove
; loc_idx
++)
592 m_locations
.RemoveLocation(locations_to_remove
.GetByIndex(loc_idx
));
596 SendBreakpointChangedEvent(removed_locations_event
);
600 static bool SymbolContextsMightBeEquivalent(SymbolContext
&old_sc
,
601 SymbolContext
&new_sc
) {
602 bool equivalent_scs
= false;
604 if (old_sc
.module_sp
.get() == new_sc
.module_sp
.get()) {
605 // If these come from the same module, we can directly compare the
607 if (old_sc
.comp_unit
&& new_sc
.comp_unit
&&
608 (old_sc
.comp_unit
== new_sc
.comp_unit
)) {
609 if (old_sc
.function
&& new_sc
.function
&&
610 (old_sc
.function
== new_sc
.function
)) {
611 equivalent_scs
= true;
613 } else if (old_sc
.symbol
&& new_sc
.symbol
&&
614 (old_sc
.symbol
== new_sc
.symbol
)) {
615 equivalent_scs
= true;
618 // Otherwise we will compare by name...
619 if (old_sc
.comp_unit
&& new_sc
.comp_unit
) {
620 if (old_sc
.comp_unit
->GetPrimaryFile() ==
621 new_sc
.comp_unit
->GetPrimaryFile()) {
622 // Now check the functions:
623 if (old_sc
.function
&& new_sc
.function
&&
624 (old_sc
.function
->GetName() == new_sc
.function
->GetName())) {
625 equivalent_scs
= true;
628 } else if (old_sc
.symbol
&& new_sc
.symbol
) {
629 if (Mangled::Compare(old_sc
.symbol
->GetMangled(),
630 new_sc
.symbol
->GetMangled()) == 0) {
631 equivalent_scs
= true;
635 return equivalent_scs
;
638 void Breakpoint::ModuleReplaced(ModuleSP old_module_sp
,
639 ModuleSP new_module_sp
) {
640 Log
*log
= GetLog(LLDBLog::Breakpoints
);
641 LLDB_LOGF(log
, "Breakpoint::ModulesReplaced for %s\n",
642 old_module_sp
->GetSpecificationDescription().c_str());
643 // First find all the locations that are in the old module
645 BreakpointLocationCollection old_break_locs
;
646 for (BreakpointLocationSP break_loc_sp
: m_locations
.BreakpointLocations()) {
647 SectionSP section_sp
= break_loc_sp
->GetAddress().GetSection();
648 if (section_sp
&& section_sp
->GetModule() == old_module_sp
) {
649 old_break_locs
.Add(break_loc_sp
);
653 size_t num_old_locations
= old_break_locs
.GetSize();
655 if (num_old_locations
== 0) {
656 // There were no locations in the old module, so we just need to check if
657 // there were any in the new module.
658 ModuleList temp_list
;
659 temp_list
.Append(new_module_sp
);
660 ResolveBreakpointInModules(temp_list
);
662 // First search the new module for locations. Then compare this with the
663 // old list, copy over locations that "look the same" Then delete the old
664 // locations. Finally remember to post the creation event.
666 // Two locations are the same if they have the same comp unit & function
667 // (by name) and there are the same number of locations in the old function
668 // as in the new one.
670 ModuleList temp_list
;
671 temp_list
.Append(new_module_sp
);
672 BreakpointLocationCollection new_break_locs
;
673 ResolveBreakpointInModules(temp_list
, new_break_locs
);
674 BreakpointLocationCollection locations_to_remove
;
675 BreakpointLocationCollection locations_to_announce
;
677 size_t num_new_locations
= new_break_locs
.GetSize();
679 if (num_new_locations
> 0) {
680 // Break out the case of one location -> one location since that's the
681 // most common one, and there's no need to build up the structures needed
682 // for the merge in that case.
683 if (num_new_locations
== 1 && num_old_locations
== 1) {
684 bool equivalent_locations
= false;
685 SymbolContext old_sc
, new_sc
;
686 // The only way the old and new location can be equivalent is if they
687 // have the same amount of information:
688 BreakpointLocationSP old_loc_sp
= old_break_locs
.GetByIndex(0);
689 BreakpointLocationSP new_loc_sp
= new_break_locs
.GetByIndex(0);
691 if (old_loc_sp
->GetAddress().CalculateSymbolContext(&old_sc
) ==
692 new_loc_sp
->GetAddress().CalculateSymbolContext(&new_sc
)) {
693 equivalent_locations
=
694 SymbolContextsMightBeEquivalent(old_sc
, new_sc
);
697 if (equivalent_locations
) {
698 m_locations
.SwapLocation(old_loc_sp
, new_loc_sp
);
700 locations_to_remove
.Add(old_loc_sp
);
701 locations_to_announce
.Add(new_loc_sp
);
704 // We don't want to have to keep computing the SymbolContexts for these
705 // addresses over and over, so lets get them up front:
707 typedef std::map
<lldb::break_id_t
, SymbolContext
> IDToSCMap
;
708 IDToSCMap old_sc_map
;
709 for (size_t idx
= 0; idx
< num_old_locations
; idx
++) {
711 BreakpointLocationSP bp_loc_sp
= old_break_locs
.GetByIndex(idx
);
712 lldb::break_id_t loc_id
= bp_loc_sp
->GetID();
713 bp_loc_sp
->GetAddress().CalculateSymbolContext(&old_sc_map
[loc_id
]);
716 std::map
<lldb::break_id_t
, SymbolContext
> new_sc_map
;
717 for (size_t idx
= 0; idx
< num_new_locations
; idx
++) {
719 BreakpointLocationSP bp_loc_sp
= new_break_locs
.GetByIndex(idx
);
720 lldb::break_id_t loc_id
= bp_loc_sp
->GetID();
721 bp_loc_sp
->GetAddress().CalculateSymbolContext(&new_sc_map
[loc_id
]);
723 // Take an element from the old Symbol Contexts
724 while (old_sc_map
.size() > 0) {
725 lldb::break_id_t old_id
= old_sc_map
.begin()->first
;
726 SymbolContext
&old_sc
= old_sc_map
.begin()->second
;
728 // Count the number of entries equivalent to this SC for the old
730 std::vector
<lldb::break_id_t
> old_id_vec
;
731 old_id_vec
.push_back(old_id
);
733 IDToSCMap::iterator tmp_iter
;
734 for (tmp_iter
= ++old_sc_map
.begin(); tmp_iter
!= old_sc_map
.end();
736 if (SymbolContextsMightBeEquivalent(old_sc
, tmp_iter
->second
))
737 old_id_vec
.push_back(tmp_iter
->first
);
740 // Now find all the equivalent locations in the new list.
741 std::vector
<lldb::break_id_t
> new_id_vec
;
742 for (tmp_iter
= new_sc_map
.begin(); tmp_iter
!= new_sc_map
.end();
744 if (SymbolContextsMightBeEquivalent(old_sc
, tmp_iter
->second
))
745 new_id_vec
.push_back(tmp_iter
->first
);
748 // Alright, if we have the same number of potentially equivalent
749 // locations in the old and new modules, we'll just map them one to
750 // one in ascending ID order (assuming the resolver's order would
751 // match the equivalent ones. Otherwise, we'll dump all the old ones,
752 // and just take the new ones, erasing the elements from both maps as
755 if (old_id_vec
.size() == new_id_vec
.size()) {
756 llvm::sort(old_id_vec
);
757 llvm::sort(new_id_vec
);
758 size_t num_elements
= old_id_vec
.size();
759 for (size_t idx
= 0; idx
< num_elements
; idx
++) {
760 BreakpointLocationSP old_loc_sp
=
761 old_break_locs
.FindByIDPair(GetID(), old_id_vec
[idx
]);
762 BreakpointLocationSP new_loc_sp
=
763 new_break_locs
.FindByIDPair(GetID(), new_id_vec
[idx
]);
764 m_locations
.SwapLocation(old_loc_sp
, new_loc_sp
);
765 old_sc_map
.erase(old_id_vec
[idx
]);
766 new_sc_map
.erase(new_id_vec
[idx
]);
769 for (lldb::break_id_t old_id
: old_id_vec
) {
770 locations_to_remove
.Add(
771 old_break_locs
.FindByIDPair(GetID(), old_id
));
772 old_sc_map
.erase(old_id
);
774 for (lldb::break_id_t new_id
: new_id_vec
) {
775 locations_to_announce
.Add(
776 new_break_locs
.FindByIDPair(GetID(), new_id
));
777 new_sc_map
.erase(new_id
);
784 // Now remove the remaining old locations, and cons up a removed locations
785 // event. Note, we don't put the new locations that were swapped with an
786 // old location on the locations_to_remove list, so we don't need to worry
787 // about telling the world about removing a location we didn't tell them
790 std::shared_ptr
<BreakpointEventData
> removed_locations_event
;
792 removed_locations_event
= std::make_shared
<BreakpointEventData
>(
793 eBreakpointEventTypeLocationsRemoved
, shared_from_this());
795 for (BreakpointLocationSP loc_sp
:
796 locations_to_remove
.BreakpointLocations()) {
797 m_locations
.RemoveLocation(loc_sp
);
798 if (removed_locations_event
)
799 removed_locations_event
->GetBreakpointLocationCollection().Add(loc_sp
);
801 SendBreakpointChangedEvent(removed_locations_event
);
803 // And announce the new ones.
806 std::shared_ptr
<BreakpointEventData
> added_locations_event
=
807 std::make_shared
<BreakpointEventData
>(
808 eBreakpointEventTypeLocationsAdded
, shared_from_this());
809 for (BreakpointLocationSP loc_sp
:
810 locations_to_announce
.BreakpointLocations())
811 added_locations_event
->GetBreakpointLocationCollection().Add(loc_sp
);
813 SendBreakpointChangedEvent(added_locations_event
);
815 m_locations
.Compact();
819 void Breakpoint::Dump(Stream
*) {}
821 size_t Breakpoint::GetNumResolvedLocations() const {
822 // Return the number of breakpoints that are actually resolved and set down
823 // in the inferior process.
824 return m_locations
.GetNumResolvedLocations();
827 bool Breakpoint::HasResolvedLocations() const {
828 return GetNumResolvedLocations() > 0;
831 size_t Breakpoint::GetNumLocations() const { return m_locations
.GetSize(); }
833 void Breakpoint::AddName(llvm::StringRef new_name
) {
834 m_name_list
.insert(new_name
.str());
837 void Breakpoint::GetDescription(Stream
*s
, lldb::DescriptionLevel level
,
838 bool show_locations
) {
839 assert(s
!= nullptr);
841 if (!m_kind_description
.empty()) {
842 if (level
== eDescriptionLevelBrief
) {
843 s
->PutCString(GetBreakpointKind());
846 s
->Printf("Kind: %s\n", GetBreakpointKind());
849 const size_t num_locations
= GetNumLocations();
850 const size_t num_resolved_locations
= GetNumResolvedLocations();
852 // They just made the breakpoint, they don't need to be told HOW they made
853 // it... Also, we'll print the breakpoint number differently depending on
854 // whether there is 1 or more locations.
855 if (level
!= eDescriptionLevelInitial
) {
856 s
->Printf("%i: ", GetID());
857 GetResolverDescription(s
);
858 GetFilterDescription(s
);
862 case lldb::eDescriptionLevelBrief
:
863 case lldb::eDescriptionLevelFull
:
864 if (num_locations
> 0) {
865 s
->Printf(", locations = %" PRIu64
, (uint64_t)num_locations
);
866 if (num_resolved_locations
> 0)
867 s
->Printf(", resolved = %" PRIu64
", hit count = %d",
868 (uint64_t)num_resolved_locations
, GetHitCount());
870 // Don't print the pending notification for exception resolvers since we
871 // don't generally know how to set them until the target is run.
872 if (m_resolver_sp
->getResolverID() !=
873 BreakpointResolver::ExceptionResolver
)
874 s
->Printf(", locations = 0 (pending)");
877 m_options
.GetDescription(s
, level
);
879 if (m_precondition_sp
)
880 m_precondition_sp
->GetDescription(*s
, level
);
882 if (level
== lldb::eDescriptionLevelFull
) {
883 if (!m_name_list
.empty()) {
889 for (const std::string
&name
: m_name_list
) {
891 s
->Printf("%s\n", name
.c_str());
900 case lldb::eDescriptionLevelInitial
:
901 s
->Printf("Breakpoint %i: ", GetID());
902 if (num_locations
== 0) {
903 s
->Printf("no locations (pending).");
904 } else if (num_locations
== 1 && !show_locations
) {
905 // There is only one location, so we'll just print that location
907 GetLocationAtIndex(0)->GetDescription(s
, level
);
909 s
->Printf("%" PRIu64
" locations.", static_cast<uint64_t>(num_locations
));
914 case lldb::eDescriptionLevelVerbose
:
915 // Verbose mode does a debug dump of the breakpoint
919 m_options
.GetDescription(s
, level
);
926 // The brief description is just the location name (1.2 or whatever). That's
927 // pointless to show in the breakpoint's description, so suppress it.
928 if (show_locations
&& level
!= lldb::eDescriptionLevelBrief
) {
930 for (size_t i
= 0; i
< num_locations
; ++i
) {
931 BreakpointLocation
*loc
= GetLocationAtIndex(i
).get();
932 loc
->GetDescription(s
, level
);
939 void Breakpoint::GetResolverDescription(Stream
*s
) {
941 m_resolver_sp
->GetDescription(s
);
944 bool Breakpoint::GetMatchingFileLine(ConstString filename
,
945 uint32_t line_number
,
946 BreakpointLocationCollection
&loc_coll
) {
947 // TODO: To be correct, this method needs to fill the breakpoint location
949 // with the location IDs which match the filename and line_number.
953 BreakpointResolverFileLine
*resolverFileLine
=
954 dyn_cast
<BreakpointResolverFileLine
>(m_resolver_sp
.get());
956 // TODO: Handle SourceLocationSpec column information
957 if (resolverFileLine
&&
958 resolverFileLine
->m_location_spec
.GetFileSpec().GetFilename() ==
960 resolverFileLine
->m_location_spec
.GetLine() == line_number
) {
967 void Breakpoint::GetFilterDescription(Stream
*s
) {
968 m_filter_sp
->GetDescription(s
);
971 bool Breakpoint::EvaluatePrecondition(StoppointCallbackContext
&context
) {
972 if (!m_precondition_sp
)
975 return m_precondition_sp
->EvaluatePrecondition(context
);
978 void Breakpoint::SendBreakpointChangedEvent(
979 lldb::BreakpointEventType eventKind
) {
980 if (!IsInternal() && GetTarget().EventTypeHasListeners(
981 Target::eBroadcastBitBreakpointChanged
)) {
982 std::shared_ptr
<BreakpointEventData
> data
=
983 std::make_shared
<BreakpointEventData
>(eventKind
, shared_from_this());
985 GetTarget().BroadcastEvent(Target::eBroadcastBitBreakpointChanged
, data
);
989 void Breakpoint::SendBreakpointChangedEvent(
990 const lldb::EventDataSP
&breakpoint_data_sp
) {
991 if (!breakpoint_data_sp
)
995 GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged
))
996 GetTarget().BroadcastEvent(Target::eBroadcastBitBreakpointChanged
,
1000 const char *Breakpoint::BreakpointEventTypeAsCString(BreakpointEventType type
) {
1002 case eBreakpointEventTypeInvalidType
: return "invalid";
1003 case eBreakpointEventTypeAdded
: return "breakpoint added";
1004 case eBreakpointEventTypeRemoved
: return "breakpoint removed";
1005 case eBreakpointEventTypeLocationsAdded
: return "locations added";
1006 case eBreakpointEventTypeLocationsRemoved
: return "locations removed";
1007 case eBreakpointEventTypeLocationsResolved
: return "locations resolved";
1008 case eBreakpointEventTypeEnabled
: return "breakpoint enabled";
1009 case eBreakpointEventTypeDisabled
: return "breakpoint disabled";
1010 case eBreakpointEventTypeCommandChanged
: return "command changed";
1011 case eBreakpointEventTypeConditionChanged
: return "condition changed";
1012 case eBreakpointEventTypeIgnoreChanged
: return "ignore count changed";
1013 case eBreakpointEventTypeThreadChanged
: return "thread changed";
1014 case eBreakpointEventTypeAutoContinueChanged
: return "autocontinue changed";
1016 llvm_unreachable("Fully covered switch above!");
1019 Log
*Breakpoint::BreakpointEventData::GetLogChannel() {
1020 return GetLog(LLDBLog::Breakpoints
);
1023 Breakpoint::BreakpointEventData::BreakpointEventData(
1024 BreakpointEventType sub_type
, const BreakpointSP
&new_breakpoint_sp
)
1025 : m_breakpoint_event(sub_type
), m_new_breakpoint_sp(new_breakpoint_sp
) {}
1027 Breakpoint::BreakpointEventData::~BreakpointEventData() = default;
1029 llvm::StringRef
Breakpoint::BreakpointEventData::GetFlavorString() {
1030 return "Breakpoint::BreakpointEventData";
1033 llvm::StringRef
Breakpoint::BreakpointEventData::GetFlavor() const {
1034 return BreakpointEventData::GetFlavorString();
1037 BreakpointSP
Breakpoint::BreakpointEventData::GetBreakpoint() const {
1038 return m_new_breakpoint_sp
;
1042 Breakpoint::BreakpointEventData::GetBreakpointEventType() const {
1043 return m_breakpoint_event
;
1046 void Breakpoint::BreakpointEventData::Dump(Stream
*s
) const {
1049 BreakpointEventType event_type
= GetBreakpointEventType();
1050 break_id_t bkpt_id
= GetBreakpoint()->GetID();
1051 s
->Format("bkpt: {0} type: {1}", bkpt_id
,
1052 BreakpointEventTypeAsCString(event_type
));
1055 const Breakpoint::BreakpointEventData
*
1056 Breakpoint::BreakpointEventData::GetEventDataFromEvent(const Event
*event
) {
1058 const EventData
*event_data
= event
->GetData();
1060 event_data
->GetFlavor() == BreakpointEventData::GetFlavorString())
1061 return static_cast<const BreakpointEventData
*>(event
->GetData());
1067 Breakpoint::BreakpointEventData::GetBreakpointEventTypeFromEvent(
1068 const EventSP
&event_sp
) {
1069 const BreakpointEventData
*data
= GetEventDataFromEvent(event_sp
.get());
1071 if (data
== nullptr)
1072 return eBreakpointEventTypeInvalidType
;
1074 return data
->GetBreakpointEventType();
1077 BreakpointSP
Breakpoint::BreakpointEventData::GetBreakpointFromEvent(
1078 const EventSP
&event_sp
) {
1081 const BreakpointEventData
*data
= GetEventDataFromEvent(event_sp
.get());
1083 bp_sp
= data
->m_new_breakpoint_sp
;
1088 size_t Breakpoint::BreakpointEventData::GetNumBreakpointLocationsFromEvent(
1089 const EventSP
&event_sp
) {
1090 const BreakpointEventData
*data
= GetEventDataFromEvent(event_sp
.get());
1092 return data
->m_locations
.GetSize();
1097 lldb::BreakpointLocationSP
1098 Breakpoint::BreakpointEventData::GetBreakpointLocationAtIndexFromEvent(
1099 const lldb::EventSP
&event_sp
, uint32_t bp_loc_idx
) {
1100 lldb::BreakpointLocationSP bp_loc_sp
;
1102 const BreakpointEventData
*data
= GetEventDataFromEvent(event_sp
.get());
1104 bp_loc_sp
= data
->m_locations
.GetByIndex(bp_loc_idx
);
1110 json::Value
Breakpoint::GetStatistics() {
1112 bp
.try_emplace("id", GetID());
1113 bp
.try_emplace("resolveTime", m_resolve_time
.get().count());
1114 bp
.try_emplace("numLocations", (int64_t)GetNumLocations());
1115 bp
.try_emplace("numResolvedLocations", (int64_t)GetNumResolvedLocations());
1116 bp
.try_emplace("hitCount", (int64_t)GetHitCount());
1117 bp
.try_emplace("internal", IsInternal());
1118 if (!m_kind_description
.empty())
1119 bp
.try_emplace("kindDescription", m_kind_description
);
1120 // Put the full structured data for reproducing this breakpoint in a key/value
1121 // pair named "details". This allows the breakpoint's details to be visible
1122 // in the stats in case we need to reproduce a breakpoint that has long
1124 StructuredData::ObjectSP bp_data_sp
= SerializeToStructuredData();
1127 llvm::raw_string_ostream
ss(buffer
);
1128 json::OStream
json_os(ss
);
1129 bp_data_sp
->Serialize(json_os
);
1130 if (auto expected_value
= llvm::json::parse(buffer
)) {
1131 bp
.try_emplace("details", std::move(*expected_value
));
1133 std::string details_error
= toString(expected_value
.takeError());
1134 json::Object details
;
1135 details
.try_emplace("error", details_error
);
1136 bp
.try_emplace("details", std::move(details
));
1139 return json::Value(std::move(bp
));
1142 void Breakpoint::ResetStatistics() { m_resolve_time
.reset(); }