Path: blob/main/contrib/llvm-project/lldb/source/Breakpoint/Breakpoint.cpp
39587 views
//===-- Breakpoint.cpp ----------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/Support/Casting.h"910#include "lldb/Breakpoint/Breakpoint.h"11#include "lldb/Breakpoint/BreakpointLocation.h"12#include "lldb/Breakpoint/BreakpointLocationCollection.h"13#include "lldb/Breakpoint/BreakpointPrecondition.h"14#include "lldb/Breakpoint/BreakpointResolver.h"15#include "lldb/Breakpoint/BreakpointResolverFileLine.h"16#include "lldb/Core/Address.h"17#include "lldb/Core/Module.h"18#include "lldb/Core/ModuleList.h"19#include "lldb/Core/SearchFilter.h"20#include "lldb/Core/Section.h"21#include "lldb/Symbol/CompileUnit.h"22#include "lldb/Symbol/Function.h"23#include "lldb/Symbol/Symbol.h"24#include "lldb/Symbol/SymbolContext.h"25#include "lldb/Target/SectionLoadList.h"26#include "lldb/Target/Target.h"27#include "lldb/Target/ThreadSpec.h"28#include "lldb/Utility/LLDBLog.h"29#include "lldb/Utility/Log.h"30#include "lldb/Utility/Stream.h"31#include "lldb/Utility/StreamString.h"3233#include <memory>3435using namespace lldb;36using namespace lldb_private;37using namespace llvm;3839const char *Breakpoint::g_option_names[static_cast<uint32_t>(40Breakpoint::OptionNames::LastOptionName)]{"Names", "Hardware"};4142// Breakpoint constructor43Breakpoint::Breakpoint(Target &target, SearchFilterSP &filter_sp,44BreakpointResolverSP &resolver_sp, bool hardware,45bool resolve_indirect_symbols)46: m_hardware(hardware), m_target(target), m_filter_sp(filter_sp),47m_resolver_sp(resolver_sp), m_options(true), m_locations(*this),48m_resolve_indirect_symbols(resolve_indirect_symbols), m_hit_counter() {}4950Breakpoint::Breakpoint(Target &new_target, const Breakpoint &source_bp)51: m_hardware(source_bp.m_hardware), m_target(new_target),52m_name_list(source_bp.m_name_list), m_options(source_bp.m_options),53m_locations(*this),54m_resolve_indirect_symbols(source_bp.m_resolve_indirect_symbols),55m_hit_counter() {}5657// Destructor58Breakpoint::~Breakpoint() = default;5960BreakpointSP Breakpoint::CopyFromBreakpoint(TargetSP new_target,61const Breakpoint& bp_to_copy_from) {62if (!new_target)63return BreakpointSP();6465BreakpointSP bp(new Breakpoint(*new_target, bp_to_copy_from));66// Now go through and copy the filter & resolver:67bp->m_resolver_sp = bp_to_copy_from.m_resolver_sp->CopyForBreakpoint(bp);68bp->m_filter_sp = bp_to_copy_from.m_filter_sp->CreateCopy(new_target);69return bp;70}7172// Serialization73StructuredData::ObjectSP Breakpoint::SerializeToStructuredData() {74// Serialize the resolver:75StructuredData::DictionarySP breakpoint_dict_sp(76new StructuredData::Dictionary());77StructuredData::DictionarySP breakpoint_contents_sp(78new StructuredData::Dictionary());7980if (!m_name_list.empty()) {81StructuredData::ArraySP names_array_sp(new StructuredData::Array());82for (auto name : m_name_list) {83names_array_sp->AddItem(84StructuredData::StringSP(new StructuredData::String(name)));85}86breakpoint_contents_sp->AddItem(Breakpoint::GetKey(OptionNames::Names),87names_array_sp);88}8990breakpoint_contents_sp->AddBooleanItem(91Breakpoint::GetKey(OptionNames::Hardware), m_hardware);9293StructuredData::ObjectSP resolver_dict_sp(94m_resolver_sp->SerializeToStructuredData());95if (!resolver_dict_sp)96return StructuredData::ObjectSP();9798breakpoint_contents_sp->AddItem(BreakpointResolver::GetSerializationKey(),99resolver_dict_sp);100101StructuredData::ObjectSP filter_dict_sp(102m_filter_sp->SerializeToStructuredData());103if (!filter_dict_sp)104return StructuredData::ObjectSP();105106breakpoint_contents_sp->AddItem(SearchFilter::GetSerializationKey(),107filter_dict_sp);108109StructuredData::ObjectSP options_dict_sp(110m_options.SerializeToStructuredData());111if (!options_dict_sp)112return StructuredData::ObjectSP();113114breakpoint_contents_sp->AddItem(BreakpointOptions::GetSerializationKey(),115options_dict_sp);116117breakpoint_dict_sp->AddItem(GetSerializationKey(), breakpoint_contents_sp);118return breakpoint_dict_sp;119}120121lldb::BreakpointSP Breakpoint::CreateFromStructuredData(122TargetSP target_sp, StructuredData::ObjectSP &object_data, Status &error) {123BreakpointSP result_sp;124if (!target_sp)125return result_sp;126127StructuredData::Dictionary *breakpoint_dict = object_data->GetAsDictionary();128129if (!breakpoint_dict || !breakpoint_dict->IsValid()) {130error.SetErrorString("Can't deserialize from an invalid data object.");131return result_sp;132}133134StructuredData::Dictionary *resolver_dict;135bool success = breakpoint_dict->GetValueForKeyAsDictionary(136BreakpointResolver::GetSerializationKey(), resolver_dict);137if (!success) {138error.SetErrorString("Breakpoint data missing toplevel resolver key");139return result_sp;140}141142Status create_error;143BreakpointResolverSP resolver_sp =144BreakpointResolver::CreateFromStructuredData(*resolver_dict,145create_error);146if (create_error.Fail()) {147error.SetErrorStringWithFormat(148"Error creating breakpoint resolver from data: %s.",149create_error.AsCString());150return result_sp;151}152153StructuredData::Dictionary *filter_dict;154success = breakpoint_dict->GetValueForKeyAsDictionary(155SearchFilter::GetSerializationKey(), filter_dict);156SearchFilterSP filter_sp;157if (!success)158filter_sp =159std::make_shared<SearchFilterForUnconstrainedSearches>(target_sp);160else {161filter_sp = SearchFilter::CreateFromStructuredData(target_sp, *filter_dict,162create_error);163if (create_error.Fail()) {164error.SetErrorStringWithFormat(165"Error creating breakpoint filter from data: %s.",166create_error.AsCString());167return result_sp;168}169}170171std::unique_ptr<BreakpointOptions> options_up;172StructuredData::Dictionary *options_dict;173Target& target = *target_sp;174success = breakpoint_dict->GetValueForKeyAsDictionary(175BreakpointOptions::GetSerializationKey(), options_dict);176if (success) {177options_up = BreakpointOptions::CreateFromStructuredData(178target, *options_dict, create_error);179if (create_error.Fail()) {180error.SetErrorStringWithFormat(181"Error creating breakpoint options from data: %s.",182create_error.AsCString());183return result_sp;184}185}186187bool hardware = false;188success = breakpoint_dict->GetValueForKeyAsBoolean(189Breakpoint::GetKey(OptionNames::Hardware), hardware);190191result_sp = target.CreateBreakpoint(filter_sp, resolver_sp, false,192hardware, true);193194if (result_sp && options_up) {195result_sp->m_options = *options_up;196}197198StructuredData::Array *names_array;199success = breakpoint_dict->GetValueForKeyAsArray(200Breakpoint::GetKey(OptionNames::Names), names_array);201if (success && names_array) {202size_t num_names = names_array->GetSize();203for (size_t i = 0; i < num_names; i++) {204if (std::optional<llvm::StringRef> maybe_name =205names_array->GetItemAtIndexAsString(i))206target.AddNameToBreakpoint(result_sp, *maybe_name, error);207}208}209210return result_sp;211}212213bool Breakpoint::SerializedBreakpointMatchesNames(214StructuredData::ObjectSP &bkpt_object_sp, std::vector<std::string> &names) {215if (!bkpt_object_sp)216return false;217218StructuredData::Dictionary *bkpt_dict = bkpt_object_sp->GetAsDictionary();219if (!bkpt_dict)220return false;221222if (names.empty())223return true;224225StructuredData::Array *names_array;226227bool success =228bkpt_dict->GetValueForKeyAsArray(GetKey(OptionNames::Names), names_array);229// If there are no names, it can't match these names;230if (!success)231return false;232233size_t num_names = names_array->GetSize();234235for (size_t i = 0; i < num_names; i++) {236std::optional<llvm::StringRef> maybe_name =237names_array->GetItemAtIndexAsString(i);238if (maybe_name && llvm::is_contained(names, *maybe_name))239return true;240}241return false;242}243244const lldb::TargetSP Breakpoint::GetTargetSP() {245return m_target.shared_from_this();246}247248bool Breakpoint::IsInternal() const { return LLDB_BREAK_ID_IS_INTERNAL(m_bid); }249250BreakpointLocationSP Breakpoint::AddLocation(const Address &addr,251bool *new_location) {252return m_locations.AddLocation(addr, m_resolve_indirect_symbols,253new_location);254}255256BreakpointLocationSP Breakpoint::FindLocationByAddress(const Address &addr) {257return m_locations.FindByAddress(addr);258}259260break_id_t Breakpoint::FindLocationIDByAddress(const Address &addr) {261return m_locations.FindIDByAddress(addr);262}263264BreakpointLocationSP Breakpoint::FindLocationByID(break_id_t bp_loc_id) {265return m_locations.FindByID(bp_loc_id);266}267268BreakpointLocationSP Breakpoint::GetLocationAtIndex(size_t index) {269return m_locations.GetByIndex(index);270}271272void Breakpoint::RemoveInvalidLocations(const ArchSpec &arch) {273m_locations.RemoveInvalidLocations(arch);274}275276// For each of the overall options we need to decide how they propagate to the277// location options. This will determine the precedence of options on the278// breakpoint vs. its locations.279280// Disable at the breakpoint level should override the location settings. That281// way you can conveniently turn off a whole breakpoint without messing up the282// individual settings.283284void Breakpoint::SetEnabled(bool enable) {285if (enable == m_options.IsEnabled())286return;287288m_options.SetEnabled(enable);289if (enable)290m_locations.ResolveAllBreakpointSites();291else292m_locations.ClearAllBreakpointSites();293294SendBreakpointChangedEvent(enable ? eBreakpointEventTypeEnabled295: eBreakpointEventTypeDisabled);296}297298bool Breakpoint::IsEnabled() { return m_options.IsEnabled(); }299300void Breakpoint::SetIgnoreCount(uint32_t n) {301if (m_options.GetIgnoreCount() == n)302return;303304m_options.SetIgnoreCount(n);305SendBreakpointChangedEvent(eBreakpointEventTypeIgnoreChanged);306}307308void Breakpoint::DecrementIgnoreCount() {309uint32_t ignore = m_options.GetIgnoreCount();310if (ignore != 0)311m_options.SetIgnoreCount(ignore - 1);312}313314uint32_t Breakpoint::GetIgnoreCount() const {315return m_options.GetIgnoreCount();316}317318uint32_t Breakpoint::GetHitCount() const { return m_hit_counter.GetValue(); }319320void Breakpoint::ResetHitCount() {321m_hit_counter.Reset();322m_locations.ResetHitCount();323}324325bool Breakpoint::IsOneShot() const { return m_options.IsOneShot(); }326327void Breakpoint::SetOneShot(bool one_shot) { m_options.SetOneShot(one_shot); }328329bool Breakpoint::IsAutoContinue() const { return m_options.IsAutoContinue(); }330331void Breakpoint::SetAutoContinue(bool auto_continue) {332m_options.SetAutoContinue(auto_continue);333}334335void Breakpoint::SetThreadID(lldb::tid_t thread_id) {336if (m_options.GetThreadSpec()->GetTID() == thread_id)337return;338339m_options.GetThreadSpec()->SetTID(thread_id);340SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged);341}342343lldb::tid_t Breakpoint::GetThreadID() const {344if (m_options.GetThreadSpecNoCreate() == nullptr)345return LLDB_INVALID_THREAD_ID;346else347return m_options.GetThreadSpecNoCreate()->GetTID();348}349350void Breakpoint::SetThreadIndex(uint32_t index) {351if (m_options.GetThreadSpec()->GetIndex() == index)352return;353354m_options.GetThreadSpec()->SetIndex(index);355SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged);356}357358uint32_t Breakpoint::GetThreadIndex() const {359if (m_options.GetThreadSpecNoCreate() == nullptr)360return 0;361else362return m_options.GetThreadSpecNoCreate()->GetIndex();363}364365void Breakpoint::SetThreadName(const char *thread_name) {366if (m_options.GetThreadSpec()->GetName() != nullptr &&367::strcmp(m_options.GetThreadSpec()->GetName(), thread_name) == 0)368return;369370m_options.GetThreadSpec()->SetName(thread_name);371SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged);372}373374const char *Breakpoint::GetThreadName() const {375if (m_options.GetThreadSpecNoCreate() == nullptr)376return nullptr;377else378return m_options.GetThreadSpecNoCreate()->GetName();379}380381void Breakpoint::SetQueueName(const char *queue_name) {382if (m_options.GetThreadSpec()->GetQueueName() != nullptr &&383::strcmp(m_options.GetThreadSpec()->GetQueueName(), queue_name) == 0)384return;385386m_options.GetThreadSpec()->SetQueueName(queue_name);387SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged);388}389390const char *Breakpoint::GetQueueName() const {391if (m_options.GetThreadSpecNoCreate() == nullptr)392return nullptr;393else394return m_options.GetThreadSpecNoCreate()->GetQueueName();395}396397void Breakpoint::SetCondition(const char *condition) {398m_options.SetCondition(condition);399SendBreakpointChangedEvent(eBreakpointEventTypeConditionChanged);400}401402const char *Breakpoint::GetConditionText() const {403return m_options.GetConditionText();404}405406// This function is used when "baton" doesn't need to be freed407void Breakpoint::SetCallback(BreakpointHitCallback callback, void *baton,408bool is_synchronous) {409// The default "Baton" class will keep a copy of "baton" and won't free or410// delete it when it goes out of scope.411m_options.SetCallback(callback, std::make_shared<UntypedBaton>(baton),412is_synchronous);413414SendBreakpointChangedEvent(eBreakpointEventTypeCommandChanged);415}416417// This function is used when a baton needs to be freed and therefore is418// contained in a "Baton" subclass.419void Breakpoint::SetCallback(BreakpointHitCallback callback,420const BatonSP &callback_baton_sp,421bool is_synchronous) {422m_options.SetCallback(callback, callback_baton_sp, is_synchronous);423}424425void Breakpoint::ClearCallback() { m_options.ClearCallback(); }426427bool Breakpoint::InvokeCallback(StoppointCallbackContext *context,428break_id_t bp_loc_id) {429return m_options.InvokeCallback(context, GetID(), bp_loc_id);430}431432BreakpointOptions &Breakpoint::GetOptions() { return m_options; }433434const BreakpointOptions &Breakpoint::GetOptions() const { return m_options; }435436void Breakpoint::ResolveBreakpoint() {437if (m_resolver_sp) {438ElapsedTime elapsed(m_resolve_time);439m_resolver_sp->ResolveBreakpoint(*m_filter_sp);440}441}442443void Breakpoint::ResolveBreakpointInModules(444ModuleList &module_list, BreakpointLocationCollection &new_locations) {445ElapsedTime elapsed(m_resolve_time);446m_locations.StartRecordingNewLocations(new_locations);447448m_resolver_sp->ResolveBreakpointInModules(*m_filter_sp, module_list);449450m_locations.StopRecordingNewLocations();451}452453void Breakpoint::ResolveBreakpointInModules(ModuleList &module_list,454bool send_event) {455if (m_resolver_sp) {456// If this is not an internal breakpoint, set up to record the new457// locations, then dispatch an event with the new locations.458if (!IsInternal() && send_event) {459std::shared_ptr<BreakpointEventData> new_locations_event =460std::make_shared<BreakpointEventData>(461eBreakpointEventTypeLocationsAdded, shared_from_this());462ResolveBreakpointInModules(463module_list, new_locations_event->GetBreakpointLocationCollection());464if (new_locations_event->GetBreakpointLocationCollection().GetSize() != 0)465SendBreakpointChangedEvent(new_locations_event);466} else {467ElapsedTime elapsed(m_resolve_time);468m_resolver_sp->ResolveBreakpointInModules(*m_filter_sp, module_list);469}470}471}472473void Breakpoint::ClearAllBreakpointSites() {474m_locations.ClearAllBreakpointSites();475}476477// ModulesChanged: Pass in a list of new modules, and478479void Breakpoint::ModulesChanged(ModuleList &module_list, bool load,480bool delete_locations) {481Log *log = GetLog(LLDBLog::Breakpoints);482LLDB_LOGF(log,483"Breakpoint::ModulesChanged: num_modules: %zu load: %i "484"delete_locations: %i\n",485module_list.GetSize(), load, delete_locations);486487if (load) {488// The logic for handling new modules is:489// 1) If the filter rejects this module, then skip it. 2) Run through the490// current location list and if there are any locations491// for that module, we mark the module as "seen" and we don't try to492// re-resolve493// breakpoint locations for that module.494// However, we do add breakpoint sites to these locations if needed.495// 3) If we don't see this module in our breakpoint location list, call496// ResolveInModules.497498ModuleList new_modules; // We'll stuff the "unseen" modules in this list,499// and then resolve500// them after the locations pass. Have to do it this way because resolving501// breakpoints will add new locations potentially.502503for (ModuleSP module_sp : module_list.Modules()) {504bool seen = false;505if (!m_filter_sp->ModulePasses(module_sp))506continue;507508BreakpointLocationCollection locations_with_no_section;509for (BreakpointLocationSP break_loc_sp :510m_locations.BreakpointLocations()) {511512// If the section for this location was deleted, that means it's Module513// has gone away but somebody forgot to tell us. Let's clean it up514// here.515Address section_addr(break_loc_sp->GetAddress());516if (section_addr.SectionWasDeleted()) {517locations_with_no_section.Add(break_loc_sp);518continue;519}520521if (!break_loc_sp->IsEnabled())522continue;523524SectionSP section_sp(section_addr.GetSection());525526// If we don't have a Section, that means this location is a raw527// address that we haven't resolved to a section yet. So we'll have to528// look in all the new modules to resolve this location. Otherwise, if529// it was set in this module, re-resolve it here.530if (section_sp && section_sp->GetModule() == module_sp) {531if (!seen)532seen = true;533534if (!break_loc_sp->ResolveBreakpointSite()) {535LLDB_LOGF(log,536"Warning: could not set breakpoint site for "537"breakpoint location %d of breakpoint %d.\n",538break_loc_sp->GetID(), GetID());539}540}541}542543size_t num_to_delete = locations_with_no_section.GetSize();544545for (size_t i = 0; i < num_to_delete; i++)546m_locations.RemoveLocation(locations_with_no_section.GetByIndex(i));547548if (!seen)549new_modules.AppendIfNeeded(module_sp);550}551552if (new_modules.GetSize() > 0) {553ResolveBreakpointInModules(new_modules);554}555} else {556// Go through the currently set locations and if any have breakpoints in557// the module list, then remove their breakpoint sites, and their locations558// if asked to.559560std::shared_ptr<BreakpointEventData> removed_locations_event;561if (!IsInternal())562removed_locations_event = std::make_shared<BreakpointEventData>(563eBreakpointEventTypeLocationsRemoved, shared_from_this());564565for (ModuleSP module_sp : module_list.Modules()) {566if (m_filter_sp->ModulePasses(module_sp)) {567size_t loc_idx = 0;568size_t num_locations = m_locations.GetSize();569BreakpointLocationCollection locations_to_remove;570for (loc_idx = 0; loc_idx < num_locations; loc_idx++) {571BreakpointLocationSP break_loc_sp(m_locations.GetByIndex(loc_idx));572SectionSP section_sp(break_loc_sp->GetAddress().GetSection());573if (section_sp && section_sp->GetModule() == module_sp) {574// Remove this breakpoint since the shared library is unloaded, but575// keep the breakpoint location around so we always get complete576// hit count and breakpoint lifetime info577break_loc_sp->ClearBreakpointSite();578if (removed_locations_event) {579removed_locations_event->GetBreakpointLocationCollection().Add(580break_loc_sp);581}582if (delete_locations)583locations_to_remove.Add(break_loc_sp);584}585}586587if (delete_locations) {588size_t num_locations_to_remove = locations_to_remove.GetSize();589for (loc_idx = 0; loc_idx < num_locations_to_remove; loc_idx++)590m_locations.RemoveLocation(locations_to_remove.GetByIndex(loc_idx));591}592}593}594SendBreakpointChangedEvent(removed_locations_event);595}596}597598static bool SymbolContextsMightBeEquivalent(SymbolContext &old_sc,599SymbolContext &new_sc) {600bool equivalent_scs = false;601602if (old_sc.module_sp.get() == new_sc.module_sp.get()) {603// If these come from the same module, we can directly compare the604// pointers:605if (old_sc.comp_unit && new_sc.comp_unit &&606(old_sc.comp_unit == new_sc.comp_unit)) {607if (old_sc.function && new_sc.function &&608(old_sc.function == new_sc.function)) {609equivalent_scs = true;610}611} else if (old_sc.symbol && new_sc.symbol &&612(old_sc.symbol == new_sc.symbol)) {613equivalent_scs = true;614}615} else {616// Otherwise we will compare by name...617if (old_sc.comp_unit && new_sc.comp_unit) {618if (old_sc.comp_unit->GetPrimaryFile() ==619new_sc.comp_unit->GetPrimaryFile()) {620// Now check the functions:621if (old_sc.function && new_sc.function &&622(old_sc.function->GetName() == new_sc.function->GetName())) {623equivalent_scs = true;624}625}626} else if (old_sc.symbol && new_sc.symbol) {627if (Mangled::Compare(old_sc.symbol->GetMangled(),628new_sc.symbol->GetMangled()) == 0) {629equivalent_scs = true;630}631}632}633return equivalent_scs;634}635636void Breakpoint::ModuleReplaced(ModuleSP old_module_sp,637ModuleSP new_module_sp) {638Log *log = GetLog(LLDBLog::Breakpoints);639LLDB_LOGF(log, "Breakpoint::ModulesReplaced for %s\n",640old_module_sp->GetSpecificationDescription().c_str());641// First find all the locations that are in the old module642643BreakpointLocationCollection old_break_locs;644for (BreakpointLocationSP break_loc_sp : m_locations.BreakpointLocations()) {645SectionSP section_sp = break_loc_sp->GetAddress().GetSection();646if (section_sp && section_sp->GetModule() == old_module_sp) {647old_break_locs.Add(break_loc_sp);648}649}650651size_t num_old_locations = old_break_locs.GetSize();652653if (num_old_locations == 0) {654// There were no locations in the old module, so we just need to check if655// there were any in the new module.656ModuleList temp_list;657temp_list.Append(new_module_sp);658ResolveBreakpointInModules(temp_list);659} else {660// First search the new module for locations. Then compare this with the661// old list, copy over locations that "look the same" Then delete the old662// locations. Finally remember to post the creation event.663//664// Two locations are the same if they have the same comp unit & function665// (by name) and there are the same number of locations in the old function666// as in the new one.667668ModuleList temp_list;669temp_list.Append(new_module_sp);670BreakpointLocationCollection new_break_locs;671ResolveBreakpointInModules(temp_list, new_break_locs);672BreakpointLocationCollection locations_to_remove;673BreakpointLocationCollection locations_to_announce;674675size_t num_new_locations = new_break_locs.GetSize();676677if (num_new_locations > 0) {678// Break out the case of one location -> one location since that's the679// most common one, and there's no need to build up the structures needed680// for the merge in that case.681if (num_new_locations == 1 && num_old_locations == 1) {682bool equivalent_locations = false;683SymbolContext old_sc, new_sc;684// The only way the old and new location can be equivalent is if they685// have the same amount of information:686BreakpointLocationSP old_loc_sp = old_break_locs.GetByIndex(0);687BreakpointLocationSP new_loc_sp = new_break_locs.GetByIndex(0);688689if (old_loc_sp->GetAddress().CalculateSymbolContext(&old_sc) ==690new_loc_sp->GetAddress().CalculateSymbolContext(&new_sc)) {691equivalent_locations =692SymbolContextsMightBeEquivalent(old_sc, new_sc);693}694695if (equivalent_locations) {696m_locations.SwapLocation(old_loc_sp, new_loc_sp);697} else {698locations_to_remove.Add(old_loc_sp);699locations_to_announce.Add(new_loc_sp);700}701} else {702// We don't want to have to keep computing the SymbolContexts for these703// addresses over and over, so lets get them up front:704705typedef std::map<lldb::break_id_t, SymbolContext> IDToSCMap;706IDToSCMap old_sc_map;707for (size_t idx = 0; idx < num_old_locations; idx++) {708SymbolContext sc;709BreakpointLocationSP bp_loc_sp = old_break_locs.GetByIndex(idx);710lldb::break_id_t loc_id = bp_loc_sp->GetID();711bp_loc_sp->GetAddress().CalculateSymbolContext(&old_sc_map[loc_id]);712}713714std::map<lldb::break_id_t, SymbolContext> new_sc_map;715for (size_t idx = 0; idx < num_new_locations; idx++) {716SymbolContext sc;717BreakpointLocationSP bp_loc_sp = new_break_locs.GetByIndex(idx);718lldb::break_id_t loc_id = bp_loc_sp->GetID();719bp_loc_sp->GetAddress().CalculateSymbolContext(&new_sc_map[loc_id]);720}721// Take an element from the old Symbol Contexts722while (old_sc_map.size() > 0) {723lldb::break_id_t old_id = old_sc_map.begin()->first;724SymbolContext &old_sc = old_sc_map.begin()->second;725726// Count the number of entries equivalent to this SC for the old727// list:728std::vector<lldb::break_id_t> old_id_vec;729old_id_vec.push_back(old_id);730731IDToSCMap::iterator tmp_iter;732for (tmp_iter = ++old_sc_map.begin(); tmp_iter != old_sc_map.end();733tmp_iter++) {734if (SymbolContextsMightBeEquivalent(old_sc, tmp_iter->second))735old_id_vec.push_back(tmp_iter->first);736}737738// Now find all the equivalent locations in the new list.739std::vector<lldb::break_id_t> new_id_vec;740for (tmp_iter = new_sc_map.begin(); tmp_iter != new_sc_map.end();741tmp_iter++) {742if (SymbolContextsMightBeEquivalent(old_sc, tmp_iter->second))743new_id_vec.push_back(tmp_iter->first);744}745746// Alright, if we have the same number of potentially equivalent747// locations in the old and new modules, we'll just map them one to748// one in ascending ID order (assuming the resolver's order would749// match the equivalent ones. Otherwise, we'll dump all the old ones,750// and just take the new ones, erasing the elements from both maps as751// we go.752753if (old_id_vec.size() == new_id_vec.size()) {754llvm::sort(old_id_vec);755llvm::sort(new_id_vec);756size_t num_elements = old_id_vec.size();757for (size_t idx = 0; idx < num_elements; idx++) {758BreakpointLocationSP old_loc_sp =759old_break_locs.FindByIDPair(GetID(), old_id_vec[idx]);760BreakpointLocationSP new_loc_sp =761new_break_locs.FindByIDPair(GetID(), new_id_vec[idx]);762m_locations.SwapLocation(old_loc_sp, new_loc_sp);763old_sc_map.erase(old_id_vec[idx]);764new_sc_map.erase(new_id_vec[idx]);765}766} else {767for (lldb::break_id_t old_id : old_id_vec) {768locations_to_remove.Add(769old_break_locs.FindByIDPair(GetID(), old_id));770old_sc_map.erase(old_id);771}772for (lldb::break_id_t new_id : new_id_vec) {773locations_to_announce.Add(774new_break_locs.FindByIDPair(GetID(), new_id));775new_sc_map.erase(new_id);776}777}778}779}780}781782// Now remove the remaining old locations, and cons up a removed locations783// event. Note, we don't put the new locations that were swapped with an784// old location on the locations_to_remove list, so we don't need to worry785// about telling the world about removing a location we didn't tell them786// about adding.787788std::shared_ptr<BreakpointEventData> removed_locations_event;789if (!IsInternal())790removed_locations_event = std::make_shared<BreakpointEventData>(791eBreakpointEventTypeLocationsRemoved, shared_from_this());792793for (BreakpointLocationSP loc_sp :794locations_to_remove.BreakpointLocations()) {795m_locations.RemoveLocation(loc_sp);796if (removed_locations_event)797removed_locations_event->GetBreakpointLocationCollection().Add(loc_sp);798}799SendBreakpointChangedEvent(removed_locations_event);800801// And announce the new ones.802803if (!IsInternal()) {804std::shared_ptr<BreakpointEventData> added_locations_event =805std::make_shared<BreakpointEventData>(806eBreakpointEventTypeLocationsAdded, shared_from_this());807for (BreakpointLocationSP loc_sp :808locations_to_announce.BreakpointLocations())809added_locations_event->GetBreakpointLocationCollection().Add(loc_sp);810811SendBreakpointChangedEvent(added_locations_event);812}813m_locations.Compact();814}815}816817void Breakpoint::Dump(Stream *) {}818819size_t Breakpoint::GetNumResolvedLocations() const {820// Return the number of breakpoints that are actually resolved and set down821// in the inferior process.822return m_locations.GetNumResolvedLocations();823}824825bool Breakpoint::HasResolvedLocations() const {826return GetNumResolvedLocations() > 0;827}828829size_t Breakpoint::GetNumLocations() const { return m_locations.GetSize(); }830831void Breakpoint::AddName(llvm::StringRef new_name) {832m_name_list.insert(new_name.str());833}834835void Breakpoint::GetDescription(Stream *s, lldb::DescriptionLevel level,836bool show_locations) {837assert(s != nullptr);838839if (!m_kind_description.empty()) {840if (level == eDescriptionLevelBrief) {841s->PutCString(GetBreakpointKind());842return;843} else844s->Printf("Kind: %s\n", GetBreakpointKind());845}846847const size_t num_locations = GetNumLocations();848const size_t num_resolved_locations = GetNumResolvedLocations();849850// They just made the breakpoint, they don't need to be told HOW they made851// it... Also, we'll print the breakpoint number differently depending on852// whether there is 1 or more locations.853if (level != eDescriptionLevelInitial) {854s->Printf("%i: ", GetID());855GetResolverDescription(s);856GetFilterDescription(s);857}858859switch (level) {860case lldb::eDescriptionLevelBrief:861case lldb::eDescriptionLevelFull:862if (num_locations > 0) {863s->Printf(", locations = %" PRIu64, (uint64_t)num_locations);864if (num_resolved_locations > 0)865s->Printf(", resolved = %" PRIu64 ", hit count = %d",866(uint64_t)num_resolved_locations, GetHitCount());867} else {868// Don't print the pending notification for exception resolvers since we869// don't generally know how to set them until the target is run.870if (m_resolver_sp->getResolverID() !=871BreakpointResolver::ExceptionResolver)872s->Printf(", locations = 0 (pending)");873}874875m_options.GetDescription(s, level);876877if (m_precondition_sp)878m_precondition_sp->GetDescription(*s, level);879880if (level == lldb::eDescriptionLevelFull) {881if (!m_name_list.empty()) {882s->EOL();883s->Indent();884s->Printf("Names:");885s->EOL();886s->IndentMore();887for (const std::string &name : m_name_list) {888s->Indent();889s->Printf("%s\n", name.c_str());890}891s->IndentLess();892}893s->IndentLess();894s->EOL();895}896break;897898case lldb::eDescriptionLevelInitial:899s->Printf("Breakpoint %i: ", GetID());900if (num_locations == 0) {901s->Printf("no locations (pending).");902} else if (num_locations == 1 && !show_locations) {903// There is only one location, so we'll just print that location904// information.905GetLocationAtIndex(0)->GetDescription(s, level);906} else {907s->Printf("%" PRIu64 " locations.", static_cast<uint64_t>(num_locations));908}909s->EOL();910break;911912case lldb::eDescriptionLevelVerbose:913// Verbose mode does a debug dump of the breakpoint914Dump(s);915s->EOL();916// s->Indent();917m_options.GetDescription(s, level);918break;919920default:921break;922}923924// The brief description is just the location name (1.2 or whatever). That's925// pointless to show in the breakpoint's description, so suppress it.926if (show_locations && level != lldb::eDescriptionLevelBrief) {927s->IndentMore();928for (size_t i = 0; i < num_locations; ++i) {929BreakpointLocation *loc = GetLocationAtIndex(i).get();930loc->GetDescription(s, level);931s->EOL();932}933s->IndentLess();934}935}936937void Breakpoint::GetResolverDescription(Stream *s) {938if (m_resolver_sp)939m_resolver_sp->GetDescription(s);940}941942bool Breakpoint::GetMatchingFileLine(ConstString filename,943uint32_t line_number,944BreakpointLocationCollection &loc_coll) {945// TODO: To be correct, this method needs to fill the breakpoint location946// collection947// with the location IDs which match the filename and line_number.948//949950if (m_resolver_sp) {951BreakpointResolverFileLine *resolverFileLine =952dyn_cast<BreakpointResolverFileLine>(m_resolver_sp.get());953954// TODO: Handle SourceLocationSpec column information955if (resolverFileLine &&956resolverFileLine->m_location_spec.GetFileSpec().GetFilename() ==957filename &&958resolverFileLine->m_location_spec.GetLine() == line_number) {959return true;960}961}962return false;963}964965void Breakpoint::GetFilterDescription(Stream *s) {966m_filter_sp->GetDescription(s);967}968969bool Breakpoint::EvaluatePrecondition(StoppointCallbackContext &context) {970if (!m_precondition_sp)971return true;972973return m_precondition_sp->EvaluatePrecondition(context);974}975976void Breakpoint::SendBreakpointChangedEvent(977lldb::BreakpointEventType eventKind) {978if (!IsInternal() && GetTarget().EventTypeHasListeners(979Target::eBroadcastBitBreakpointChanged)) {980std::shared_ptr<BreakpointEventData> data =981std::make_shared<BreakpointEventData>(eventKind, shared_from_this());982983GetTarget().BroadcastEvent(Target::eBroadcastBitBreakpointChanged, data);984}985}986987void Breakpoint::SendBreakpointChangedEvent(988const lldb::EventDataSP &breakpoint_data_sp) {989if (!breakpoint_data_sp)990return;991992if (!IsInternal() &&993GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))994GetTarget().BroadcastEvent(Target::eBroadcastBitBreakpointChanged,995breakpoint_data_sp);996}997998const char *Breakpoint::BreakpointEventTypeAsCString(BreakpointEventType type) {999switch (type) {1000case eBreakpointEventTypeInvalidType: return "invalid";1001case eBreakpointEventTypeAdded: return "breakpoint added";1002case eBreakpointEventTypeRemoved: return "breakpoint removed";1003case eBreakpointEventTypeLocationsAdded: return "locations added";1004case eBreakpointEventTypeLocationsRemoved: return "locations removed";1005case eBreakpointEventTypeLocationsResolved: return "locations resolved";1006case eBreakpointEventTypeEnabled: return "breakpoint enabled";1007case eBreakpointEventTypeDisabled: return "breakpoint disabled";1008case eBreakpointEventTypeCommandChanged: return "command changed";1009case eBreakpointEventTypeConditionChanged: return "condition changed";1010case eBreakpointEventTypeIgnoreChanged: return "ignore count changed";1011case eBreakpointEventTypeThreadChanged: return "thread changed";1012case eBreakpointEventTypeAutoContinueChanged: return "autocontinue changed";1013};1014llvm_unreachable("Fully covered switch above!");1015}10161017Log *Breakpoint::BreakpointEventData::GetLogChannel() {1018return GetLog(LLDBLog::Breakpoints);1019}10201021Breakpoint::BreakpointEventData::BreakpointEventData(1022BreakpointEventType sub_type, const BreakpointSP &new_breakpoint_sp)1023: m_breakpoint_event(sub_type), m_new_breakpoint_sp(new_breakpoint_sp) {}10241025Breakpoint::BreakpointEventData::~BreakpointEventData() = default;10261027llvm::StringRef Breakpoint::BreakpointEventData::GetFlavorString() {1028return "Breakpoint::BreakpointEventData";1029}10301031llvm::StringRef Breakpoint::BreakpointEventData::GetFlavor() const {1032return BreakpointEventData::GetFlavorString();1033}10341035BreakpointSP Breakpoint::BreakpointEventData::GetBreakpoint() const {1036return m_new_breakpoint_sp;1037}10381039BreakpointEventType1040Breakpoint::BreakpointEventData::GetBreakpointEventType() const {1041return m_breakpoint_event;1042}10431044void Breakpoint::BreakpointEventData::Dump(Stream *s) const {1045if (!s)1046return;1047BreakpointEventType event_type = GetBreakpointEventType();1048break_id_t bkpt_id = GetBreakpoint()->GetID();1049s->Format("bkpt: {0} type: {1}", bkpt_id,1050BreakpointEventTypeAsCString(event_type));1051}10521053const Breakpoint::BreakpointEventData *1054Breakpoint::BreakpointEventData::GetEventDataFromEvent(const Event *event) {1055if (event) {1056const EventData *event_data = event->GetData();1057if (event_data &&1058event_data->GetFlavor() == BreakpointEventData::GetFlavorString())1059return static_cast<const BreakpointEventData *>(event->GetData());1060}1061return nullptr;1062}10631064BreakpointEventType1065Breakpoint::BreakpointEventData::GetBreakpointEventTypeFromEvent(1066const EventSP &event_sp) {1067const BreakpointEventData *data = GetEventDataFromEvent(event_sp.get());10681069if (data == nullptr)1070return eBreakpointEventTypeInvalidType;1071else1072return data->GetBreakpointEventType();1073}10741075BreakpointSP Breakpoint::BreakpointEventData::GetBreakpointFromEvent(1076const EventSP &event_sp) {1077BreakpointSP bp_sp;10781079const BreakpointEventData *data = GetEventDataFromEvent(event_sp.get());1080if (data)1081bp_sp = data->m_new_breakpoint_sp;10821083return bp_sp;1084}10851086size_t Breakpoint::BreakpointEventData::GetNumBreakpointLocationsFromEvent(1087const EventSP &event_sp) {1088const BreakpointEventData *data = GetEventDataFromEvent(event_sp.get());1089if (data)1090return data->m_locations.GetSize();10911092return 0;1093}10941095lldb::BreakpointLocationSP1096Breakpoint::BreakpointEventData::GetBreakpointLocationAtIndexFromEvent(1097const lldb::EventSP &event_sp, uint32_t bp_loc_idx) {1098lldb::BreakpointLocationSP bp_loc_sp;10991100const BreakpointEventData *data = GetEventDataFromEvent(event_sp.get());1101if (data) {1102bp_loc_sp = data->m_locations.GetByIndex(bp_loc_idx);1103}11041105return bp_loc_sp;1106}11071108json::Value Breakpoint::GetStatistics() {1109json::Object bp;1110bp.try_emplace("id", GetID());1111bp.try_emplace("resolveTime", m_resolve_time.get().count());1112bp.try_emplace("numLocations", (int64_t)GetNumLocations());1113bp.try_emplace("numResolvedLocations", (int64_t)GetNumResolvedLocations());1114bp.try_emplace("hitCount", (int64_t)GetHitCount());1115bp.try_emplace("internal", IsInternal());1116if (!m_kind_description.empty())1117bp.try_emplace("kindDescription", m_kind_description);1118// Put the full structured data for reproducing this breakpoint in a key/value1119// pair named "details". This allows the breakpoint's details to be visible1120// in the stats in case we need to reproduce a breakpoint that has long1121// resolve times1122StructuredData::ObjectSP bp_data_sp = SerializeToStructuredData();1123if (bp_data_sp) {1124std::string buffer;1125llvm::raw_string_ostream ss(buffer);1126json::OStream json_os(ss);1127bp_data_sp->Serialize(json_os);1128if (auto expected_value = llvm::json::parse(ss.str())) {1129bp.try_emplace("details", std::move(*expected_value));1130} else {1131std::string details_error = toString(expected_value.takeError());1132json::Object details;1133details.try_emplace("error", details_error);1134bp.try_emplace("details", std::move(details));1135}1136}1137return json::Value(std::move(bp));1138}113911401141