summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/lldb/source/Breakpoint
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2020-08-03 14:33:06 +0000
committerpatrick <patrick@openbsd.org>2020-08-03 14:33:06 +0000
commit061da546b983eb767bad15e67af1174fb0bcf31c (patch)
tree83c78b820819d70aa40c36d90447978b300078c5 /gnu/llvm/lldb/source/Breakpoint
parentImport LLVM 10.0.0 release including clang, lld and lldb. (diff)
downloadwireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.tar.xz
wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.zip
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom tested by plenty
Diffstat (limited to 'gnu/llvm/lldb/source/Breakpoint')
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/Breakpoint.cpp1102
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/BreakpointID.cpp121
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/BreakpointIDList.cpp348
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/BreakpointList.cpp195
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/BreakpointLocation.cpp659
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/BreakpointLocationCollection.cpp187
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/BreakpointLocationList.cpp312
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/BreakpointName.cpp86
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/BreakpointOptions.cpp673
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/BreakpointPrecondition.cpp26
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/BreakpointResolver.cpp352
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/BreakpointResolverAddress.cpp184
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp272
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp172
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/BreakpointResolverName.cpp433
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/BreakpointResolverScripted.cpp163
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/BreakpointSite.cpp206
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/BreakpointSiteList.cpp200
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/CMakeLists.txt37
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/Stoppoint.cpp24
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/StoppointCallbackContext.cpp24
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/StoppointLocation.cpp32
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/Watchpoint.cpp388
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/WatchpointList.cpp252
-rw-r--r--gnu/llvm/lldb/source/Breakpoint/WatchpointOptions.cpp182
25 files changed, 6630 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/source/Breakpoint/Breakpoint.cpp b/gnu/llvm/lldb/source/Breakpoint/Breakpoint.cpp
new file mode 100644
index 00000000000..13acf4bb92e
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/Breakpoint.cpp
@@ -0,0 +1,1102 @@
+//===-- Breakpoint.cpp ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Casting.h"
+
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointLocationCollection.h"
+#include "lldb/Breakpoint/BreakpointPrecondition.h"
+#include "lldb/Breakpoint/BreakpointResolver.h"
+#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/SearchFilter.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace llvm;
+
+ConstString Breakpoint::GetEventIdentifier() {
+ static ConstString g_identifier("event-identifier.breakpoint.changed");
+ return g_identifier;
+}
+
+const char *Breakpoint::g_option_names[static_cast<uint32_t>(
+ Breakpoint::OptionNames::LastOptionName)]{"Names", "Hardware"};
+
+// Breakpoint constructor
+Breakpoint::Breakpoint(Target &target, SearchFilterSP &filter_sp,
+ BreakpointResolverSP &resolver_sp, bool hardware,
+ bool resolve_indirect_symbols)
+ : m_being_created(true), m_hardware(hardware), m_target(target),
+ m_filter_sp(filter_sp), m_resolver_sp(resolver_sp),
+ m_options_up(new BreakpointOptions(true)), m_locations(*this),
+ m_resolve_indirect_symbols(resolve_indirect_symbols), m_hit_count(0) {
+ m_being_created = false;
+}
+
+Breakpoint::Breakpoint(Target &new_target, Breakpoint &source_bp)
+ : m_being_created(true), m_hardware(source_bp.m_hardware),
+ m_target(new_target), m_name_list(source_bp.m_name_list),
+ m_options_up(new BreakpointOptions(*source_bp.m_options_up)),
+ m_locations(*this),
+ m_resolve_indirect_symbols(source_bp.m_resolve_indirect_symbols),
+ m_hit_count(0) {
+ // Now go through and copy the filter & resolver:
+ m_resolver_sp = source_bp.m_resolver_sp->CopyForBreakpoint(*this);
+ m_filter_sp = source_bp.m_filter_sp->CopyForBreakpoint(*this);
+}
+
+// Destructor
+Breakpoint::~Breakpoint() = default;
+
+// Serialization
+StructuredData::ObjectSP Breakpoint::SerializeToStructuredData() {
+ // Serialize the resolver:
+ StructuredData::DictionarySP breakpoint_dict_sp(
+ new StructuredData::Dictionary());
+ StructuredData::DictionarySP breakpoint_contents_sp(
+ new StructuredData::Dictionary());
+
+ if (!m_name_list.empty()) {
+ StructuredData::ArraySP names_array_sp(new StructuredData::Array());
+ for (auto name : m_name_list) {
+ names_array_sp->AddItem(
+ StructuredData::StringSP(new StructuredData::String(name)));
+ }
+ breakpoint_contents_sp->AddItem(Breakpoint::GetKey(OptionNames::Names),
+ names_array_sp);
+ }
+
+ breakpoint_contents_sp->AddBooleanItem(
+ Breakpoint::GetKey(OptionNames::Hardware), m_hardware);
+
+ StructuredData::ObjectSP resolver_dict_sp(
+ m_resolver_sp->SerializeToStructuredData());
+ if (!resolver_dict_sp)
+ return StructuredData::ObjectSP();
+
+ breakpoint_contents_sp->AddItem(BreakpointResolver::GetSerializationKey(),
+ resolver_dict_sp);
+
+ StructuredData::ObjectSP filter_dict_sp(
+ m_filter_sp->SerializeToStructuredData());
+ if (!filter_dict_sp)
+ return StructuredData::ObjectSP();
+
+ breakpoint_contents_sp->AddItem(SearchFilter::GetSerializationKey(),
+ filter_dict_sp);
+
+ StructuredData::ObjectSP options_dict_sp(
+ m_options_up->SerializeToStructuredData());
+ if (!options_dict_sp)
+ return StructuredData::ObjectSP();
+
+ breakpoint_contents_sp->AddItem(BreakpointOptions::GetSerializationKey(),
+ options_dict_sp);
+
+ breakpoint_dict_sp->AddItem(GetSerializationKey(), breakpoint_contents_sp);
+ return breakpoint_dict_sp;
+}
+
+lldb::BreakpointSP Breakpoint::CreateFromStructuredData(
+ Target &target, StructuredData::ObjectSP &object_data, Status &error) {
+ BreakpointSP result_sp;
+
+ StructuredData::Dictionary *breakpoint_dict = object_data->GetAsDictionary();
+
+ if (!breakpoint_dict || !breakpoint_dict->IsValid()) {
+ error.SetErrorString("Can't deserialize from an invalid data object.");
+ return result_sp;
+ }
+
+ StructuredData::Dictionary *resolver_dict;
+ bool success = breakpoint_dict->GetValueForKeyAsDictionary(
+ BreakpointResolver::GetSerializationKey(), resolver_dict);
+ if (!success) {
+ error.SetErrorStringWithFormat(
+ "Breakpoint data missing toplevel resolver key");
+ return result_sp;
+ }
+
+ Status create_error;
+ BreakpointResolverSP resolver_sp =
+ BreakpointResolver::CreateFromStructuredData(*resolver_dict,
+ create_error);
+ if (create_error.Fail()) {
+ error.SetErrorStringWithFormat(
+ "Error creating breakpoint resolver from data: %s.",
+ create_error.AsCString());
+ return result_sp;
+ }
+
+ StructuredData::Dictionary *filter_dict;
+ success = breakpoint_dict->GetValueForKeyAsDictionary(
+ SearchFilter::GetSerializationKey(), filter_dict);
+ SearchFilterSP filter_sp;
+ if (!success)
+ filter_sp = std::make_shared<SearchFilterForUnconstrainedSearches>(
+ target.shared_from_this());
+ else {
+ filter_sp = SearchFilter::CreateFromStructuredData(target, *filter_dict,
+ create_error);
+ if (create_error.Fail()) {
+ error.SetErrorStringWithFormat(
+ "Error creating breakpoint filter from data: %s.",
+ create_error.AsCString());
+ return result_sp;
+ }
+ }
+
+ std::unique_ptr<BreakpointOptions> options_up;
+ StructuredData::Dictionary *options_dict;
+ success = breakpoint_dict->GetValueForKeyAsDictionary(
+ BreakpointOptions::GetSerializationKey(), options_dict);
+ if (success) {
+ options_up = BreakpointOptions::CreateFromStructuredData(
+ target, *options_dict, create_error);
+ if (create_error.Fail()) {
+ error.SetErrorStringWithFormat(
+ "Error creating breakpoint options from data: %s.",
+ create_error.AsCString());
+ return result_sp;
+ }
+ }
+
+ bool hardware = false;
+ success = breakpoint_dict->GetValueForKeyAsBoolean(
+ Breakpoint::GetKey(OptionNames::Hardware), hardware);
+
+ result_sp =
+ target.CreateBreakpoint(filter_sp, resolver_sp, false, hardware, true);
+
+ if (result_sp && options_up) {
+ result_sp->m_options_up = std::move(options_up);
+ }
+
+ StructuredData::Array *names_array;
+ success = breakpoint_dict->GetValueForKeyAsArray(
+ Breakpoint::GetKey(OptionNames::Names), names_array);
+ if (success && names_array) {
+ size_t num_names = names_array->GetSize();
+ for (size_t i = 0; i < num_names; i++) {
+ llvm::StringRef name;
+ Status error;
+ success = names_array->GetItemAtIndexAsString(i, name);
+ target.AddNameToBreakpoint(result_sp, name.str().c_str(), error);
+ }
+ }
+
+ return result_sp;
+}
+
+bool Breakpoint::SerializedBreakpointMatchesNames(
+ StructuredData::ObjectSP &bkpt_object_sp, std::vector<std::string> &names) {
+ if (!bkpt_object_sp)
+ return false;
+
+ StructuredData::Dictionary *bkpt_dict = bkpt_object_sp->GetAsDictionary();
+ if (!bkpt_dict)
+ return false;
+
+ if (names.empty())
+ return true;
+
+ StructuredData::Array *names_array;
+
+ bool success =
+ bkpt_dict->GetValueForKeyAsArray(GetKey(OptionNames::Names), names_array);
+ // If there are no names, it can't match these names;
+ if (!success)
+ return false;
+
+ size_t num_names = names_array->GetSize();
+ std::vector<std::string>::iterator begin = names.begin();
+ std::vector<std::string>::iterator end = names.end();
+
+ for (size_t i = 0; i < num_names; i++) {
+ llvm::StringRef name;
+ if (names_array->GetItemAtIndexAsString(i, name)) {
+ if (std::find(begin, end, name) != end) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+const lldb::TargetSP Breakpoint::GetTargetSP() {
+ return m_target.shared_from_this();
+}
+
+bool Breakpoint::IsInternal() const { return LLDB_BREAK_ID_IS_INTERNAL(m_bid); }
+
+BreakpointLocationSP Breakpoint::AddLocation(const Address &addr,
+ bool *new_location) {
+ return m_locations.AddLocation(addr, m_resolve_indirect_symbols,
+ new_location);
+}
+
+BreakpointLocationSP Breakpoint::FindLocationByAddress(const Address &addr) {
+ return m_locations.FindByAddress(addr);
+}
+
+break_id_t Breakpoint::FindLocationIDByAddress(const Address &addr) {
+ return m_locations.FindIDByAddress(addr);
+}
+
+BreakpointLocationSP Breakpoint::FindLocationByID(break_id_t bp_loc_id) {
+ return m_locations.FindByID(bp_loc_id);
+}
+
+BreakpointLocationSP Breakpoint::GetLocationAtIndex(size_t index) {
+ return m_locations.GetByIndex(index);
+}
+
+void Breakpoint::RemoveInvalidLocations(const ArchSpec &arch) {
+ m_locations.RemoveInvalidLocations(arch);
+}
+
+// For each of the overall options we need to decide how they propagate to the
+// location options. This will determine the precedence of options on the
+// breakpoint vs. its locations.
+
+// Disable at the breakpoint level should override the location settings. That
+// way you can conveniently turn off a whole breakpoint without messing up the
+// individual settings.
+
+void Breakpoint::SetEnabled(bool enable) {
+ if (enable == m_options_up->IsEnabled())
+ return;
+
+ m_options_up->SetEnabled(enable);
+ if (enable)
+ m_locations.ResolveAllBreakpointSites();
+ else
+ m_locations.ClearAllBreakpointSites();
+
+ SendBreakpointChangedEvent(enable ? eBreakpointEventTypeEnabled
+ : eBreakpointEventTypeDisabled);
+}
+
+bool Breakpoint::IsEnabled() { return m_options_up->IsEnabled(); }
+
+void Breakpoint::SetIgnoreCount(uint32_t n) {
+ if (m_options_up->GetIgnoreCount() == n)
+ return;
+
+ m_options_up->SetIgnoreCount(n);
+ SendBreakpointChangedEvent(eBreakpointEventTypeIgnoreChanged);
+}
+
+void Breakpoint::DecrementIgnoreCount() {
+ uint32_t ignore = m_options_up->GetIgnoreCount();
+ if (ignore != 0)
+ m_options_up->SetIgnoreCount(ignore - 1);
+}
+
+uint32_t Breakpoint::GetIgnoreCount() const {
+ return m_options_up->GetIgnoreCount();
+}
+
+bool Breakpoint::IgnoreCountShouldStop() {
+ uint32_t ignore = GetIgnoreCount();
+ if (ignore != 0) {
+ // When we get here we know the location that caused the stop doesn't have
+ // an ignore count, since by contract we call it first... So we don't have
+ // to find & decrement it, we only have to decrement our own ignore count.
+ DecrementIgnoreCount();
+ return false;
+ } else
+ return true;
+}
+
+uint32_t Breakpoint::GetHitCount() const { return m_hit_count; }
+
+bool Breakpoint::IsOneShot() const { return m_options_up->IsOneShot(); }
+
+void Breakpoint::SetOneShot(bool one_shot) {
+ m_options_up->SetOneShot(one_shot);
+}
+
+bool Breakpoint::IsAutoContinue() const {
+ return m_options_up->IsAutoContinue();
+}
+
+void Breakpoint::SetAutoContinue(bool auto_continue) {
+ m_options_up->SetAutoContinue(auto_continue);
+}
+
+void Breakpoint::SetThreadID(lldb::tid_t thread_id) {
+ if (m_options_up->GetThreadSpec()->GetTID() == thread_id)
+ return;
+
+ m_options_up->GetThreadSpec()->SetTID(thread_id);
+ SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged);
+}
+
+lldb::tid_t Breakpoint::GetThreadID() const {
+ if (m_options_up->GetThreadSpecNoCreate() == nullptr)
+ return LLDB_INVALID_THREAD_ID;
+ else
+ return m_options_up->GetThreadSpecNoCreate()->GetTID();
+}
+
+void Breakpoint::SetThreadIndex(uint32_t index) {
+ if (m_options_up->GetThreadSpec()->GetIndex() == index)
+ return;
+
+ m_options_up->GetThreadSpec()->SetIndex(index);
+ SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged);
+}
+
+uint32_t Breakpoint::GetThreadIndex() const {
+ if (m_options_up->GetThreadSpecNoCreate() == nullptr)
+ return 0;
+ else
+ return m_options_up->GetThreadSpecNoCreate()->GetIndex();
+}
+
+void Breakpoint::SetThreadName(const char *thread_name) {
+ if (m_options_up->GetThreadSpec()->GetName() != nullptr &&
+ ::strcmp(m_options_up->GetThreadSpec()->GetName(), thread_name) == 0)
+ return;
+
+ m_options_up->GetThreadSpec()->SetName(thread_name);
+ SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged);
+}
+
+const char *Breakpoint::GetThreadName() const {
+ if (m_options_up->GetThreadSpecNoCreate() == nullptr)
+ return nullptr;
+ else
+ return m_options_up->GetThreadSpecNoCreate()->GetName();
+}
+
+void Breakpoint::SetQueueName(const char *queue_name) {
+ if (m_options_up->GetThreadSpec()->GetQueueName() != nullptr &&
+ ::strcmp(m_options_up->GetThreadSpec()->GetQueueName(), queue_name) == 0)
+ return;
+
+ m_options_up->GetThreadSpec()->SetQueueName(queue_name);
+ SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged);
+}
+
+const char *Breakpoint::GetQueueName() const {
+ if (m_options_up->GetThreadSpecNoCreate() == nullptr)
+ return nullptr;
+ else
+ return m_options_up->GetThreadSpecNoCreate()->GetQueueName();
+}
+
+void Breakpoint::SetCondition(const char *condition) {
+ m_options_up->SetCondition(condition);
+ SendBreakpointChangedEvent(eBreakpointEventTypeConditionChanged);
+}
+
+const char *Breakpoint::GetConditionText() const {
+ return m_options_up->GetConditionText();
+}
+
+// This function is used when "baton" doesn't need to be freed
+void Breakpoint::SetCallback(BreakpointHitCallback callback, void *baton,
+ bool is_synchronous) {
+ // The default "Baton" class will keep a copy of "baton" and won't free or
+ // delete it when it goes goes out of scope.
+ m_options_up->SetCallback(callback, std::make_shared<UntypedBaton>(baton),
+ is_synchronous);
+
+ SendBreakpointChangedEvent(eBreakpointEventTypeCommandChanged);
+}
+
+// This function is used when a baton needs to be freed and therefore is
+// contained in a "Baton" subclass.
+void Breakpoint::SetCallback(BreakpointHitCallback callback,
+ const BatonSP &callback_baton_sp,
+ bool is_synchronous) {
+ m_options_up->SetCallback(callback, callback_baton_sp, is_synchronous);
+}
+
+void Breakpoint::ClearCallback() { m_options_up->ClearCallback(); }
+
+bool Breakpoint::InvokeCallback(StoppointCallbackContext *context,
+ break_id_t bp_loc_id) {
+ return m_options_up->InvokeCallback(context, GetID(), bp_loc_id);
+}
+
+BreakpointOptions *Breakpoint::GetOptions() { return m_options_up.get(); }
+
+const BreakpointOptions *Breakpoint::GetOptions() const {
+ return m_options_up.get();
+}
+
+void Breakpoint::ResolveBreakpoint() {
+ if (m_resolver_sp)
+ m_resolver_sp->ResolveBreakpoint(*m_filter_sp);
+}
+
+void Breakpoint::ResolveBreakpointInModules(
+ ModuleList &module_list, BreakpointLocationCollection &new_locations) {
+ m_locations.StartRecordingNewLocations(new_locations);
+
+ m_resolver_sp->ResolveBreakpointInModules(*m_filter_sp, module_list);
+
+ m_locations.StopRecordingNewLocations();
+}
+
+void Breakpoint::ResolveBreakpointInModules(ModuleList &module_list,
+ bool send_event) {
+ if (m_resolver_sp) {
+ // If this is not an internal breakpoint, set up to record the new
+ // locations, then dispatch an event with the new locations.
+ if (!IsInternal() && send_event) {
+ BreakpointEventData *new_locations_event = new BreakpointEventData(
+ eBreakpointEventTypeLocationsAdded, shared_from_this());
+
+ ResolveBreakpointInModules(
+ module_list, new_locations_event->GetBreakpointLocationCollection());
+
+ if (new_locations_event->GetBreakpointLocationCollection().GetSize() !=
+ 0) {
+ SendBreakpointChangedEvent(new_locations_event);
+ } else
+ delete new_locations_event;
+ } else {
+ m_resolver_sp->ResolveBreakpointInModules(*m_filter_sp, module_list);
+ }
+ }
+}
+
+void Breakpoint::ClearAllBreakpointSites() {
+ m_locations.ClearAllBreakpointSites();
+}
+
+// ModulesChanged: Pass in a list of new modules, and
+
+void Breakpoint::ModulesChanged(ModuleList &module_list, bool load,
+ bool delete_locations) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+ LLDB_LOGF(log,
+ "Breakpoint::ModulesChanged: num_modules: %zu load: %i "
+ "delete_locations: %i\n",
+ module_list.GetSize(), load, delete_locations);
+
+ std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex());
+ if (load) {
+ // The logic for handling new modules is:
+ // 1) If the filter rejects this module, then skip it. 2) Run through the
+ // current location list and if there are any locations
+ // for that module, we mark the module as "seen" and we don't try to
+ // re-resolve
+ // breakpoint locations for that module.
+ // However, we do add breakpoint sites to these locations if needed.
+ // 3) If we don't see this module in our breakpoint location list, call
+ // ResolveInModules.
+
+ ModuleList new_modules; // We'll stuff the "unseen" modules in this list,
+ // and then resolve
+ // them after the locations pass. Have to do it this way because resolving
+ // breakpoints will add new locations potentially.
+
+ for (ModuleSP module_sp : module_list.ModulesNoLocking()) {
+ bool seen = false;
+ if (!m_filter_sp->ModulePasses(module_sp))
+ continue;
+
+ BreakpointLocationCollection locations_with_no_section;
+ for (BreakpointLocationSP break_loc_sp :
+ m_locations.BreakpointLocations()) {
+
+ // If the section for this location was deleted, that means it's Module
+ // has gone away but somebody forgot to tell us. Let's clean it up
+ // here.
+ Address section_addr(break_loc_sp->GetAddress());
+ if (section_addr.SectionWasDeleted()) {
+ locations_with_no_section.Add(break_loc_sp);
+ continue;
+ }
+
+ if (!break_loc_sp->IsEnabled())
+ continue;
+
+ SectionSP section_sp(section_addr.GetSection());
+
+ // If we don't have a Section, that means this location is a raw
+ // address that we haven't resolved to a section yet. So we'll have to
+ // look in all the new modules to resolve this location. Otherwise, if
+ // it was set in this module, re-resolve it here.
+ if (section_sp && section_sp->GetModule() == module_sp) {
+ if (!seen)
+ seen = true;
+
+ if (!break_loc_sp->ResolveBreakpointSite()) {
+ LLDB_LOGF(log,
+ "Warning: could not set breakpoint site for "
+ "breakpoint location %d of breakpoint %d.\n",
+ break_loc_sp->GetID(), GetID());
+ }
+ }
+ }
+
+ size_t num_to_delete = locations_with_no_section.GetSize();
+
+ for (size_t i = 0; i < num_to_delete; i++)
+ m_locations.RemoveLocation(locations_with_no_section.GetByIndex(i));
+
+ if (!seen)
+ new_modules.AppendIfNeeded(module_sp);
+ }
+
+ if (new_modules.GetSize() > 0) {
+ ResolveBreakpointInModules(new_modules);
+ }
+ } else {
+ // Go through the currently set locations and if any have breakpoints in
+ // the module list, then remove their breakpoint sites, and their locations
+ // if asked to.
+
+ BreakpointEventData *removed_locations_event;
+ if (!IsInternal())
+ removed_locations_event = new BreakpointEventData(
+ eBreakpointEventTypeLocationsRemoved, shared_from_this());
+ else
+ removed_locations_event = nullptr;
+
+ size_t num_modules = module_list.GetSize();
+ for (size_t i = 0; i < num_modules; i++) {
+ ModuleSP module_sp(module_list.GetModuleAtIndexUnlocked(i));
+ if (m_filter_sp->ModulePasses(module_sp)) {
+ size_t loc_idx = 0;
+ size_t num_locations = m_locations.GetSize();
+ BreakpointLocationCollection locations_to_remove;
+ for (loc_idx = 0; loc_idx < num_locations; loc_idx++) {
+ BreakpointLocationSP break_loc_sp(m_locations.GetByIndex(loc_idx));
+ SectionSP section_sp(break_loc_sp->GetAddress().GetSection());
+ if (section_sp && section_sp->GetModule() == module_sp) {
+ // Remove this breakpoint since the shared library is unloaded, but
+ // keep the breakpoint location around so we always get complete
+ // hit count and breakpoint lifetime info
+ break_loc_sp->ClearBreakpointSite();
+ if (removed_locations_event) {
+ removed_locations_event->GetBreakpointLocationCollection().Add(
+ break_loc_sp);
+ }
+ if (delete_locations)
+ locations_to_remove.Add(break_loc_sp);
+ }
+ }
+
+ if (delete_locations) {
+ size_t num_locations_to_remove = locations_to_remove.GetSize();
+ for (loc_idx = 0; loc_idx < num_locations_to_remove; loc_idx++)
+ m_locations.RemoveLocation(locations_to_remove.GetByIndex(loc_idx));
+ }
+ }
+ }
+ SendBreakpointChangedEvent(removed_locations_event);
+ }
+}
+
+namespace {
+static bool SymbolContextsMightBeEquivalent(SymbolContext &old_sc,
+ SymbolContext &new_sc) {
+ bool equivalent_scs = false;
+
+ if (old_sc.module_sp.get() == new_sc.module_sp.get()) {
+ // If these come from the same module, we can directly compare the
+ // pointers:
+ if (old_sc.comp_unit && new_sc.comp_unit &&
+ (old_sc.comp_unit == new_sc.comp_unit)) {
+ if (old_sc.function && new_sc.function &&
+ (old_sc.function == new_sc.function)) {
+ equivalent_scs = true;
+ }
+ } else if (old_sc.symbol && new_sc.symbol &&
+ (old_sc.symbol == new_sc.symbol)) {
+ equivalent_scs = true;
+ }
+ } else {
+ // Otherwise we will compare by name...
+ if (old_sc.comp_unit && new_sc.comp_unit) {
+ if (old_sc.comp_unit->GetPrimaryFile() ==
+ new_sc.comp_unit->GetPrimaryFile()) {
+ // Now check the functions:
+ if (old_sc.function && new_sc.function &&
+ (old_sc.function->GetName() == new_sc.function->GetName())) {
+ equivalent_scs = true;
+ }
+ }
+ } else if (old_sc.symbol && new_sc.symbol) {
+ if (Mangled::Compare(old_sc.symbol->GetMangled(),
+ new_sc.symbol->GetMangled()) == 0) {
+ equivalent_scs = true;
+ }
+ }
+ }
+ return equivalent_scs;
+}
+} // anonymous namespace
+
+void Breakpoint::ModuleReplaced(ModuleSP old_module_sp,
+ ModuleSP new_module_sp) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+ LLDB_LOGF(log, "Breakpoint::ModulesReplaced for %s\n",
+ old_module_sp->GetSpecificationDescription().c_str());
+ // First find all the locations that are in the old module
+
+ BreakpointLocationCollection old_break_locs;
+ for (BreakpointLocationSP break_loc_sp : m_locations.BreakpointLocations()) {
+ SectionSP section_sp = break_loc_sp->GetAddress().GetSection();
+ if (section_sp && section_sp->GetModule() == old_module_sp) {
+ old_break_locs.Add(break_loc_sp);
+ }
+ }
+
+ size_t num_old_locations = old_break_locs.GetSize();
+
+ if (num_old_locations == 0) {
+ // There were no locations in the old module, so we just need to check if
+ // there were any in the new module.
+ ModuleList temp_list;
+ temp_list.Append(new_module_sp);
+ ResolveBreakpointInModules(temp_list);
+ } else {
+ // First search the new module for locations. Then compare this with the
+ // old list, copy over locations that "look the same" Then delete the old
+ // locations. Finally remember to post the creation event.
+ //
+ // Two locations are the same if they have the same comp unit & function
+ // (by name) and there are the same number of locations in the old function
+ // as in the new one.
+
+ ModuleList temp_list;
+ temp_list.Append(new_module_sp);
+ BreakpointLocationCollection new_break_locs;
+ ResolveBreakpointInModules(temp_list, new_break_locs);
+ BreakpointLocationCollection locations_to_remove;
+ BreakpointLocationCollection locations_to_announce;
+
+ size_t num_new_locations = new_break_locs.GetSize();
+
+ if (num_new_locations > 0) {
+ // Break out the case of one location -> one location since that's the
+ // most common one, and there's no need to build up the structures needed
+ // for the merge in that case.
+ if (num_new_locations == 1 && num_old_locations == 1) {
+ bool equivalent_locations = false;
+ SymbolContext old_sc, new_sc;
+ // The only way the old and new location can be equivalent is if they
+ // have the same amount of information:
+ BreakpointLocationSP old_loc_sp = old_break_locs.GetByIndex(0);
+ BreakpointLocationSP new_loc_sp = new_break_locs.GetByIndex(0);
+
+ if (old_loc_sp->GetAddress().CalculateSymbolContext(&old_sc) ==
+ new_loc_sp->GetAddress().CalculateSymbolContext(&new_sc)) {
+ equivalent_locations =
+ SymbolContextsMightBeEquivalent(old_sc, new_sc);
+ }
+
+ if (equivalent_locations) {
+ m_locations.SwapLocation(old_loc_sp, new_loc_sp);
+ } else {
+ locations_to_remove.Add(old_loc_sp);
+ locations_to_announce.Add(new_loc_sp);
+ }
+ } else {
+ // We don't want to have to keep computing the SymbolContexts for these
+ // addresses over and over, so lets get them up front:
+
+ typedef std::map<lldb::break_id_t, SymbolContext> IDToSCMap;
+ IDToSCMap old_sc_map;
+ for (size_t idx = 0; idx < num_old_locations; idx++) {
+ SymbolContext sc;
+ BreakpointLocationSP bp_loc_sp = old_break_locs.GetByIndex(idx);
+ lldb::break_id_t loc_id = bp_loc_sp->GetID();
+ bp_loc_sp->GetAddress().CalculateSymbolContext(&old_sc_map[loc_id]);
+ }
+
+ std::map<lldb::break_id_t, SymbolContext> new_sc_map;
+ for (size_t idx = 0; idx < num_new_locations; idx++) {
+ SymbolContext sc;
+ BreakpointLocationSP bp_loc_sp = new_break_locs.GetByIndex(idx);
+ lldb::break_id_t loc_id = bp_loc_sp->GetID();
+ bp_loc_sp->GetAddress().CalculateSymbolContext(&new_sc_map[loc_id]);
+ }
+ // Take an element from the old Symbol Contexts
+ while (old_sc_map.size() > 0) {
+ lldb::break_id_t old_id = old_sc_map.begin()->first;
+ SymbolContext &old_sc = old_sc_map.begin()->second;
+
+ // Count the number of entries equivalent to this SC for the old
+ // list:
+ std::vector<lldb::break_id_t> old_id_vec;
+ old_id_vec.push_back(old_id);
+
+ IDToSCMap::iterator tmp_iter;
+ for (tmp_iter = ++old_sc_map.begin(); tmp_iter != old_sc_map.end();
+ tmp_iter++) {
+ if (SymbolContextsMightBeEquivalent(old_sc, tmp_iter->second))
+ old_id_vec.push_back(tmp_iter->first);
+ }
+
+ // Now find all the equivalent locations in the new list.
+ std::vector<lldb::break_id_t> new_id_vec;
+ for (tmp_iter = new_sc_map.begin(); tmp_iter != new_sc_map.end();
+ tmp_iter++) {
+ if (SymbolContextsMightBeEquivalent(old_sc, tmp_iter->second))
+ new_id_vec.push_back(tmp_iter->first);
+ }
+
+ // Alright, if we have the same number of potentially equivalent
+ // locations in the old and new modules, we'll just map them one to
+ // one in ascending ID order (assuming the resolver's order would
+ // match the equivalent ones. Otherwise, we'll dump all the old ones,
+ // and just take the new ones, erasing the elements from both maps as
+ // we go.
+
+ if (old_id_vec.size() == new_id_vec.size()) {
+ llvm::sort(old_id_vec);
+ llvm::sort(new_id_vec);
+ size_t num_elements = old_id_vec.size();
+ for (size_t idx = 0; idx < num_elements; idx++) {
+ BreakpointLocationSP old_loc_sp =
+ old_break_locs.FindByIDPair(GetID(), old_id_vec[idx]);
+ BreakpointLocationSP new_loc_sp =
+ new_break_locs.FindByIDPair(GetID(), new_id_vec[idx]);
+ m_locations.SwapLocation(old_loc_sp, new_loc_sp);
+ old_sc_map.erase(old_id_vec[idx]);
+ new_sc_map.erase(new_id_vec[idx]);
+ }
+ } else {
+ for (lldb::break_id_t old_id : old_id_vec) {
+ locations_to_remove.Add(
+ old_break_locs.FindByIDPair(GetID(), old_id));
+ old_sc_map.erase(old_id);
+ }
+ for (lldb::break_id_t new_id : new_id_vec) {
+ locations_to_announce.Add(
+ new_break_locs.FindByIDPair(GetID(), new_id));
+ new_sc_map.erase(new_id);
+ }
+ }
+ }
+ }
+ }
+
+ // Now remove the remaining old locations, and cons up a removed locations
+ // event. Note, we don't put the new locations that were swapped with an
+ // old location on the locations_to_remove list, so we don't need to worry
+ // about telling the world about removing a location we didn't tell them
+ // about adding.
+
+ BreakpointEventData *locations_event;
+ if (!IsInternal())
+ locations_event = new BreakpointEventData(
+ eBreakpointEventTypeLocationsRemoved, shared_from_this());
+ else
+ locations_event = nullptr;
+
+ for (BreakpointLocationSP loc_sp :
+ locations_to_remove.BreakpointLocations()) {
+ m_locations.RemoveLocation(loc_sp);
+ if (locations_event)
+ locations_event->GetBreakpointLocationCollection().Add(loc_sp);
+ }
+ SendBreakpointChangedEvent(locations_event);
+
+ // And announce the new ones.
+
+ if (!IsInternal()) {
+ locations_event = new BreakpointEventData(
+ eBreakpointEventTypeLocationsAdded, shared_from_this());
+ for (BreakpointLocationSP loc_sp :
+ locations_to_announce.BreakpointLocations())
+ locations_event->GetBreakpointLocationCollection().Add(loc_sp);
+
+ SendBreakpointChangedEvent(locations_event);
+ }
+ m_locations.Compact();
+ }
+}
+
+void Breakpoint::Dump(Stream *) {}
+
+size_t Breakpoint::GetNumResolvedLocations() const {
+ // Return the number of breakpoints that are actually resolved and set down
+ // in the inferior process.
+ return m_locations.GetNumResolvedLocations();
+}
+
+bool Breakpoint::HasResolvedLocations() const {
+ return GetNumResolvedLocations() > 0;
+}
+
+size_t Breakpoint::GetNumLocations() const { return m_locations.GetSize(); }
+
+bool Breakpoint::AddName(llvm::StringRef new_name) {
+ m_name_list.insert(new_name.str().c_str());
+ return true;
+}
+
+void Breakpoint::GetDescription(Stream *s, lldb::DescriptionLevel level,
+ bool show_locations) {
+ assert(s != nullptr);
+
+ if (!m_kind_description.empty()) {
+ if (level == eDescriptionLevelBrief) {
+ s->PutCString(GetBreakpointKind());
+ return;
+ } else
+ s->Printf("Kind: %s\n", GetBreakpointKind());
+ }
+
+ const size_t num_locations = GetNumLocations();
+ const size_t num_resolved_locations = GetNumResolvedLocations();
+
+ // They just made the breakpoint, they don't need to be told HOW they made
+ // it... Also, we'll print the breakpoint number differently depending on
+ // whether there is 1 or more locations.
+ if (level != eDescriptionLevelInitial) {
+ s->Printf("%i: ", GetID());
+ GetResolverDescription(s);
+ GetFilterDescription(s);
+ }
+
+ switch (level) {
+ case lldb::eDescriptionLevelBrief:
+ case lldb::eDescriptionLevelFull:
+ if (num_locations > 0) {
+ s->Printf(", locations = %" PRIu64, (uint64_t)num_locations);
+ if (num_resolved_locations > 0)
+ s->Printf(", resolved = %" PRIu64 ", hit count = %d",
+ (uint64_t)num_resolved_locations, GetHitCount());
+ } else {
+ // Don't print the pending notification for exception resolvers since we
+ // don't generally know how to set them until the target is run.
+ if (m_resolver_sp->getResolverID() !=
+ BreakpointResolver::ExceptionResolver)
+ s->Printf(", locations = 0 (pending)");
+ }
+
+ GetOptions()->GetDescription(s, level);
+
+ if (m_precondition_sp)
+ m_precondition_sp->GetDescription(*s, level);
+
+ if (level == lldb::eDescriptionLevelFull) {
+ if (!m_name_list.empty()) {
+ s->EOL();
+ s->Indent();
+ s->Printf("Names:");
+ s->EOL();
+ s->IndentMore();
+ for (std::string name : m_name_list) {
+ s->Indent();
+ s->Printf("%s\n", name.c_str());
+ }
+ s->IndentLess();
+ }
+ s->IndentLess();
+ s->EOL();
+ }
+ break;
+
+ case lldb::eDescriptionLevelInitial:
+ s->Printf("Breakpoint %i: ", GetID());
+ if (num_locations == 0) {
+ s->Printf("no locations (pending).");
+ } else if (num_locations == 1 && !show_locations) {
+ // There is only one location, so we'll just print that location
+ // information.
+ GetLocationAtIndex(0)->GetDescription(s, level);
+ } else {
+ s->Printf("%" PRIu64 " locations.", static_cast<uint64_t>(num_locations));
+ }
+ s->EOL();
+ break;
+
+ case lldb::eDescriptionLevelVerbose:
+ // Verbose mode does a debug dump of the breakpoint
+ Dump(s);
+ s->EOL();
+ // s->Indent();
+ GetOptions()->GetDescription(s, level);
+ break;
+
+ default:
+ break;
+ }
+
+ // The brief description is just the location name (1.2 or whatever). That's
+ // pointless to show in the breakpoint's description, so suppress it.
+ if (show_locations && level != lldb::eDescriptionLevelBrief) {
+ s->IndentMore();
+ for (size_t i = 0; i < num_locations; ++i) {
+ BreakpointLocation *loc = GetLocationAtIndex(i).get();
+ loc->GetDescription(s, level);
+ s->EOL();
+ }
+ s->IndentLess();
+ }
+}
+
+void Breakpoint::GetResolverDescription(Stream *s) {
+ if (m_resolver_sp)
+ m_resolver_sp->GetDescription(s);
+}
+
+bool Breakpoint::GetMatchingFileLine(ConstString filename,
+ uint32_t line_number,
+ BreakpointLocationCollection &loc_coll) {
+ // TODO: To be correct, this method needs to fill the breakpoint location
+ // collection
+ // with the location IDs which match the filename and line_number.
+ //
+
+ if (m_resolver_sp) {
+ BreakpointResolverFileLine *resolverFileLine =
+ dyn_cast<BreakpointResolverFileLine>(m_resolver_sp.get());
+ if (resolverFileLine &&
+ resolverFileLine->m_file_spec.GetFilename() == filename &&
+ resolverFileLine->m_line_number == line_number) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void Breakpoint::GetFilterDescription(Stream *s) {
+ m_filter_sp->GetDescription(s);
+}
+
+bool Breakpoint::EvaluatePrecondition(StoppointCallbackContext &context) {
+ if (!m_precondition_sp)
+ return true;
+
+ return m_precondition_sp->EvaluatePrecondition(context);
+}
+
+void Breakpoint::SendBreakpointChangedEvent(
+ lldb::BreakpointEventType eventKind) {
+ if (!m_being_created && !IsInternal() &&
+ GetTarget().EventTypeHasListeners(
+ Target::eBroadcastBitBreakpointChanged)) {
+ BreakpointEventData *data =
+ new Breakpoint::BreakpointEventData(eventKind, shared_from_this());
+
+ GetTarget().BroadcastEvent(Target::eBroadcastBitBreakpointChanged, data);
+ }
+}
+
+void Breakpoint::SendBreakpointChangedEvent(BreakpointEventData *data) {
+ if (data == nullptr)
+ return;
+
+ if (!m_being_created && !IsInternal() &&
+ GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
+ GetTarget().BroadcastEvent(Target::eBroadcastBitBreakpointChanged, data);
+ else
+ delete data;
+}
+
+Breakpoint::BreakpointEventData::BreakpointEventData(
+ BreakpointEventType sub_type, const BreakpointSP &new_breakpoint_sp)
+ : EventData(), m_breakpoint_event(sub_type),
+ m_new_breakpoint_sp(new_breakpoint_sp) {}
+
+Breakpoint::BreakpointEventData::~BreakpointEventData() = default;
+
+ConstString Breakpoint::BreakpointEventData::GetFlavorString() {
+ static ConstString g_flavor("Breakpoint::BreakpointEventData");
+ return g_flavor;
+}
+
+ConstString Breakpoint::BreakpointEventData::GetFlavor() const {
+ return BreakpointEventData::GetFlavorString();
+}
+
+BreakpointSP &Breakpoint::BreakpointEventData::GetBreakpoint() {
+ return m_new_breakpoint_sp;
+}
+
+BreakpointEventType
+Breakpoint::BreakpointEventData::GetBreakpointEventType() const {
+ return m_breakpoint_event;
+}
+
+void Breakpoint::BreakpointEventData::Dump(Stream *s) const {}
+
+const Breakpoint::BreakpointEventData *
+Breakpoint::BreakpointEventData::GetEventDataFromEvent(const Event *event) {
+ if (event) {
+ const EventData *event_data = event->GetData();
+ if (event_data &&
+ event_data->GetFlavor() == BreakpointEventData::GetFlavorString())
+ return static_cast<const BreakpointEventData *>(event->GetData());
+ }
+ return nullptr;
+}
+
+BreakpointEventType
+Breakpoint::BreakpointEventData::GetBreakpointEventTypeFromEvent(
+ const EventSP &event_sp) {
+ const BreakpointEventData *data = GetEventDataFromEvent(event_sp.get());
+
+ if (data == nullptr)
+ return eBreakpointEventTypeInvalidType;
+ else
+ return data->GetBreakpointEventType();
+}
+
+BreakpointSP Breakpoint::BreakpointEventData::GetBreakpointFromEvent(
+ const EventSP &event_sp) {
+ BreakpointSP bp_sp;
+
+ const BreakpointEventData *data = GetEventDataFromEvent(event_sp.get());
+ if (data)
+ bp_sp = data->m_new_breakpoint_sp;
+
+ return bp_sp;
+}
+
+size_t Breakpoint::BreakpointEventData::GetNumBreakpointLocationsFromEvent(
+ const EventSP &event_sp) {
+ const BreakpointEventData *data = GetEventDataFromEvent(event_sp.get());
+ if (data)
+ return data->m_locations.GetSize();
+
+ return 0;
+}
+
+lldb::BreakpointLocationSP
+Breakpoint::BreakpointEventData::GetBreakpointLocationAtIndexFromEvent(
+ const lldb::EventSP &event_sp, uint32_t bp_loc_idx) {
+ lldb::BreakpointLocationSP bp_loc_sp;
+
+ const BreakpointEventData *data = GetEventDataFromEvent(event_sp.get());
+ if (data) {
+ bp_loc_sp = data->m_locations.GetByIndex(bp_loc_idx);
+ }
+
+ return bp_loc_sp;
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointID.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointID.cpp
new file mode 100644
index 00000000000..dc2e57cb085
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointID.cpp
@@ -0,0 +1,121 @@
+//===-- BreakpointID.cpp ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointID.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointID::BreakpointID(break_id_t bp_id, break_id_t loc_id)
+ : m_break_id(bp_id), m_location_id(loc_id) {}
+
+BreakpointID::~BreakpointID() = default;
+
+static llvm::StringRef g_range_specifiers[] = {"-", "to", "To", "TO"};
+
+// Tells whether or not STR is valid to use between two strings representing
+// breakpoint IDs, to indicate a range of breakpoint IDs. This is broken out
+// into a separate function so that we can easily change or add to the format
+// for specifying ID ranges at a later date.
+
+bool BreakpointID::IsRangeIdentifier(llvm::StringRef str) {
+ for (auto spec : g_range_specifiers) {
+ if (spec == str)
+ return true;
+ }
+
+ return false;
+}
+
+bool BreakpointID::IsValidIDExpression(llvm::StringRef str) {
+ return BreakpointID::ParseCanonicalReference(str).hasValue();
+}
+
+llvm::ArrayRef<llvm::StringRef> BreakpointID::GetRangeSpecifiers() {
+ return llvm::makeArrayRef(g_range_specifiers);
+}
+
+void BreakpointID::GetDescription(Stream *s, lldb::DescriptionLevel level) {
+ if (level == eDescriptionLevelVerbose)
+ s->Printf("%p BreakpointID:", static_cast<void *>(this));
+
+ if (m_break_id == LLDB_INVALID_BREAK_ID)
+ s->PutCString("<invalid>");
+ else if (m_location_id == LLDB_INVALID_BREAK_ID)
+ s->Printf("%i", m_break_id);
+ else
+ s->Printf("%i.%i", m_break_id, m_location_id);
+}
+
+void BreakpointID::GetCanonicalReference(Stream *s, break_id_t bp_id,
+ break_id_t loc_id) {
+ if (bp_id == LLDB_INVALID_BREAK_ID)
+ s->PutCString("<invalid>");
+ else if (loc_id == LLDB_INVALID_BREAK_ID)
+ s->Printf("%i", bp_id);
+ else
+ s->Printf("%i.%i", bp_id, loc_id);
+}
+
+llvm::Optional<BreakpointID>
+BreakpointID::ParseCanonicalReference(llvm::StringRef input) {
+ break_id_t bp_id;
+ break_id_t loc_id = LLDB_INVALID_BREAK_ID;
+
+ if (input.empty())
+ return llvm::None;
+
+ // If it doesn't start with an integer, it's not valid.
+ if (input.consumeInteger(0, bp_id))
+ return llvm::None;
+
+ // period is optional, but if it exists, it must be followed by a number.
+ if (input.consume_front(".")) {
+ if (input.consumeInteger(0, loc_id))
+ return llvm::None;
+ }
+
+ // And at the end, the entire string must have been consumed.
+ if (!input.empty())
+ return llvm::None;
+
+ return BreakpointID(bp_id, loc_id);
+}
+
+bool BreakpointID::StringIsBreakpointName(llvm::StringRef str, Status &error) {
+ error.Clear();
+ if (str.empty())
+ {
+ error.SetErrorStringWithFormat("Empty breakpoint names are not allowed");
+ return false;
+ }
+
+ // First character must be a letter or _
+ if (!isalpha(str[0]) && str[0] != '_')
+ {
+ error.SetErrorStringWithFormat("Breakpoint names must start with a "
+ "character or underscore: %s",
+ str.str().c_str());
+ return false;
+ }
+
+ // Cannot contain ., -, or space.
+ if (str.find_first_of(".- ") != llvm::StringRef::npos) {
+ error.SetErrorStringWithFormat("Breakpoint names cannot contain "
+ "'.' or '-': \"%s\"",
+ str.str().c_str());
+ return false;
+ }
+
+ return true;
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointIDList.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointIDList.cpp
new file mode 100644
index 00000000000..de68c44ec6a
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointIDList.cpp
@@ -0,0 +1,348 @@
+//===-- BreakpointIDList.cpp ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Breakpoint/BreakpointIDList.h"
+
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/Args.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// class BreakpointIDList
+
+BreakpointIDList::BreakpointIDList()
+ : m_invalid_id(LLDB_INVALID_BREAK_ID, LLDB_INVALID_BREAK_ID) {}
+
+BreakpointIDList::~BreakpointIDList() = default;
+
+size_t BreakpointIDList::GetSize() const { return m_breakpoint_ids.size(); }
+
+const BreakpointID &
+BreakpointIDList::GetBreakpointIDAtIndex(size_t index) const {
+ return ((index < m_breakpoint_ids.size()) ? m_breakpoint_ids[index]
+ : m_invalid_id);
+}
+
+bool BreakpointIDList::RemoveBreakpointIDAtIndex(size_t index) {
+ if (index >= m_breakpoint_ids.size())
+ return false;
+
+ m_breakpoint_ids.erase(m_breakpoint_ids.begin() + index);
+ return true;
+}
+
+void BreakpointIDList::Clear() { m_breakpoint_ids.clear(); }
+
+bool BreakpointIDList::AddBreakpointID(BreakpointID bp_id) {
+ m_breakpoint_ids.push_back(bp_id);
+
+ return true; // We don't do any verification in this function, so always
+ // return true.
+}
+
+bool BreakpointIDList::AddBreakpointID(const char *bp_id_str) {
+ auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
+ if (!bp_id.hasValue())
+ return false;
+
+ m_breakpoint_ids.push_back(*bp_id);
+ return true;
+}
+
+bool BreakpointIDList::FindBreakpointID(BreakpointID &bp_id,
+ size_t *position) const {
+ for (size_t i = 0; i < m_breakpoint_ids.size(); ++i) {
+ BreakpointID tmp_id = m_breakpoint_ids[i];
+ if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID() &&
+ tmp_id.GetLocationID() == bp_id.GetLocationID()) {
+ *position = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool BreakpointIDList::FindBreakpointID(const char *bp_id_str,
+ size_t *position) const {
+ auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
+ if (!bp_id.hasValue())
+ return false;
+
+ return FindBreakpointID(*bp_id, position);
+}
+
+void BreakpointIDList::InsertStringArray(
+ llvm::ArrayRef<const char *> string_array, CommandReturnObject &result) {
+ if(string_array.empty())
+ return;
+
+ for (const char *str : string_array) {
+ auto bp_id = BreakpointID::ParseCanonicalReference(str);
+ if (bp_id.hasValue())
+ m_breakpoint_ids.push_back(*bp_id);
+ }
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+}
+
+// This function takes OLD_ARGS, which is usually the result of breaking the
+// command string arguments into
+// an array of space-separated strings, and searches through the arguments for
+// any breakpoint ID range specifiers.
+// Any string in the array that is not part of an ID range specifier is copied
+// directly into NEW_ARGS. If any
+// ID range specifiers are found, the range is interpreted and a list of
+// canonical breakpoint IDs corresponding to
+// all the current breakpoints and locations in the range are added to
+// NEW_ARGS. When this function is done,
+// NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced
+// by the members of the range.
+
+void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target,
+ bool allow_locations,
+ BreakpointName::Permissions
+ ::PermissionKinds purpose,
+ CommandReturnObject &result,
+ Args &new_args) {
+ llvm::StringRef range_from;
+ llvm::StringRef range_to;
+ llvm::StringRef current_arg;
+ std::set<std::string> names_found;
+
+ for (size_t i = 0; i < old_args.size(); ++i) {
+ bool is_range = false;
+
+ current_arg = old_args[i].ref();
+ if (!allow_locations && current_arg.contains('.')) {
+ result.AppendErrorWithFormat(
+ "Breakpoint locations not allowed, saw location: %s.",
+ current_arg.str().c_str());
+ new_args.Clear();
+ return;
+ }
+
+ Status error;
+
+ std::tie(range_from, range_to) =
+ BreakpointIDList::SplitIDRangeExpression(current_arg);
+ if (!range_from.empty() && !range_to.empty()) {
+ is_range = true;
+ } else if (BreakpointID::StringIsBreakpointName(current_arg, error)) {
+ if (!error.Success()) {
+ new_args.Clear();
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return;
+ } else
+ names_found.insert(current_arg);
+ } else if ((i + 2 < old_args.size()) &&
+ BreakpointID::IsRangeIdentifier(old_args[i + 1].ref()) &&
+ BreakpointID::IsValidIDExpression(current_arg) &&
+ BreakpointID::IsValidIDExpression(old_args[i + 2].ref())) {
+ range_from = current_arg;
+ range_to = old_args[i + 2].ref();
+ is_range = true;
+ i = i + 2;
+ } else {
+ // See if user has specified id.*
+ llvm::StringRef tmp_str = old_args[i].ref();
+ size_t pos = tmp_str.find('.');
+ if (pos != llvm::StringRef::npos) {
+ llvm::StringRef bp_id_str = tmp_str.substr(0, pos);
+ if (BreakpointID::IsValidIDExpression(bp_id_str) &&
+ tmp_str[pos + 1] == '*' && tmp_str.size() == (pos + 2)) {
+
+ BreakpointSP breakpoint_sp;
+ auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
+ if (bp_id.hasValue())
+ breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID());
+ if (!breakpoint_sp) {
+ new_args.Clear();
+ result.AppendErrorWithFormat("'%d' is not a valid breakpoint ID.\n",
+ bp_id->GetBreakpointID());
+ result.SetStatus(eReturnStatusFailed);
+ return;
+ }
+ const size_t num_locations = breakpoint_sp->GetNumLocations();
+ for (size_t j = 0; j < num_locations; ++j) {
+ BreakpointLocation *bp_loc =
+ breakpoint_sp->GetLocationAtIndex(j).get();
+ StreamString canonical_id_str;
+ BreakpointID::GetCanonicalReference(
+ &canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID());
+ new_args.AppendArgument(canonical_id_str.GetString());
+ }
+ }
+ }
+ }
+
+ if (!is_range) {
+ new_args.AppendArgument(current_arg);
+ continue;
+ }
+
+ auto start_bp = BreakpointID::ParseCanonicalReference(range_from);
+ auto end_bp = BreakpointID::ParseCanonicalReference(range_to);
+
+ if (!start_bp.hasValue() ||
+ !target->GetBreakpointByID(start_bp->GetBreakpointID())) {
+ new_args.Clear();
+ result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
+ range_from.str().c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return;
+ }
+
+ if (!end_bp.hasValue() ||
+ !target->GetBreakpointByID(end_bp->GetBreakpointID())) {
+ new_args.Clear();
+ result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
+ range_to.str().c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return;
+ }
+ break_id_t start_bp_id = start_bp->GetBreakpointID();
+ break_id_t start_loc_id = start_bp->GetLocationID();
+ break_id_t end_bp_id = end_bp->GetBreakpointID();
+ break_id_t end_loc_id = end_bp->GetLocationID();
+ if (((start_loc_id == LLDB_INVALID_BREAK_ID) &&
+ (end_loc_id != LLDB_INVALID_BREAK_ID)) ||
+ ((start_loc_id != LLDB_INVALID_BREAK_ID) &&
+ (end_loc_id == LLDB_INVALID_BREAK_ID))) {
+ new_args.Clear();
+ result.AppendErrorWithFormat("Invalid breakpoint id range: Either "
+ "both ends of range must specify"
+ " a breakpoint location, or neither can "
+ "specify a breakpoint location.\n");
+ result.SetStatus(eReturnStatusFailed);
+ return;
+ }
+
+ // We have valid range starting & ending breakpoint IDs. Go through all
+ // the breakpoints in the target and find all the breakpoints that fit into
+ // this range, and add them to new_args.
+
+ // Next check to see if we have location id's. If so, make sure the
+ // start_bp_id and end_bp_id are for the same breakpoint; otherwise we have
+ // an illegal range: breakpoint id ranges that specify bp locations are NOT
+ // allowed to cross major bp id numbers.
+
+ if ((start_loc_id != LLDB_INVALID_BREAK_ID) ||
+ (end_loc_id != LLDB_INVALID_BREAK_ID)) {
+ if (start_bp_id != end_bp_id) {
+ new_args.Clear();
+ result.AppendErrorWithFormat(
+ "Invalid range: Ranges that specify particular breakpoint "
+ "locations"
+ " must be within the same major breakpoint; you specified two"
+ " different major breakpoints, %d and %d.\n",
+ start_bp_id, end_bp_id);
+ result.SetStatus(eReturnStatusFailed);
+ return;
+ }
+ }
+
+ const BreakpointList &breakpoints = target->GetBreakpointList();
+ const size_t num_breakpoints = breakpoints.GetSize();
+ for (size_t j = 0; j < num_breakpoints; ++j) {
+ Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(j).get();
+ break_id_t cur_bp_id = breakpoint->GetID();
+
+ if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
+ continue;
+
+ const size_t num_locations = breakpoint->GetNumLocations();
+
+ if ((cur_bp_id == start_bp_id) &&
+ (start_loc_id != LLDB_INVALID_BREAK_ID)) {
+ for (size_t k = 0; k < num_locations; ++k) {
+ BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();
+ if ((bp_loc->GetID() >= start_loc_id) &&
+ (bp_loc->GetID() <= end_loc_id)) {
+ StreamString canonical_id_str;
+ BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
+ bp_loc->GetID());
+ new_args.AppendArgument(canonical_id_str.GetString());
+ }
+ }
+ } else if ((cur_bp_id == end_bp_id) &&
+ (end_loc_id != LLDB_INVALID_BREAK_ID)) {
+ for (size_t k = 0; k < num_locations; ++k) {
+ BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();
+ if (bp_loc->GetID() <= end_loc_id) {
+ StreamString canonical_id_str;
+ BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
+ bp_loc->GetID());
+ new_args.AppendArgument(canonical_id_str.GetString());
+ }
+ }
+ } else {
+ StreamString canonical_id_str;
+ BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
+ LLDB_INVALID_BREAK_ID);
+ new_args.AppendArgument(canonical_id_str.GetString());
+ }
+ }
+ }
+
+ // Okay, now see if we found any names, and if we did, add them:
+ if (target && !names_found.empty()) {
+ Status error;
+ // Remove any names that aren't visible for this purpose:
+ auto iter = names_found.begin();
+ while (iter != names_found.end()) {
+ BreakpointName *bp_name = target->FindBreakpointName(ConstString(*iter),
+ true,
+ error);
+ if (bp_name && !bp_name->GetPermission(purpose))
+ iter = names_found.erase(iter);
+ else
+ iter++;
+ }
+
+ if (!names_found.empty()) {
+ for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints()) {
+ for (std::string name : names_found) {
+ if (bkpt_sp->MatchesName(name.c_str())) {
+ StreamString canonical_id_str;
+ BreakpointID::GetCanonicalReference(
+ &canonical_id_str, bkpt_sp->GetID(), LLDB_INVALID_BREAK_ID);
+ new_args.AppendArgument(canonical_id_str.GetString());
+ }
+ }
+ }
+ }
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+}
+
+std::pair<llvm::StringRef, llvm::StringRef>
+BreakpointIDList::SplitIDRangeExpression(llvm::StringRef in_string) {
+ for (auto specifier_str : BreakpointID::GetRangeSpecifiers()) {
+ size_t idx = in_string.find(specifier_str);
+ if (idx == llvm::StringRef::npos)
+ continue;
+ llvm::StringRef right1 = in_string.drop_front(idx);
+
+ llvm::StringRef from = in_string.take_front(idx);
+ llvm::StringRef to = right1.drop_front(specifier_str.size());
+
+ if (BreakpointID::IsValidIDExpression(from) &&
+ BreakpointID::IsValidIDExpression(to)) {
+ return std::make_pair(from, to);
+ }
+ }
+
+ return std::pair<llvm::StringRef, llvm::StringRef>();
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointList.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointList.cpp
new file mode 100644
index 00000000000..5b23c633d14
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointList.cpp
@@ -0,0 +1,195 @@
+//===-- BreakpointList.cpp --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointList.h"
+
+#include "lldb/Target/Target.h"
+
+#include "llvm/Support/Errc.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static void NotifyChange(const BreakpointSP &bp, BreakpointEventType event) {
+ Target &target = bp->GetTarget();
+ if (target.EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
+ target.BroadcastEvent(Target::eBroadcastBitBreakpointChanged,
+ new Breakpoint::BreakpointEventData(event, bp));
+}
+
+BreakpointList::BreakpointList(bool is_internal)
+ : m_mutex(), m_breakpoints(), m_next_break_id(0),
+ m_is_internal(is_internal) {}
+
+BreakpointList::~BreakpointList() {}
+
+break_id_t BreakpointList::Add(BreakpointSP &bp_sp, bool notify) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+
+ // Internal breakpoint IDs are negative, normal ones are positive
+ bp_sp->SetID(m_is_internal ? --m_next_break_id : ++m_next_break_id);
+
+ m_breakpoints.push_back(bp_sp);
+
+ if (notify)
+ NotifyChange(bp_sp, eBreakpointEventTypeAdded);
+
+ return bp_sp->GetID();
+}
+
+bool BreakpointList::Remove(break_id_t break_id, bool notify) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+
+ auto it = std::find_if(
+ m_breakpoints.begin(), m_breakpoints.end(),
+ [&](const BreakpointSP &bp) { return bp->GetID() == break_id; });
+
+ if (it == m_breakpoints.end())
+ return false;
+
+ if (notify)
+ NotifyChange(*it, eBreakpointEventTypeRemoved);
+
+ m_breakpoints.erase(it);
+
+ return true;
+}
+
+void BreakpointList::RemoveInvalidLocations(const ArchSpec &arch) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ for (const auto &bp_sp : m_breakpoints)
+ bp_sp->RemoveInvalidLocations(arch);
+}
+
+void BreakpointList::SetEnabledAll(bool enabled) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ for (const auto &bp_sp : m_breakpoints)
+ bp_sp->SetEnabled(enabled);
+}
+
+void BreakpointList::SetEnabledAllowed(bool enabled) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ for (const auto &bp_sp : m_breakpoints)
+ if (bp_sp->AllowDisable())
+ bp_sp->SetEnabled(enabled);
+}
+
+void BreakpointList::RemoveAll(bool notify) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ ClearAllBreakpointSites();
+
+ if (notify) {
+ for (const auto &bp_sp : m_breakpoints)
+ NotifyChange(bp_sp, eBreakpointEventTypeRemoved);
+ }
+
+ m_breakpoints.clear();
+}
+
+void BreakpointList::RemoveAllowed(bool notify) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+
+ for (const auto &bp_sp : m_breakpoints) {
+ if (bp_sp->AllowDelete())
+ bp_sp->ClearAllBreakpointSites();
+ if (notify)
+ NotifyChange(bp_sp, eBreakpointEventTypeRemoved);
+ }
+
+ m_breakpoints.erase(
+ std::remove_if(m_breakpoints.begin(), m_breakpoints.end(),
+ [&](const BreakpointSP &bp) { return bp->AllowDelete(); }),
+ m_breakpoints.end());
+}
+
+BreakpointList::bp_collection::iterator
+BreakpointList::GetBreakpointIDIterator(break_id_t break_id) {
+ return std::find_if(
+ m_breakpoints.begin(), m_breakpoints.end(),
+ [&](const BreakpointSP &bp) { return bp->GetID() == break_id; });
+}
+
+BreakpointList::bp_collection::const_iterator
+BreakpointList::GetBreakpointIDConstIterator(break_id_t break_id) const {
+ return std::find_if(
+ m_breakpoints.begin(), m_breakpoints.end(),
+ [&](const BreakpointSP &bp) { return bp->GetID() == break_id; });
+}
+
+BreakpointSP BreakpointList::FindBreakpointByID(break_id_t break_id) const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+
+ auto it = GetBreakpointIDConstIterator(break_id);
+ if (it != m_breakpoints.end())
+ return *it;
+ return {};
+}
+
+llvm::Expected<std::vector<lldb::BreakpointSP>>
+BreakpointList::FindBreakpointsByName(const char *name) {
+ if (!name)
+ return llvm::createStringError(llvm::errc::invalid_argument,
+ "FindBreakpointsByName requires a name");
+
+ Status error;
+ if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(name), error))
+ return error.ToError();
+
+ std::vector<lldb::BreakpointSP> matching_bps;
+ for (BreakpointSP bkpt_sp : Breakpoints()) {
+ if (bkpt_sp->MatchesName(name)) {
+ matching_bps.push_back(bkpt_sp);
+ }
+ }
+
+ return matching_bps;
+}
+
+void BreakpointList::Dump(Stream *s) const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ s->Printf("%p: ", static_cast<const void *>(this));
+ s->Indent();
+ s->Printf("BreakpointList with %u Breakpoints:\n",
+ (uint32_t)m_breakpoints.size());
+ s->IndentMore();
+ for (const auto &bp_sp : m_breakpoints)
+ bp_sp->Dump(s);
+ s->IndentLess();
+}
+
+BreakpointSP BreakpointList::GetBreakpointAtIndex(size_t i) const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (i < m_breakpoints.size())
+ return m_breakpoints[i];
+ return {};
+}
+
+void BreakpointList::UpdateBreakpoints(ModuleList &module_list, bool added,
+ bool delete_locations) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ for (const auto &bp_sp : m_breakpoints)
+ bp_sp->ModulesChanged(module_list, added, delete_locations);
+}
+
+void BreakpointList::UpdateBreakpointsWhenModuleIsReplaced(
+ ModuleSP old_module_sp, ModuleSP new_module_sp) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ for (const auto &bp_sp : m_breakpoints)
+ bp_sp->ModuleReplaced(old_module_sp, new_module_sp);
+}
+
+void BreakpointList::ClearAllBreakpointSites() {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ for (const auto &bp_sp : m_breakpoints)
+ bp_sp->ClearAllBreakpointSites();
+}
+
+void BreakpointList::GetListMutex(
+ std::unique_lock<std::recursive_mutex> &lock) {
+ lock = std::unique_lock<std::recursive_mutex>(m_mutex);
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointLocation.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointLocation.cpp
new file mode 100644
index 00000000000..7f08b08c605
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointLocation.cpp
@@ -0,0 +1,659 @@
+//===-- BreakpointLocation.cpp ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointID.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Expression/DiagnosticManager.h"
+#include "lldb/Expression/ExpressionVariable.h"
+#include "lldb/Expression/UserExpression.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/TypeSystem.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointLocation::BreakpointLocation(break_id_t loc_id, Breakpoint &owner,
+ const Address &addr, lldb::tid_t tid,
+ bool hardware, bool check_for_resolver)
+ : StoppointLocation(loc_id, addr.GetOpcodeLoadAddress(&owner.GetTarget()),
+ hardware),
+ m_being_created(true), m_should_resolve_indirect_functions(false),
+ m_is_reexported(false), m_is_indirect(false), m_address(addr),
+ m_owner(owner), m_options_up(), m_bp_site_sp(), m_condition_mutex() {
+ if (check_for_resolver) {
+ Symbol *symbol = m_address.CalculateSymbolContextSymbol();
+ if (symbol && symbol->IsIndirect()) {
+ SetShouldResolveIndirectFunctions(true);
+ }
+ }
+
+ SetThreadID(tid);
+ m_being_created = false;
+}
+
+BreakpointLocation::~BreakpointLocation() { ClearBreakpointSite(); }
+
+lldb::addr_t BreakpointLocation::GetLoadAddress() const {
+ return m_address.GetOpcodeLoadAddress(&m_owner.GetTarget());
+}
+
+const BreakpointOptions *
+BreakpointLocation::GetOptionsSpecifyingKind(BreakpointOptions::OptionKind kind)
+const {
+ if (m_options_up && m_options_up->IsOptionSet(kind))
+ return m_options_up.get();
+ else
+ return m_owner.GetOptions();
+}
+
+Address &BreakpointLocation::GetAddress() { return m_address; }
+
+Breakpoint &BreakpointLocation::GetBreakpoint() { return m_owner; }
+
+Target &BreakpointLocation::GetTarget() { return m_owner.GetTarget(); }
+
+bool BreakpointLocation::IsEnabled() const {
+ if (!m_owner.IsEnabled())
+ return false;
+ else if (m_options_up != nullptr)
+ return m_options_up->IsEnabled();
+ else
+ return true;
+}
+
+void BreakpointLocation::SetEnabled(bool enabled) {
+ GetLocationOptions()->SetEnabled(enabled);
+ if (enabled) {
+ ResolveBreakpointSite();
+ } else {
+ ClearBreakpointSite();
+ }
+ SendBreakpointLocationChangedEvent(enabled ? eBreakpointEventTypeEnabled
+ : eBreakpointEventTypeDisabled);
+}
+
+bool BreakpointLocation::IsAutoContinue() const {
+ if (m_options_up &&
+ m_options_up->IsOptionSet(BreakpointOptions::eAutoContinue))
+ return m_options_up->IsAutoContinue();
+ else
+ return m_owner.IsAutoContinue();
+}
+
+void BreakpointLocation::SetAutoContinue(bool auto_continue) {
+ GetLocationOptions()->SetAutoContinue(auto_continue);
+ SendBreakpointLocationChangedEvent(eBreakpointEventTypeAutoContinueChanged);
+}
+
+void BreakpointLocation::SetThreadID(lldb::tid_t thread_id) {
+ if (thread_id != LLDB_INVALID_THREAD_ID)
+ GetLocationOptions()->SetThreadID(thread_id);
+ else {
+ // If we're resetting this to an invalid thread id, then don't make an
+ // options pointer just to do that.
+ if (m_options_up != nullptr)
+ m_options_up->SetThreadID(thread_id);
+ }
+ SendBreakpointLocationChangedEvent(eBreakpointEventTypeThreadChanged);
+}
+
+lldb::tid_t BreakpointLocation::GetThreadID() {
+ const ThreadSpec *thread_spec =
+ GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec)
+ ->GetThreadSpecNoCreate();
+ if (thread_spec)
+ return thread_spec->GetTID();
+ else
+ return LLDB_INVALID_THREAD_ID;
+}
+
+void BreakpointLocation::SetThreadIndex(uint32_t index) {
+ if (index != 0)
+ GetLocationOptions()->GetThreadSpec()->SetIndex(index);
+ else {
+ // If we're resetting this to an invalid thread id, then don't make an
+ // options pointer just to do that.
+ if (m_options_up != nullptr)
+ m_options_up->GetThreadSpec()->SetIndex(index);
+ }
+ SendBreakpointLocationChangedEvent(eBreakpointEventTypeThreadChanged);
+}
+
+uint32_t BreakpointLocation::GetThreadIndex() const {
+ const ThreadSpec *thread_spec =
+ GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec)
+ ->GetThreadSpecNoCreate();
+ if (thread_spec)
+ return thread_spec->GetIndex();
+ else
+ return 0;
+}
+
+void BreakpointLocation::SetThreadName(const char *thread_name) {
+ if (thread_name != nullptr)
+ GetLocationOptions()->GetThreadSpec()->SetName(thread_name);
+ else {
+ // If we're resetting this to an invalid thread id, then don't make an
+ // options pointer just to do that.
+ if (m_options_up != nullptr)
+ m_options_up->GetThreadSpec()->SetName(thread_name);
+ }
+ SendBreakpointLocationChangedEvent(eBreakpointEventTypeThreadChanged);
+}
+
+const char *BreakpointLocation::GetThreadName() const {
+ const ThreadSpec *thread_spec =
+ GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec)
+ ->GetThreadSpecNoCreate();
+ if (thread_spec)
+ return thread_spec->GetName();
+ else
+ return nullptr;
+}
+
+void BreakpointLocation::SetQueueName(const char *queue_name) {
+ if (queue_name != nullptr)
+ GetLocationOptions()->GetThreadSpec()->SetQueueName(queue_name);
+ else {
+ // If we're resetting this to an invalid thread id, then don't make an
+ // options pointer just to do that.
+ if (m_options_up != nullptr)
+ m_options_up->GetThreadSpec()->SetQueueName(queue_name);
+ }
+ SendBreakpointLocationChangedEvent(eBreakpointEventTypeThreadChanged);
+}
+
+const char *BreakpointLocation::GetQueueName() const {
+ const ThreadSpec *thread_spec =
+ GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec)
+ ->GetThreadSpecNoCreate();
+ if (thread_spec)
+ return thread_spec->GetQueueName();
+ else
+ return nullptr;
+}
+
+bool BreakpointLocation::InvokeCallback(StoppointCallbackContext *context) {
+ if (m_options_up != nullptr && m_options_up->HasCallback())
+ return m_options_up->InvokeCallback(context, m_owner.GetID(), GetID());
+ else
+ return m_owner.InvokeCallback(context, GetID());
+}
+
+void BreakpointLocation::SetCallback(BreakpointHitCallback callback,
+ void *baton, bool is_synchronous) {
+ // The default "Baton" class will keep a copy of "baton" and won't free or
+ // delete it when it goes goes out of scope.
+ GetLocationOptions()->SetCallback(
+ callback, std::make_shared<UntypedBaton>(baton), is_synchronous);
+ SendBreakpointLocationChangedEvent(eBreakpointEventTypeCommandChanged);
+}
+
+void BreakpointLocation::SetCallback(BreakpointHitCallback callback,
+ const BatonSP &baton_sp,
+ bool is_synchronous) {
+ GetLocationOptions()->SetCallback(callback, baton_sp, is_synchronous);
+ SendBreakpointLocationChangedEvent(eBreakpointEventTypeCommandChanged);
+}
+
+void BreakpointLocation::ClearCallback() {
+ GetLocationOptions()->ClearCallback();
+}
+
+void BreakpointLocation::SetCondition(const char *condition) {
+ GetLocationOptions()->SetCondition(condition);
+ SendBreakpointLocationChangedEvent(eBreakpointEventTypeConditionChanged);
+}
+
+const char *BreakpointLocation::GetConditionText(size_t *hash) const {
+ return GetOptionsSpecifyingKind(BreakpointOptions::eCondition)
+ ->GetConditionText(hash);
+}
+
+bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
+ Status &error) {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS);
+
+ std::lock_guard<std::mutex> guard(m_condition_mutex);
+
+ size_t condition_hash;
+ const char *condition_text = GetConditionText(&condition_hash);
+
+ if (!condition_text) {
+ m_user_expression_sp.reset();
+ return false;
+ }
+
+ error.Clear();
+
+ DiagnosticManager diagnostics;
+
+ if (condition_hash != m_condition_hash || !m_user_expression_sp ||
+ !m_user_expression_sp->MatchesContext(exe_ctx)) {
+ LanguageType language = eLanguageTypeUnknown;
+ // See if we can figure out the language from the frame, otherwise use the
+ // default language:
+ CompileUnit *comp_unit = m_address.CalculateSymbolContextCompileUnit();
+ if (comp_unit)
+ language = comp_unit->GetLanguage();
+
+ m_user_expression_sp.reset(GetTarget().GetUserExpressionForLanguage(
+ condition_text, llvm::StringRef(), language, Expression::eResultTypeAny,
+ EvaluateExpressionOptions(), nullptr, error));
+ if (error.Fail()) {
+ LLDB_LOGF(log, "Error getting condition expression: %s.",
+ error.AsCString());
+ m_user_expression_sp.reset();
+ return true;
+ }
+
+ if (!m_user_expression_sp->Parse(diagnostics, exe_ctx,
+ eExecutionPolicyOnlyWhenNeeded, true,
+ false)) {
+ error.SetErrorStringWithFormat(
+ "Couldn't parse conditional expression:\n%s",
+ diagnostics.GetString().c_str());
+ m_user_expression_sp.reset();
+ return true;
+ }
+
+ m_condition_hash = condition_hash;
+ }
+
+ // We need to make sure the user sees any parse errors in their condition, so
+ // we'll hook the constructor errors up to the debugger's Async I/O.
+
+ ValueObjectSP result_value_sp;
+
+ EvaluateExpressionOptions options;
+ options.SetUnwindOnError(true);
+ options.SetIgnoreBreakpoints(true);
+ options.SetTryAllThreads(true);
+ options.SetResultIsInternal(
+ true); // Don't generate a user variable for condition expressions.
+
+ Status expr_error;
+
+ diagnostics.Clear();
+
+ ExpressionVariableSP result_variable_sp;
+
+ ExpressionResults result_code = m_user_expression_sp->Execute(
+ diagnostics, exe_ctx, options, m_user_expression_sp, result_variable_sp);
+
+ bool ret;
+
+ if (result_code == eExpressionCompleted) {
+ if (!result_variable_sp) {
+ error.SetErrorString("Expression did not return a result");
+ return false;
+ }
+
+ result_value_sp = result_variable_sp->GetValueObject();
+
+ if (result_value_sp) {
+ ret = result_value_sp->IsLogicalTrue(error);
+ if (log) {
+ if (error.Success()) {
+ LLDB_LOGF(log, "Condition successfully evaluated, result is %s.\n",
+ ret ? "true" : "false");
+ } else {
+ error.SetErrorString(
+ "Failed to get an integer result from the expression");
+ ret = false;
+ }
+ }
+ } else {
+ ret = false;
+ error.SetErrorString("Failed to get any result from the expression");
+ }
+ } else {
+ ret = false;
+ error.SetErrorStringWithFormat("Couldn't execute expression:\n%s",
+ diagnostics.GetString().c_str());
+ }
+
+ return ret;
+}
+
+uint32_t BreakpointLocation::GetIgnoreCount() {
+ return GetOptionsSpecifyingKind(BreakpointOptions::eIgnoreCount)
+ ->GetIgnoreCount();
+}
+
+void BreakpointLocation::SetIgnoreCount(uint32_t n) {
+ GetLocationOptions()->SetIgnoreCount(n);
+ SendBreakpointLocationChangedEvent(eBreakpointEventTypeIgnoreChanged);
+}
+
+void BreakpointLocation::DecrementIgnoreCount() {
+ if (m_options_up != nullptr) {
+ uint32_t loc_ignore = m_options_up->GetIgnoreCount();
+ if (loc_ignore != 0)
+ m_options_up->SetIgnoreCount(loc_ignore - 1);
+ }
+}
+
+bool BreakpointLocation::IgnoreCountShouldStop() {
+ if (m_options_up != nullptr) {
+ uint32_t loc_ignore = m_options_up->GetIgnoreCount();
+ if (loc_ignore != 0) {
+ m_owner.DecrementIgnoreCount();
+ DecrementIgnoreCount(); // Have to decrement our owners' ignore count,
+ // since it won't get a
+ // chance to.
+ return false;
+ }
+ }
+ return true;
+}
+
+BreakpointOptions *BreakpointLocation::GetLocationOptions() {
+ // If we make the copy we don't copy the callbacks because that is
+ // potentially expensive and we don't want to do that for the simple case
+ // where someone is just disabling the location.
+ if (m_options_up == nullptr)
+ m_options_up.reset(new BreakpointOptions(false));
+
+ return m_options_up.get();
+}
+
+bool BreakpointLocation::ValidForThisThread(Thread *thread) {
+ return thread
+ ->MatchesSpec(GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec)
+ ->GetThreadSpecNoCreate());
+}
+
+// RETURNS - true if we should stop at this breakpoint, false if we
+// should continue. Note, we don't check the thread spec for the breakpoint
+// here, since if the breakpoint is not for this thread, then the event won't
+// even get reported, so the check is redundant.
+
+bool BreakpointLocation::ShouldStop(StoppointCallbackContext *context) {
+ bool should_stop = true;
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS);
+
+ // Do this first, if a location is disabled, it shouldn't increment its hit
+ // count.
+ if (!IsEnabled())
+ return false;
+
+ if (!IgnoreCountShouldStop())
+ return false;
+
+ if (!m_owner.IgnoreCountShouldStop())
+ return false;
+
+ // We only run synchronous callbacks in ShouldStop:
+ context->is_synchronous = true;
+ should_stop = InvokeCallback(context);
+
+ if (log) {
+ StreamString s;
+ GetDescription(&s, lldb::eDescriptionLevelVerbose);
+ LLDB_LOGF(log, "Hit breakpoint location: %s, %s.\n", s.GetData(),
+ should_stop ? "stopping" : "continuing");
+ }
+
+ return should_stop;
+}
+
+void BreakpointLocation::BumpHitCount() {
+ if (IsEnabled()) {
+ // Step our hit count, and also step the hit count of the owner.
+ IncrementHitCount();
+ m_owner.IncrementHitCount();
+ }
+}
+
+void BreakpointLocation::UndoBumpHitCount() {
+ if (IsEnabled()) {
+ // Step our hit count, and also step the hit count of the owner.
+ DecrementHitCount();
+ m_owner.DecrementHitCount();
+ }
+}
+
+bool BreakpointLocation::IsResolved() const {
+ return m_bp_site_sp.get() != nullptr;
+}
+
+lldb::BreakpointSiteSP BreakpointLocation::GetBreakpointSite() const {
+ return m_bp_site_sp;
+}
+
+bool BreakpointLocation::ResolveBreakpointSite() {
+ if (m_bp_site_sp)
+ return true;
+
+ Process *process = m_owner.GetTarget().GetProcessSP().get();
+ if (process == nullptr)
+ return false;
+
+ lldb::break_id_t new_id =
+ process->CreateBreakpointSite(shared_from_this(), m_owner.IsHardware());
+
+ if (new_id == LLDB_INVALID_BREAK_ID) {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS);
+ if (log)
+ log->Warning("Failed to add breakpoint site at 0x%" PRIx64,
+ m_address.GetOpcodeLoadAddress(&m_owner.GetTarget()));
+ }
+
+ return IsResolved();
+}
+
+bool BreakpointLocation::SetBreakpointSite(BreakpointSiteSP &bp_site_sp) {
+ m_bp_site_sp = bp_site_sp;
+ SendBreakpointLocationChangedEvent(eBreakpointEventTypeLocationsResolved);
+ return true;
+}
+
+bool BreakpointLocation::ClearBreakpointSite() {
+ if (m_bp_site_sp.get()) {
+ ProcessSP process_sp(m_owner.GetTarget().GetProcessSP());
+ // If the process exists, get it to remove the owner, it will remove the
+ // physical implementation of the breakpoint as well if there are no more
+ // owners. Otherwise just remove this owner.
+ if (process_sp)
+ process_sp->RemoveOwnerFromBreakpointSite(GetBreakpoint().GetID(),
+ GetID(), m_bp_site_sp);
+ else
+ m_bp_site_sp->RemoveOwner(GetBreakpoint().GetID(), GetID());
+
+ m_bp_site_sp.reset();
+ return true;
+ }
+ return false;
+}
+
+void BreakpointLocation::GetDescription(Stream *s,
+ lldb::DescriptionLevel level) {
+ SymbolContext sc;
+
+ // If the description level is "initial" then the breakpoint is printing out
+ // our initial state, and we should let it decide how it wants to print our
+ // label.
+ if (level != eDescriptionLevelInitial) {
+ s->Indent();
+ BreakpointID::GetCanonicalReference(s, m_owner.GetID(), GetID());
+ }
+
+ if (level == lldb::eDescriptionLevelBrief)
+ return;
+
+ if (level != eDescriptionLevelInitial)
+ s->PutCString(": ");
+
+ if (level == lldb::eDescriptionLevelVerbose)
+ s->IndentMore();
+
+ if (m_address.IsSectionOffset()) {
+ m_address.CalculateSymbolContext(&sc);
+
+ if (level == lldb::eDescriptionLevelFull ||
+ level == eDescriptionLevelInitial) {
+ if (IsReExported())
+ s->PutCString("re-exported target = ");
+ else
+ s->PutCString("where = ");
+ sc.DumpStopContext(s, m_owner.GetTarget().GetProcessSP().get(), m_address,
+ false, true, false, true, true);
+ } else {
+ if (sc.module_sp) {
+ s->EOL();
+ s->Indent("module = ");
+ sc.module_sp->GetFileSpec().Dump(s->AsRawOstream());
+ }
+
+ if (sc.comp_unit != nullptr) {
+ s->EOL();
+ s->Indent("compile unit = ");
+ sc.comp_unit->GetPrimaryFile().GetFilename().Dump(s);
+
+ if (sc.function != nullptr) {
+ s->EOL();
+ s->Indent("function = ");
+ s->PutCString(sc.function->GetName().AsCString("<unknown>"));
+ }
+
+ if (sc.line_entry.line > 0) {
+ s->EOL();
+ s->Indent("location = ");
+ sc.line_entry.DumpStopContext(s, true);
+ }
+
+ } else {
+ // If we don't have a comp unit, see if we have a symbol we can print.
+ if (sc.symbol) {
+ s->EOL();
+ if (IsReExported())
+ s->Indent("re-exported target = ");
+ else
+ s->Indent("symbol = ");
+ s->PutCString(sc.symbol->GetName().AsCString("<unknown>"));
+ }
+ }
+ }
+ }
+
+ if (level == lldb::eDescriptionLevelVerbose) {
+ s->EOL();
+ s->Indent();
+ }
+
+ if (m_address.IsSectionOffset() &&
+ (level == eDescriptionLevelFull || level == eDescriptionLevelInitial))
+ s->Printf(", ");
+ s->Printf("address = ");
+
+ ExecutionContextScope *exe_scope = nullptr;
+ Target *target = &m_owner.GetTarget();
+ if (target)
+ exe_scope = target->GetProcessSP().get();
+ if (exe_scope == nullptr)
+ exe_scope = target;
+
+ if (level == eDescriptionLevelInitial)
+ m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress,
+ Address::DumpStyleFileAddress);
+ else
+ m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress,
+ Address::DumpStyleModuleWithFileAddress);
+
+ if (IsIndirect() && m_bp_site_sp) {
+ Address resolved_address;
+ resolved_address.SetLoadAddress(m_bp_site_sp->GetLoadAddress(), target);
+ Symbol *resolved_symbol = resolved_address.CalculateSymbolContextSymbol();
+ if (resolved_symbol) {
+ if (level == eDescriptionLevelFull || level == eDescriptionLevelInitial)
+ s->Printf(", ");
+ else if (level == lldb::eDescriptionLevelVerbose) {
+ s->EOL();
+ s->Indent();
+ }
+ s->Printf("indirect target = %s",
+ resolved_symbol->GetName().GetCString());
+ }
+ }
+
+ if (level == lldb::eDescriptionLevelVerbose) {
+ s->EOL();
+ s->Indent();
+ s->Printf("resolved = %s\n", IsResolved() ? "true" : "false");
+
+ s->Indent();
+ s->Printf("hit count = %-4u\n", GetHitCount());
+
+ if (m_options_up) {
+ s->Indent();
+ m_options_up->GetDescription(s, level);
+ s->EOL();
+ }
+ s->IndentLess();
+ } else if (level != eDescriptionLevelInitial) {
+ s->Printf(", %sresolved, hit count = %u ", (IsResolved() ? "" : "un"),
+ GetHitCount());
+ if (m_options_up) {
+ m_options_up->GetDescription(s, level);
+ }
+ }
+}
+
+void BreakpointLocation::Dump(Stream *s) const {
+ if (s == nullptr)
+ return;
+
+ lldb::tid_t tid = GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec)
+ ->GetThreadSpecNoCreate()->GetTID();
+ s->Printf("BreakpointLocation %u: tid = %4.4" PRIx64
+ " load addr = 0x%8.8" PRIx64 " state = %s type = %s breakpoint "
+ "hw_index = %i hit_count = %-4u ignore_count = %-4u",
+ GetID(), tid,
+ (uint64_t)m_address.GetOpcodeLoadAddress(&m_owner.GetTarget()),
+ (m_options_up ? m_options_up->IsEnabled() : m_owner.IsEnabled())
+ ? "enabled "
+ : "disabled",
+ IsHardware() ? "hardware" : "software", GetHardwareIndex(),
+ GetHitCount(),
+ GetOptionsSpecifyingKind(BreakpointOptions::eIgnoreCount)
+ ->GetIgnoreCount());
+}
+
+void BreakpointLocation::SendBreakpointLocationChangedEvent(
+ lldb::BreakpointEventType eventKind) {
+ if (!m_being_created && !m_owner.IsInternal() &&
+ m_owner.GetTarget().EventTypeHasListeners(
+ Target::eBroadcastBitBreakpointChanged)) {
+ Breakpoint::BreakpointEventData *data = new Breakpoint::BreakpointEventData(
+ eventKind, m_owner.shared_from_this());
+ data->GetBreakpointLocationCollection().Add(shared_from_this());
+ m_owner.GetTarget().BroadcastEvent(Target::eBroadcastBitBreakpointChanged,
+ data);
+ }
+}
+
+void BreakpointLocation::SwapLocation(BreakpointLocationSP swap_from) {
+ m_address = swap_from->m_address;
+ m_should_resolve_indirect_functions =
+ swap_from->m_should_resolve_indirect_functions;
+ m_is_reexported = swap_from->m_is_reexported;
+ m_is_indirect = swap_from->m_is_indirect;
+ m_user_expression_sp.reset();
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointLocationCollection.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointLocationCollection.cpp
new file mode 100644
index 00000000000..76084adbd2a
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointLocationCollection.cpp
@@ -0,0 +1,187 @@
+//===-- BreakpointLocationCollection.cpp ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointLocationCollection.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadSpec.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// BreakpointLocationCollection constructor
+BreakpointLocationCollection::BreakpointLocationCollection()
+ : m_break_loc_collection(), m_collection_mutex() {}
+
+// Destructor
+BreakpointLocationCollection::~BreakpointLocationCollection() {}
+
+void BreakpointLocationCollection::Add(const BreakpointLocationSP &bp_loc) {
+ std::lock_guard<std::mutex> guard(m_collection_mutex);
+ BreakpointLocationSP old_bp_loc =
+ FindByIDPair(bp_loc->GetBreakpoint().GetID(), bp_loc->GetID());
+ if (!old_bp_loc.get())
+ m_break_loc_collection.push_back(bp_loc);
+}
+
+bool BreakpointLocationCollection::Remove(lldb::break_id_t bp_id,
+ lldb::break_id_t bp_loc_id) {
+ std::lock_guard<std::mutex> guard(m_collection_mutex);
+ collection::iterator pos = GetIDPairIterator(bp_id, bp_loc_id); // Predicate
+ if (pos != m_break_loc_collection.end()) {
+ m_break_loc_collection.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+class BreakpointIDPairMatches {
+public:
+ BreakpointIDPairMatches(lldb::break_id_t break_id,
+ lldb::break_id_t break_loc_id)
+ : m_break_id(break_id), m_break_loc_id(break_loc_id) {}
+
+ bool operator()(const BreakpointLocationSP &bp_loc) const {
+ return m_break_id == bp_loc->GetBreakpoint().GetID() &&
+ m_break_loc_id == bp_loc->GetID();
+ }
+
+private:
+ const lldb::break_id_t m_break_id;
+ const lldb::break_id_t m_break_loc_id;
+};
+
+BreakpointLocationCollection::collection::iterator
+BreakpointLocationCollection::GetIDPairIterator(lldb::break_id_t break_id,
+ lldb::break_id_t break_loc_id) {
+ return std::find_if(
+ m_break_loc_collection.begin(),
+ m_break_loc_collection.end(), // Search full range
+ BreakpointIDPairMatches(break_id, break_loc_id)); // Predicate
+}
+
+BreakpointLocationCollection::collection::const_iterator
+BreakpointLocationCollection::GetIDPairConstIterator(
+ lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const {
+ return std::find_if(
+ m_break_loc_collection.begin(),
+ m_break_loc_collection.end(), // Search full range
+ BreakpointIDPairMatches(break_id, break_loc_id)); // Predicate
+}
+
+BreakpointLocationSP
+BreakpointLocationCollection::FindByIDPair(lldb::break_id_t break_id,
+ lldb::break_id_t break_loc_id) {
+ BreakpointLocationSP stop_sp;
+ collection::iterator pos = GetIDPairIterator(break_id, break_loc_id);
+ if (pos != m_break_loc_collection.end())
+ stop_sp = *pos;
+
+ return stop_sp;
+}
+
+const BreakpointLocationSP BreakpointLocationCollection::FindByIDPair(
+ lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const {
+ BreakpointLocationSP stop_sp;
+ collection::const_iterator pos =
+ GetIDPairConstIterator(break_id, break_loc_id);
+ if (pos != m_break_loc_collection.end())
+ stop_sp = *pos;
+
+ return stop_sp;
+}
+
+BreakpointLocationSP BreakpointLocationCollection::GetByIndex(size_t i) {
+ std::lock_guard<std::mutex> guard(m_collection_mutex);
+ BreakpointLocationSP stop_sp;
+ if (i < m_break_loc_collection.size())
+ stop_sp = m_break_loc_collection[i];
+
+ return stop_sp;
+}
+
+const BreakpointLocationSP
+BreakpointLocationCollection::GetByIndex(size_t i) const {
+ std::lock_guard<std::mutex> guard(m_collection_mutex);
+ BreakpointLocationSP stop_sp;
+ if (i < m_break_loc_collection.size())
+ stop_sp = m_break_loc_collection[i];
+
+ return stop_sp;
+}
+
+bool BreakpointLocationCollection::ShouldStop(
+ StoppointCallbackContext *context) {
+ bool shouldStop = false;
+ size_t i = 0;
+ size_t prev_size = GetSize();
+ while (i < prev_size) {
+ // ShouldStop can remove the breakpoint from the list
+ if (GetByIndex(i)->ShouldStop(context))
+ shouldStop = true;
+
+ if (prev_size == GetSize())
+ i++;
+ prev_size = GetSize();
+ }
+ return shouldStop;
+}
+
+bool BreakpointLocationCollection::ValidForThisThread(Thread *thread) {
+ std::lock_guard<std::mutex> guard(m_collection_mutex);
+ collection::iterator pos, begin = m_break_loc_collection.begin(),
+ end = m_break_loc_collection.end();
+
+ for (pos = begin; pos != end; ++pos) {
+ if ((*pos)->ValidForThisThread(thread))
+ return true;
+ }
+ return false;
+}
+
+bool BreakpointLocationCollection::IsInternal() const {
+ std::lock_guard<std::mutex> guard(m_collection_mutex);
+ collection::const_iterator pos, begin = m_break_loc_collection.begin(),
+ end = m_break_loc_collection.end();
+
+ bool is_internal = true;
+
+ for (pos = begin; pos != end; ++pos) {
+ if (!(*pos)->GetBreakpoint().IsInternal()) {
+ is_internal = false;
+ break;
+ }
+ }
+ return is_internal;
+}
+
+void BreakpointLocationCollection::GetDescription(
+ Stream *s, lldb::DescriptionLevel level) {
+ std::lock_guard<std::mutex> guard(m_collection_mutex);
+ collection::iterator pos, begin = m_break_loc_collection.begin(),
+ end = m_break_loc_collection.end();
+
+ for (pos = begin; pos != end; ++pos) {
+ if (pos != begin)
+ s->PutChar(' ');
+ (*pos)->GetDescription(s, level);
+ }
+}
+
+BreakpointLocationCollection &BreakpointLocationCollection::operator=(
+ const BreakpointLocationCollection &rhs) {
+ if (this != &rhs) {
+ std::lock(m_collection_mutex, rhs.m_collection_mutex);
+ std::lock_guard<std::mutex> lhs_guard(m_collection_mutex, std::adopt_lock);
+ std::lock_guard<std::mutex> rhs_guard(rhs.m_collection_mutex, std::adopt_lock);
+ m_break_loc_collection = rhs.m_break_loc_collection;
+ }
+ return *this;
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointLocationList.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointLocationList.cpp
new file mode 100644
index 00000000000..ee586127ee7
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointLocationList.cpp
@@ -0,0 +1,312 @@
+//===-- BreakpointLocationList.cpp ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointLocationList.h"
+
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/ArchSpec.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointLocationList::BreakpointLocationList(Breakpoint &owner)
+ : m_owner(owner), m_locations(), m_address_to_location(), m_mutex(),
+ m_next_id(0), m_new_location_recorder(nullptr) {}
+
+BreakpointLocationList::~BreakpointLocationList() = default;
+
+BreakpointLocationSP
+BreakpointLocationList::Create(const Address &addr,
+ bool resolve_indirect_symbols) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ // The location ID is just the size of the location list + 1
+ lldb::break_id_t bp_loc_id = ++m_next_id;
+ BreakpointLocationSP bp_loc_sp(
+ new BreakpointLocation(bp_loc_id, m_owner, addr, LLDB_INVALID_THREAD_ID,
+ m_owner.IsHardware(), resolve_indirect_symbols));
+ m_locations.push_back(bp_loc_sp);
+ m_address_to_location[addr] = bp_loc_sp;
+ return bp_loc_sp;
+}
+
+bool BreakpointLocationList::ShouldStop(StoppointCallbackContext *context,
+ lldb::break_id_t break_id) {
+ BreakpointLocationSP bp = FindByID(break_id);
+ if (bp) {
+ // Let the BreakpointLocation decide if it should stop here (could not have
+ // reached it's target hit count yet, or it could have a callback that
+ // decided it shouldn't stop (shared library loads/unloads).
+ return bp->ShouldStop(context);
+ }
+ // We should stop here since this BreakpointLocation isn't valid anymore or
+ // it doesn't exist.
+ return true;
+}
+
+lldb::break_id_t BreakpointLocationList::FindIDByAddress(const Address &addr) {
+ BreakpointLocationSP bp_loc_sp = FindByAddress(addr);
+ if (bp_loc_sp) {
+ return bp_loc_sp->GetID();
+ }
+ return LLDB_INVALID_BREAK_ID;
+}
+
+static bool Compare(BreakpointLocationSP lhs, lldb::break_id_t val) {
+ return lhs->GetID() < val;
+}
+
+BreakpointLocationSP
+BreakpointLocationList::FindByID(lldb::break_id_t break_id) const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ collection::const_iterator end = m_locations.end();
+ collection::const_iterator pos =
+ std::lower_bound(m_locations.begin(), end, break_id, Compare);
+ if (pos != end && (*pos)->GetID() == break_id)
+ return *(pos);
+ else
+ return BreakpointLocationSP();
+}
+
+size_t BreakpointLocationList::FindInModule(
+ Module *module, BreakpointLocationCollection &bp_loc_list) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ const size_t orig_size = bp_loc_list.GetSize();
+ collection::iterator pos, end = m_locations.end();
+
+ for (pos = m_locations.begin(); pos != end; ++pos) {
+ BreakpointLocationSP break_loc = (*pos);
+ SectionSP section_sp(break_loc->GetAddress().GetSection());
+ if (section_sp && section_sp->GetModule().get() == module) {
+ bp_loc_list.Add(break_loc);
+ }
+ }
+ return bp_loc_list.GetSize() - orig_size;
+}
+
+const BreakpointLocationSP
+BreakpointLocationList::FindByAddress(const Address &addr) const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ BreakpointLocationSP bp_loc_sp;
+ if (!m_locations.empty()) {
+ Address so_addr;
+
+ if (addr.IsSectionOffset()) {
+ so_addr = addr;
+ } else {
+ // Try and resolve as a load address if possible.
+ m_owner.GetTarget().GetSectionLoadList().ResolveLoadAddress(
+ addr.GetOffset(), so_addr);
+ if (!so_addr.IsValid()) {
+ // The address didn't resolve, so just set to passed in addr.
+ so_addr = addr;
+ }
+ }
+
+ addr_map::const_iterator pos = m_address_to_location.find(so_addr);
+ if (pos != m_address_to_location.end())
+ bp_loc_sp = pos->second;
+ }
+
+ return bp_loc_sp;
+}
+
+void BreakpointLocationList::Dump(Stream *s) const {
+ s->Printf("%p: ", static_cast<const void *>(this));
+ // s->Indent();
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ s->Printf("BreakpointLocationList with %" PRIu64 " BreakpointLocations:\n",
+ (uint64_t)m_locations.size());
+ s->IndentMore();
+ collection::const_iterator pos, end = m_locations.end();
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ (*pos)->Dump(s);
+ s->IndentLess();
+}
+
+BreakpointLocationSP BreakpointLocationList::GetByIndex(size_t i) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ BreakpointLocationSP bp_loc_sp;
+ if (i < m_locations.size())
+ bp_loc_sp = m_locations[i];
+
+ return bp_loc_sp;
+}
+
+const BreakpointLocationSP BreakpointLocationList::GetByIndex(size_t i) const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ BreakpointLocationSP bp_loc_sp;
+ if (i < m_locations.size())
+ bp_loc_sp = m_locations[i];
+
+ return bp_loc_sp;
+}
+
+void BreakpointLocationList::ClearAllBreakpointSites() {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ collection::iterator pos, end = m_locations.end();
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ (*pos)->ClearBreakpointSite();
+}
+
+void BreakpointLocationList::ResolveAllBreakpointSites() {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ collection::iterator pos, end = m_locations.end();
+
+ for (pos = m_locations.begin(); pos != end; ++pos) {
+ if ((*pos)->IsEnabled())
+ (*pos)->ResolveBreakpointSite();
+ }
+}
+
+uint32_t BreakpointLocationList::GetHitCount() const {
+ uint32_t hit_count = 0;
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ collection::const_iterator pos, end = m_locations.end();
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ hit_count += (*pos)->GetHitCount();
+ return hit_count;
+}
+
+size_t BreakpointLocationList::GetNumResolvedLocations() const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ size_t resolve_count = 0;
+ collection::const_iterator pos, end = m_locations.end();
+ for (pos = m_locations.begin(); pos != end; ++pos) {
+ if ((*pos)->IsResolved())
+ ++resolve_count;
+ }
+ return resolve_count;
+}
+
+void BreakpointLocationList::GetDescription(Stream *s,
+ lldb::DescriptionLevel level) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ collection::iterator pos, end = m_locations.end();
+
+ for (pos = m_locations.begin(); pos != end; ++pos) {
+ s->Printf(" ");
+ (*pos)->GetDescription(s, level);
+ }
+}
+
+BreakpointLocationSP BreakpointLocationList::AddLocation(
+ const Address &addr, bool resolve_indirect_symbols, bool *new_location) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+
+ if (new_location)
+ *new_location = false;
+ BreakpointLocationSP bp_loc_sp(FindByAddress(addr));
+ if (!bp_loc_sp) {
+ bp_loc_sp = Create(addr, resolve_indirect_symbols);
+ if (bp_loc_sp) {
+ bp_loc_sp->ResolveBreakpointSite();
+
+ if (new_location)
+ *new_location = true;
+ if (m_new_location_recorder) {
+ m_new_location_recorder->Add(bp_loc_sp);
+ }
+ }
+ }
+ return bp_loc_sp;
+}
+
+void BreakpointLocationList::SwapLocation(
+ BreakpointLocationSP to_location_sp,
+ BreakpointLocationSP from_location_sp) {
+ if (!from_location_sp || !to_location_sp)
+ return;
+
+ m_address_to_location.erase(to_location_sp->GetAddress());
+ to_location_sp->SwapLocation(from_location_sp);
+ RemoveLocation(from_location_sp);
+ m_address_to_location[to_location_sp->GetAddress()] = to_location_sp;
+ to_location_sp->ResolveBreakpointSite();
+}
+
+bool BreakpointLocationList::RemoveLocation(
+ const lldb::BreakpointLocationSP &bp_loc_sp) {
+ if (bp_loc_sp) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+
+ m_address_to_location.erase(bp_loc_sp->GetAddress());
+
+ size_t num_locations = m_locations.size();
+ for (size_t idx = 0; idx < num_locations; idx++) {
+ if (m_locations[idx].get() == bp_loc_sp.get()) {
+ RemoveLocationByIndex(idx);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void BreakpointLocationList::RemoveLocationByIndex(size_t idx) {
+ assert (idx < m_locations.size());
+ m_address_to_location.erase(m_locations[idx]->GetAddress());
+ m_locations.erase(m_locations.begin() + idx);
+}
+
+void BreakpointLocationList::RemoveInvalidLocations(const ArchSpec &arch) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ size_t idx = 0;
+ // Don't cache m_location.size() as it will change since we might remove
+ // locations from our vector...
+ while (idx < m_locations.size()) {
+ BreakpointLocation *bp_loc = m_locations[idx].get();
+ if (bp_loc->GetAddress().SectionWasDeleted()) {
+ // Section was deleted which means this breakpoint comes from a module
+ // that is no longer valid, so we should remove it.
+ RemoveLocationByIndex(idx);
+ continue;
+ }
+ if (arch.IsValid()) {
+ ModuleSP module_sp(bp_loc->GetAddress().GetModule());
+ if (module_sp) {
+ if (!arch.IsCompatibleMatch(module_sp->GetArchitecture())) {
+ // The breakpoint was in a module whose architecture is no longer
+ // compatible with "arch", so we need to remove it
+ RemoveLocationByIndex(idx);
+ continue;
+ }
+ }
+ }
+ // Only increment the index if we didn't remove the locations at index
+ // "idx"
+ ++idx;
+ }
+}
+
+void BreakpointLocationList::StartRecordingNewLocations(
+ BreakpointLocationCollection &new_locations) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ assert(m_new_location_recorder == nullptr);
+ m_new_location_recorder = &new_locations;
+}
+
+void BreakpointLocationList::StopRecordingNewLocations() {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ m_new_location_recorder = nullptr;
+}
+
+void BreakpointLocationList::Compact() {
+ lldb::break_id_t highest_id = 0;
+
+ for (BreakpointLocationSP loc_sp : m_locations) {
+ lldb::break_id_t cur_id = loc_sp->GetID();
+ if (cur_id > highest_id)
+ highest_id = cur_id;
+ }
+ m_next_id = highest_id;
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointName.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointName.cpp
new file mode 100644
index 00000000000..749fa86bca9
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointName.cpp
@@ -0,0 +1,86 @@
+//===-- BreakpointName.cpp --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Casting.h"
+
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointOptions.h"
+#include "lldb/Breakpoint/BreakpointLocationCollection.h"
+#include "lldb/Breakpoint/BreakpointResolver.h"
+#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const Flags::ValueType BreakpointName::Permissions::permissions_mask
+ [BreakpointName::Permissions::PermissionKinds::allPerms + 1] = {
+ (1u << 0),
+ (1u << 1),
+ (1u << 2),
+ (0x5u)
+};
+
+BreakpointName::BreakpointName(ConstString name, const Breakpoint &bkpt,
+ const char *help) :
+ m_name(name), m_options(bkpt.GetOptions())
+{
+ SetHelp(help);
+}
+
+bool BreakpointName::Permissions::GetDescription(Stream *s,
+ lldb::DescriptionLevel level) {
+ if (!AnySet())
+ return false;
+ s->IndentMore();
+ s->Indent();
+ if (IsSet(listPerm))
+ s->Printf("list: %s", GetAllowList() ? "allowed" : "disallowed");
+
+ if (IsSet(disablePerm))
+ s->Printf("disable: %s", GetAllowDisable() ? "allowed" : "disallowed");
+
+ if (IsSet(deletePerm))
+ s->Printf("delete: %s", GetAllowDelete() ? "allowed" : "disallowed");
+ s->IndentLess();
+ return true;
+}
+
+bool BreakpointName::GetDescription(Stream *s, lldb::DescriptionLevel level) {
+ bool printed_any = false;
+ if (!m_help.empty())
+ s->Printf("Help: %s\n", m_help.c_str());
+
+ if (GetOptions().AnySet())
+ {
+ s->PutCString("Options: \n");
+ s->IndentMore();
+ s->Indent();
+ GetOptions().GetDescription(s, level);
+ printed_any = true;
+ s->IndentLess();
+ }
+ if (GetPermissions().AnySet())
+ {
+ s->PutCString("Permissions: \n");
+ s->IndentMore();
+ s->Indent();
+ GetPermissions().GetDescription(s, level);
+ printed_any = true;
+ s->IndentLess();
+ }
+ return printed_any;
+}
+
+void BreakpointName::ConfigureBreakpoint(lldb::BreakpointSP bp_sp)
+{
+ bp_sp->GetOptions()->CopyOverSetOptions(GetOptions());
+ bp_sp->GetPermissions().MergeInto(GetPermissions());
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointOptions.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointOptions.cpp
new file mode 100644
index 00000000000..8fd16f420c0
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointOptions.cpp
@@ -0,0 +1,673 @@
+//===-- BreakpointOptions.cpp -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointOptions.h"
+
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char
+ *BreakpointOptions::CommandData::g_option_names[static_cast<uint32_t>(
+ BreakpointOptions::CommandData::OptionNames::LastOptionName)]{
+ "UserSource", "ScriptSource", "StopOnError"};
+
+StructuredData::ObjectSP
+BreakpointOptions::CommandData::SerializeToStructuredData() {
+ size_t num_strings = user_source.GetSize();
+ if (num_strings == 0 && script_source.empty()) {
+ // We shouldn't serialize commands if there aren't any, return an empty sp
+ // to indicate this.
+ return StructuredData::ObjectSP();
+ }
+
+ StructuredData::DictionarySP options_dict_sp(
+ new StructuredData::Dictionary());
+ options_dict_sp->AddBooleanItem(GetKey(OptionNames::StopOnError),
+ stop_on_error);
+
+ StructuredData::ArraySP user_source_sp(new StructuredData::Array());
+ for (size_t i = 0; i < num_strings; i++) {
+ StructuredData::StringSP item_sp(
+ new StructuredData::String(user_source[i]));
+ user_source_sp->AddItem(item_sp);
+ options_dict_sp->AddItem(GetKey(OptionNames::UserSource), user_source_sp);
+ }
+
+ options_dict_sp->AddStringItem(
+ GetKey(OptionNames::Interpreter),
+ ScriptInterpreter::LanguageToString(interpreter));
+ return options_dict_sp;
+}
+
+std::unique_ptr<BreakpointOptions::CommandData>
+BreakpointOptions::CommandData::CreateFromStructuredData(
+ const StructuredData::Dictionary &options_dict, Status &error) {
+ std::unique_ptr<CommandData> data_up(new CommandData());
+ bool found_something = false;
+
+ bool success = options_dict.GetValueForKeyAsBoolean(
+ GetKey(OptionNames::StopOnError), data_up->stop_on_error);
+
+ if (success)
+ found_something = true;
+
+ llvm::StringRef interpreter_str;
+ ScriptLanguage interp_language;
+ success = options_dict.GetValueForKeyAsString(
+ GetKey(OptionNames::Interpreter), interpreter_str);
+
+ if (!success) {
+ error.SetErrorString("Missing command language value.");
+ return data_up;
+ }
+
+ found_something = true;
+ interp_language = ScriptInterpreter::StringToLanguage(interpreter_str);
+ if (interp_language == eScriptLanguageUnknown) {
+ error.SetErrorStringWithFormatv("Unknown breakpoint command language: {0}.",
+ interpreter_str);
+ return data_up;
+ }
+ data_up->interpreter = interp_language;
+
+ StructuredData::Array *user_source;
+ success = options_dict.GetValueForKeyAsArray(GetKey(OptionNames::UserSource),
+ user_source);
+ if (success) {
+ found_something = true;
+ size_t num_elems = user_source->GetSize();
+ for (size_t i = 0; i < num_elems; i++) {
+ llvm::StringRef elem_string;
+ success = user_source->GetItemAtIndexAsString(i, elem_string);
+ if (success)
+ data_up->user_source.AppendString(elem_string);
+ }
+ }
+
+ if (found_something)
+ return data_up;
+ else
+ return std::unique_ptr<BreakpointOptions::CommandData>();
+}
+
+const char *BreakpointOptions::g_option_names[(
+ size_t)BreakpointOptions::OptionNames::LastOptionName]{
+ "ConditionText", "IgnoreCount",
+ "EnabledState", "OneShotState", "AutoContinue"};
+
+bool BreakpointOptions::NullCallback(void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id) {
+ return true;
+}
+
+// BreakpointOptions constructor
+BreakpointOptions::BreakpointOptions(bool all_flags_set)
+ : m_callback(BreakpointOptions::NullCallback), m_callback_baton_sp(),
+ m_baton_is_command_baton(false), m_callback_is_synchronous(false),
+ m_enabled(true), m_one_shot(false), m_ignore_count(0), m_thread_spec_up(),
+ m_condition_text(), m_condition_text_hash(0), m_auto_continue(false),
+ m_set_flags(0) {
+ if (all_flags_set)
+ m_set_flags.Set(~((Flags::ValueType)0));
+}
+
+BreakpointOptions::BreakpointOptions(const char *condition, bool enabled,
+ int32_t ignore, bool one_shot,
+ bool auto_continue)
+ : m_callback(nullptr), m_baton_is_command_baton(false),
+ m_callback_is_synchronous(false), m_enabled(enabled),
+ m_one_shot(one_shot), m_ignore_count(ignore),
+ m_condition_text_hash(0), m_auto_continue(auto_continue)
+{
+ m_set_flags.Set(eEnabled | eIgnoreCount | eOneShot
+ | eAutoContinue);
+ if (condition && *condition != '\0') {
+ SetCondition(condition);
+ }
+}
+
+// BreakpointOptions copy constructor
+BreakpointOptions::BreakpointOptions(const BreakpointOptions &rhs)
+ : m_callback(rhs.m_callback), m_callback_baton_sp(rhs.m_callback_baton_sp),
+ m_baton_is_command_baton(rhs.m_baton_is_command_baton),
+ m_callback_is_synchronous(rhs.m_callback_is_synchronous),
+ m_enabled(rhs.m_enabled), m_one_shot(rhs.m_one_shot),
+ m_ignore_count(rhs.m_ignore_count), m_thread_spec_up(),
+ m_auto_continue(rhs.m_auto_continue), m_set_flags(rhs.m_set_flags) {
+ if (rhs.m_thread_spec_up != nullptr)
+ m_thread_spec_up.reset(new ThreadSpec(*rhs.m_thread_spec_up));
+ m_condition_text = rhs.m_condition_text;
+ m_condition_text_hash = rhs.m_condition_text_hash;
+}
+
+// BreakpointOptions assignment operator
+const BreakpointOptions &BreakpointOptions::
+operator=(const BreakpointOptions &rhs) {
+ m_callback = rhs.m_callback;
+ m_callback_baton_sp = rhs.m_callback_baton_sp;
+ m_baton_is_command_baton = rhs.m_baton_is_command_baton;
+ m_callback_is_synchronous = rhs.m_callback_is_synchronous;
+ m_enabled = rhs.m_enabled;
+ m_one_shot = rhs.m_one_shot;
+ m_ignore_count = rhs.m_ignore_count;
+ if (rhs.m_thread_spec_up != nullptr)
+ m_thread_spec_up.reset(new ThreadSpec(*rhs.m_thread_spec_up));
+ m_condition_text = rhs.m_condition_text;
+ m_condition_text_hash = rhs.m_condition_text_hash;
+ m_auto_continue = rhs.m_auto_continue;
+ m_set_flags = rhs.m_set_flags;
+ return *this;
+}
+
+void BreakpointOptions::CopyOverSetOptions(const BreakpointOptions &incoming)
+{
+ if (incoming.m_set_flags.Test(eEnabled))
+ {
+ m_enabled = incoming.m_enabled;
+ m_set_flags.Set(eEnabled);
+ }
+ if (incoming.m_set_flags.Test(eOneShot))
+ {
+ m_one_shot = incoming.m_one_shot;
+ m_set_flags.Set(eOneShot);
+ }
+ if (incoming.m_set_flags.Test(eCallback))
+ {
+ m_callback = incoming.m_callback;
+ m_callback_baton_sp = incoming.m_callback_baton_sp;
+ m_callback_is_synchronous = incoming.m_callback_is_synchronous;
+ m_baton_is_command_baton = incoming.m_baton_is_command_baton;
+ m_set_flags.Set(eCallback);
+ }
+ if (incoming.m_set_flags.Test(eIgnoreCount))
+ {
+ m_ignore_count = incoming.m_ignore_count;
+ m_set_flags.Set(eIgnoreCount);
+ }
+ if (incoming.m_set_flags.Test(eCondition))
+ {
+ // If we're copying over an empty condition, mark it as unset.
+ if (incoming.m_condition_text.empty()) {
+ m_condition_text.clear();
+ m_condition_text_hash = 0;
+ m_set_flags.Clear(eCondition);
+ } else {
+ m_condition_text = incoming.m_condition_text;
+ m_condition_text_hash = incoming.m_condition_text_hash;
+ m_set_flags.Set(eCondition);
+ }
+ }
+ if (incoming.m_set_flags.Test(eAutoContinue))
+ {
+ m_auto_continue = incoming.m_auto_continue;
+ m_set_flags.Set(eAutoContinue);
+ }
+ if (incoming.m_set_flags.Test(eThreadSpec) && incoming.m_thread_spec_up) {
+ if (!m_thread_spec_up)
+ m_thread_spec_up.reset(new ThreadSpec(*incoming.m_thread_spec_up));
+ else
+ *m_thread_spec_up = *incoming.m_thread_spec_up;
+ m_set_flags.Set(eThreadSpec);
+ }
+}
+
+// Destructor
+BreakpointOptions::~BreakpointOptions() = default;
+
+std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData(
+ Target &target, const StructuredData::Dictionary &options_dict,
+ Status &error) {
+ bool enabled = true;
+ bool one_shot = false;
+ bool auto_continue = false;
+ int32_t ignore_count = 0;
+ llvm::StringRef condition_ref("");
+ Flags set_options;
+
+ const char *key = GetKey(OptionNames::EnabledState);
+ bool success;
+ if (key && options_dict.HasKey(key)) {
+ success = options_dict.GetValueForKeyAsBoolean(key, enabled);
+ if (!success) {
+ error.SetErrorStringWithFormat("%s key is not a boolean.", key);
+ return nullptr;
+ }
+ set_options.Set(eEnabled);
+ }
+
+ key = GetKey(OptionNames::OneShotState);
+ if (key && options_dict.HasKey(key)) {
+ success = options_dict.GetValueForKeyAsBoolean(key, one_shot);
+ if (!success) {
+ error.SetErrorStringWithFormat("%s key is not a boolean.", key);
+ return nullptr;
+ }
+ set_options.Set(eOneShot);
+ }
+
+ key = GetKey(OptionNames::AutoContinue);
+ if (key && options_dict.HasKey(key)) {
+ success = options_dict.GetValueForKeyAsBoolean(key, auto_continue);
+ if (!success) {
+ error.SetErrorStringWithFormat("%s key is not a boolean.", key);
+ return nullptr;
+ }
+ set_options.Set(eAutoContinue);
+ }
+
+ key = GetKey(OptionNames::IgnoreCount);
+ if (key && options_dict.HasKey(key)) {
+ success = options_dict.GetValueForKeyAsInteger(key, ignore_count);
+ if (!success) {
+ error.SetErrorStringWithFormat("%s key is not an integer.", key);
+ return nullptr;
+ }
+ set_options.Set(eIgnoreCount);
+ }
+
+ key = GetKey(OptionNames::ConditionText);
+ if (key && options_dict.HasKey(key)) {
+ success = options_dict.GetValueForKeyAsString(key, condition_ref);
+ if (!success) {
+ error.SetErrorStringWithFormat("%s key is not an string.", key);
+ return nullptr;
+ }
+ set_options.Set(eCondition);
+ }
+
+ std::unique_ptr<CommandData> cmd_data_up;
+ StructuredData::Dictionary *cmds_dict;
+ success = options_dict.GetValueForKeyAsDictionary(
+ CommandData::GetSerializationKey(), cmds_dict);
+ if (success && cmds_dict) {
+ Status cmds_error;
+ cmd_data_up = CommandData::CreateFromStructuredData(*cmds_dict, cmds_error);
+ if (cmds_error.Fail()) {
+ error.SetErrorStringWithFormat(
+ "Failed to deserialize breakpoint command options: %s.",
+ cmds_error.AsCString());
+ return nullptr;
+ }
+ }
+
+ auto bp_options = std::make_unique<BreakpointOptions>(
+ condition_ref.str().c_str(), enabled,
+ ignore_count, one_shot, auto_continue);
+ if (cmd_data_up) {
+ if (cmd_data_up->interpreter == eScriptLanguageNone)
+ bp_options->SetCommandDataCallback(cmd_data_up);
+ else {
+ ScriptInterpreter *interp = target.GetDebugger().GetScriptInterpreter();
+ if (!interp) {
+ error.SetErrorStringWithFormat(
+ "Can't set script commands - no script interpreter");
+ return nullptr;
+ }
+ if (interp->GetLanguage() != cmd_data_up->interpreter) {
+ error.SetErrorStringWithFormat(
+ "Current script language doesn't match breakpoint's language: %s",
+ ScriptInterpreter::LanguageToString(cmd_data_up->interpreter)
+ .c_str());
+ return nullptr;
+ }
+ Status script_error;
+ script_error =
+ interp->SetBreakpointCommandCallback(bp_options.get(), cmd_data_up);
+ if (script_error.Fail()) {
+ error.SetErrorStringWithFormat("Error generating script callback: %s.",
+ error.AsCString());
+ return nullptr;
+ }
+ }
+ }
+
+ StructuredData::Dictionary *thread_spec_dict;
+ success = options_dict.GetValueForKeyAsDictionary(
+ ThreadSpec::GetSerializationKey(), thread_spec_dict);
+ if (success) {
+ Status thread_spec_error;
+ std::unique_ptr<ThreadSpec> thread_spec_up =
+ ThreadSpec::CreateFromStructuredData(*thread_spec_dict,
+ thread_spec_error);
+ if (thread_spec_error.Fail()) {
+ error.SetErrorStringWithFormat(
+ "Failed to deserialize breakpoint thread spec options: %s.",
+ thread_spec_error.AsCString());
+ return nullptr;
+ }
+ bp_options->SetThreadSpec(thread_spec_up);
+ }
+ return bp_options;
+}
+
+StructuredData::ObjectSP BreakpointOptions::SerializeToStructuredData() {
+ StructuredData::DictionarySP options_dict_sp(
+ new StructuredData::Dictionary());
+ if (m_set_flags.Test(eEnabled))
+ options_dict_sp->AddBooleanItem(GetKey(OptionNames::EnabledState),
+ m_enabled);
+ if (m_set_flags.Test(eOneShot))
+ options_dict_sp->AddBooleanItem(GetKey(OptionNames::OneShotState),
+ m_one_shot);
+ if (m_set_flags.Test(eAutoContinue))
+ options_dict_sp->AddBooleanItem(GetKey(OptionNames::AutoContinue),
+ m_auto_continue);
+ if (m_set_flags.Test(eIgnoreCount))
+ options_dict_sp->AddIntegerItem(GetKey(OptionNames::IgnoreCount),
+ m_ignore_count);
+ if (m_set_flags.Test(eCondition))
+ options_dict_sp->AddStringItem(GetKey(OptionNames::ConditionText),
+ m_condition_text);
+
+ if (m_set_flags.Test(eCallback) && m_baton_is_command_baton) {
+ auto cmd_baton =
+ std::static_pointer_cast<CommandBaton>(m_callback_baton_sp);
+ StructuredData::ObjectSP commands_sp =
+ cmd_baton->getItem()->SerializeToStructuredData();
+ if (commands_sp) {
+ options_dict_sp->AddItem(
+ BreakpointOptions::CommandData::GetSerializationKey(), commands_sp);
+ }
+ }
+ if (m_set_flags.Test(eThreadSpec) && m_thread_spec_up) {
+ StructuredData::ObjectSP thread_spec_sp =
+ m_thread_spec_up->SerializeToStructuredData();
+ options_dict_sp->AddItem(ThreadSpec::GetSerializationKey(), thread_spec_sp);
+ }
+
+ return options_dict_sp;
+}
+
+// Callbacks
+void BreakpointOptions::SetCallback(BreakpointHitCallback callback,
+ const lldb::BatonSP &callback_baton_sp,
+ bool callback_is_synchronous) {
+ // FIXME: This seems unsafe. If BatonSP actually *is* a CommandBaton, but
+ // in a shared_ptr<Baton> instead of a shared_ptr<CommandBaton>, then we will
+ // set m_baton_is_command_baton to false, which is incorrect. One possible
+ // solution is to make the base Baton class provide a method such as:
+ // virtual StringRef getBatonId() const { return ""; }
+ // and have CommandBaton override this to return something unique, and then
+ // check for it here. Another option might be to make Baton using the llvm
+ // casting infrastructure, so that we could write something like:
+ // if (llvm::isa<CommandBaton>(callback_baton_sp))
+ // at relevant callsites instead of storing a boolean.
+ m_callback_is_synchronous = callback_is_synchronous;
+ m_callback = callback;
+ m_callback_baton_sp = callback_baton_sp;
+ m_baton_is_command_baton = false;
+ m_set_flags.Set(eCallback);
+}
+
+void BreakpointOptions::SetCallback(
+ BreakpointHitCallback callback,
+ const BreakpointOptions::CommandBatonSP &callback_baton_sp,
+ bool callback_is_synchronous) {
+ m_callback_is_synchronous = callback_is_synchronous;
+ m_callback = callback;
+ m_callback_baton_sp = callback_baton_sp;
+ m_baton_is_command_baton = true;
+ m_set_flags.Set(eCallback);
+}
+
+void BreakpointOptions::ClearCallback() {
+ m_callback = BreakpointOptions::NullCallback;
+ m_callback_is_synchronous = false;
+ m_callback_baton_sp.reset();
+ m_baton_is_command_baton = false;
+ m_set_flags.Clear(eCallback);
+}
+
+Baton *BreakpointOptions::GetBaton() { return m_callback_baton_sp.get(); }
+
+const Baton *BreakpointOptions::GetBaton() const {
+ return m_callback_baton_sp.get();
+}
+
+bool BreakpointOptions::InvokeCallback(StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id) {
+ if (m_callback) {
+ if (context->is_synchronous == IsCallbackSynchronous()) {
+ return m_callback(m_callback_baton_sp ? m_callback_baton_sp->data()
+ : nullptr,
+ context, break_id, break_loc_id);
+ } else if (IsCallbackSynchronous()) {
+ // If a synchronous callback is called at async time, it should not say
+ // to stop.
+ return false;
+ }
+ }
+ return true;
+}
+
+bool BreakpointOptions::HasCallback() const {
+ return m_callback != BreakpointOptions::NullCallback;
+}
+
+bool BreakpointOptions::GetCommandLineCallbacks(StringList &command_list) {
+ if (!HasCallback())
+ return false;
+ if (!m_baton_is_command_baton)
+ return false;
+
+ auto cmd_baton = std::static_pointer_cast<CommandBaton>(m_callback_baton_sp);
+ CommandData *data = cmd_baton->getItem();
+ if (!data)
+ return false;
+ command_list = data->user_source;
+ return true;
+}
+
+void BreakpointOptions::SetCondition(const char *condition) {
+ if (!condition || condition[0] == '\0') {
+ condition = "";
+ m_set_flags.Clear(eCondition);
+ }
+ else
+ m_set_flags.Set(eCondition);
+
+ m_condition_text.assign(condition);
+ std::hash<std::string> hasher;
+ m_condition_text_hash = hasher(m_condition_text);
+}
+
+const char *BreakpointOptions::GetConditionText(size_t *hash) const {
+ if (!m_condition_text.empty()) {
+ if (hash)
+ *hash = m_condition_text_hash;
+
+ return m_condition_text.c_str();
+ } else {
+ return nullptr;
+ }
+}
+
+const ThreadSpec *BreakpointOptions::GetThreadSpecNoCreate() const {
+ return m_thread_spec_up.get();
+}
+
+ThreadSpec *BreakpointOptions::GetThreadSpec() {
+ if (m_thread_spec_up == nullptr) {
+ m_set_flags.Set(eThreadSpec);
+ m_thread_spec_up.reset(new ThreadSpec());
+ }
+
+ return m_thread_spec_up.get();
+}
+
+void BreakpointOptions::SetThreadID(lldb::tid_t thread_id) {
+ GetThreadSpec()->SetTID(thread_id);
+ m_set_flags.Set(eThreadSpec);
+}
+
+void BreakpointOptions::SetThreadSpec(
+ std::unique_ptr<ThreadSpec> &thread_spec_up) {
+ m_thread_spec_up = std::move(thread_spec_up);
+ m_set_flags.Set(eThreadSpec);
+}
+
+void BreakpointOptions::GetDescription(Stream *s,
+ lldb::DescriptionLevel level) const {
+ // Figure out if there are any options not at their default value, and only
+ // print anything if there are:
+
+ if (m_ignore_count != 0 || !m_enabled || m_one_shot || m_auto_continue ||
+ (GetThreadSpecNoCreate() != nullptr &&
+ GetThreadSpecNoCreate()->HasSpecification())) {
+ if (level == lldb::eDescriptionLevelVerbose) {
+ s->EOL();
+ s->IndentMore();
+ s->Indent();
+ s->PutCString("Breakpoint Options:\n");
+ s->IndentMore();
+ s->Indent();
+ } else
+ s->PutCString(" Options: ");
+
+ if (m_ignore_count > 0)
+ s->Printf("ignore: %d ", m_ignore_count);
+ s->Printf("%sabled ", m_enabled ? "en" : "dis");
+
+ if (m_one_shot)
+ s->Printf("one-shot ");
+
+ if (m_auto_continue)
+ s->Printf("auto-continue ");
+
+ if (m_thread_spec_up)
+ m_thread_spec_up->GetDescription(s, level);
+
+ if (level == lldb::eDescriptionLevelFull) {
+ s->IndentLess();
+ s->IndentMore();
+ }
+ }
+
+ if (m_callback_baton_sp.get()) {
+ if (level != eDescriptionLevelBrief) {
+ s->EOL();
+ m_callback_baton_sp->GetDescription(s->AsRawOstream(), level,
+ s->GetIndentLevel());
+ }
+ }
+ if (!m_condition_text.empty()) {
+ if (level != eDescriptionLevelBrief) {
+ s->EOL();
+ s->Printf("Condition: %s\n", m_condition_text.c_str());
+ }
+ }
+}
+
+void BreakpointOptions::CommandBaton::GetDescription(
+ llvm::raw_ostream &s, lldb::DescriptionLevel level,
+ unsigned indentation) const {
+ const CommandData *data = getItem();
+
+ if (level == eDescriptionLevelBrief) {
+ s << ", commands = "
+ << ((data && data->user_source.GetSize() > 0) ? "yes" : "no");
+ return;
+ }
+
+ indentation += 2;
+ s.indent(indentation);
+ s << "Breakpoint commands";
+ if (data->interpreter != eScriptLanguageNone)
+ s << llvm::formatv(" ({0}):\n",
+ ScriptInterpreter::LanguageToString(data->interpreter));
+ else
+ s << ":\n";
+
+ indentation += 2;
+ if (data && data->user_source.GetSize() > 0) {
+ for (llvm::StringRef str : data->user_source) {
+ s.indent(indentation);
+ s << str << "\n";
+ }
+ } else
+ s << "No commands.\n";
+}
+
+void BreakpointOptions::SetCommandDataCallback(
+ std::unique_ptr<CommandData> &cmd_data) {
+ cmd_data->interpreter = eScriptLanguageNone;
+ auto baton_sp = std::make_shared<CommandBaton>(std::move(cmd_data));
+ SetCallback(BreakpointOptions::BreakpointOptionsCallbackFunction, baton_sp);
+ m_set_flags.Set(eCallback);
+}
+
+bool BreakpointOptions::BreakpointOptionsCallbackFunction(
+ void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id) {
+ bool ret_value = true;
+ if (baton == nullptr)
+ return true;
+
+ CommandData *data = (CommandData *)baton;
+ StringList &commands = data->user_source;
+
+ if (commands.GetSize() > 0) {
+ ExecutionContext exe_ctx(context->exe_ctx_ref);
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target) {
+ CommandReturnObject result;
+ Debugger &debugger = target->GetDebugger();
+ // Rig up the results secondary output stream to the debugger's, so the
+ // output will come out synchronously if the debugger is set up that way.
+
+ StreamSP output_stream(debugger.GetAsyncOutputStream());
+ StreamSP error_stream(debugger.GetAsyncErrorStream());
+ result.SetImmediateOutputStream(output_stream);
+ result.SetImmediateErrorStream(error_stream);
+
+ CommandInterpreterRunOptions options;
+ options.SetStopOnContinue(true);
+ options.SetStopOnError(data->stop_on_error);
+ options.SetEchoCommands(true);
+ options.SetPrintResults(true);
+ options.SetPrintErrors(true);
+ options.SetAddToHistory(false);
+
+ debugger.GetCommandInterpreter().HandleCommands(commands, &exe_ctx,
+ options, result);
+ result.GetImmediateOutputStream()->Flush();
+ result.GetImmediateErrorStream()->Flush();
+ }
+ }
+ return ret_value;
+}
+
+void BreakpointOptions::Clear()
+{
+ m_set_flags.Clear();
+ m_thread_spec_up.release();
+ m_one_shot = false;
+ m_ignore_count = 0;
+ m_auto_continue = false;
+ m_callback = nullptr;
+ m_callback_baton_sp.reset();
+ m_baton_is_command_baton = false;
+ m_callback_is_synchronous = false;
+ m_enabled = false;
+ m_condition_text.clear();
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointPrecondition.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointPrecondition.cpp
new file mode 100644
index 00000000000..a387c75c835
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointPrecondition.cpp
@@ -0,0 +1,26 @@
+//===-- BreakpointPrecondition.cpp ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointPrecondition.h"
+#include "lldb/Utility/Status.h"
+
+using namespace lldb_private;
+
+bool BreakpointPrecondition::EvaluatePrecondition(
+ StoppointCallbackContext &context) {
+ return false;
+}
+
+void BreakpointPrecondition::GetDescription(Stream &stream,
+ lldb::DescriptionLevel level) {}
+
+Status BreakpointPrecondition::ConfigurePrecondition(Args &args) {
+ Status error;
+ error.SetErrorString("Base breakpoint precondition has no options.");
+ return error;
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointResolver.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolver.cpp
new file mode 100644
index 00000000000..e0a4e6ac671
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolver.cpp
@@ -0,0 +1,352 @@
+//===-- BreakpointResolver.cpp ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointResolver.h"
+
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+// Have to include the other breakpoint resolver types here so the static
+// create from StructuredData can call them.
+#include "lldb/Breakpoint/BreakpointResolverAddress.h"
+#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
+#include "lldb/Breakpoint/BreakpointResolverFileRegex.h"
+#include "lldb/Breakpoint/BreakpointResolverName.h"
+#include "lldb/Breakpoint/BreakpointResolverScripted.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/SearchFilter.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+// BreakpointResolver:
+const char *BreakpointResolver::g_ty_to_name[] = {"FileAndLine", "Address",
+ "SymbolName", "SourceRegex",
+ "Python", "Exception",
+ "Unknown"};
+
+const char *BreakpointResolver::g_option_names[static_cast<uint32_t>(
+ BreakpointResolver::OptionNames::LastOptionName)] = {
+ "AddressOffset", "Exact", "FileName", "Inlines", "Language",
+ "LineNumber", "Column", "ModuleName", "NameMask", "Offset",
+ "PythonClass", "Regex", "ScriptArgs", "SectionName", "SearchDepth",
+ "SkipPrologue", "SymbolNames"};
+
+const char *BreakpointResolver::ResolverTyToName(enum ResolverTy type) {
+ if (type > LastKnownResolverType)
+ return g_ty_to_name[UnknownResolver];
+
+ return g_ty_to_name[type];
+}
+
+BreakpointResolver::ResolverTy
+BreakpointResolver::NameToResolverTy(llvm::StringRef name) {
+ for (size_t i = 0; i < LastKnownResolverType; i++) {
+ if (name == g_ty_to_name[i])
+ return (ResolverTy)i;
+ }
+ return UnknownResolver;
+}
+
+BreakpointResolver::BreakpointResolver(Breakpoint *bkpt,
+ const unsigned char resolverTy,
+ lldb::addr_t offset)
+ : m_breakpoint(bkpt), m_offset(offset), SubclassID(resolverTy) {}
+
+BreakpointResolver::~BreakpointResolver() {}
+
+BreakpointResolverSP BreakpointResolver::CreateFromStructuredData(
+ const StructuredData::Dictionary &resolver_dict, Status &error) {
+ BreakpointResolverSP result_sp;
+ if (!resolver_dict.IsValid()) {
+ error.SetErrorString("Can't deserialize from an invalid data object.");
+ return result_sp;
+ }
+
+ llvm::StringRef subclass_name;
+
+ bool success = resolver_dict.GetValueForKeyAsString(
+ GetSerializationSubclassKey(), subclass_name);
+
+ if (!success) {
+ error.SetErrorStringWithFormat(
+ "Resolver data missing subclass resolver key");
+ return result_sp;
+ }
+
+ ResolverTy resolver_type = NameToResolverTy(subclass_name);
+ if (resolver_type == UnknownResolver) {
+ error.SetErrorStringWithFormatv("Unknown resolver type: {0}.",
+ subclass_name);
+ return result_sp;
+ }
+
+ StructuredData::Dictionary *subclass_options = nullptr;
+ success = resolver_dict.GetValueForKeyAsDictionary(
+ GetSerializationSubclassOptionsKey(), subclass_options);
+ if (!success || !subclass_options || !subclass_options->IsValid()) {
+ error.SetErrorString("Resolver data missing subclass options key.");
+ return result_sp;
+ }
+
+ lldb::addr_t offset;
+ success = subclass_options->GetValueForKeyAsInteger(
+ GetKey(OptionNames::Offset), offset);
+ if (!success) {
+ error.SetErrorString("Resolver data missing offset options key.");
+ return result_sp;
+ }
+
+ BreakpointResolver *resolver;
+
+ switch (resolver_type) {
+ case FileLineResolver:
+ resolver = BreakpointResolverFileLine::CreateFromStructuredData(
+ nullptr, *subclass_options, error);
+ break;
+ case AddressResolver:
+ resolver = BreakpointResolverAddress::CreateFromStructuredData(
+ nullptr, *subclass_options, error);
+ break;
+ case NameResolver:
+ resolver = BreakpointResolverName::CreateFromStructuredData(
+ nullptr, *subclass_options, error);
+ break;
+ case FileRegexResolver:
+ resolver = BreakpointResolverFileRegex::CreateFromStructuredData(
+ nullptr, *subclass_options, error);
+ break;
+ case PythonResolver:
+ resolver = BreakpointResolverScripted::CreateFromStructuredData(
+ nullptr, *subclass_options, error);
+ break;
+ case ExceptionResolver:
+ error.SetErrorString("Exception resolvers are hard.");
+ break;
+ default:
+ llvm_unreachable("Should never get an unresolvable resolver type.");
+ }
+
+ if (!error.Success()) {
+ return result_sp;
+ } else {
+ // Add on the global offset option:
+ resolver->SetOffset(offset);
+ return BreakpointResolverSP(resolver);
+ }
+}
+
+StructuredData::DictionarySP BreakpointResolver::WrapOptionsDict(
+ StructuredData::DictionarySP options_dict_sp) {
+ if (!options_dict_sp || !options_dict_sp->IsValid())
+ return StructuredData::DictionarySP();
+
+ StructuredData::DictionarySP type_dict_sp(new StructuredData::Dictionary());
+ type_dict_sp->AddStringItem(GetSerializationSubclassKey(), GetResolverName());
+ type_dict_sp->AddItem(GetSerializationSubclassOptionsKey(), options_dict_sp);
+
+ // Add the m_offset to the dictionary:
+ options_dict_sp->AddIntegerItem(GetKey(OptionNames::Offset), m_offset);
+
+ return type_dict_sp;
+}
+
+void BreakpointResolver::SetBreakpoint(Breakpoint *bkpt) {
+ m_breakpoint = bkpt;
+ NotifyBreakpointSet();
+}
+
+void BreakpointResolver::ResolveBreakpointInModules(SearchFilter &filter,
+ ModuleList &modules) {
+ filter.SearchInModuleList(*this, modules);
+}
+
+void BreakpointResolver::ResolveBreakpoint(SearchFilter &filter) {
+ filter.Search(*this);
+}
+
+namespace {
+struct SourceLoc {
+ uint32_t line = UINT32_MAX;
+ uint32_t column;
+ SourceLoc(uint32_t l, uint32_t c) : line(l), column(c ? c : UINT32_MAX) {}
+ SourceLoc(const SymbolContext &sc)
+ : line(sc.line_entry.line),
+ column(sc.line_entry.column ? sc.line_entry.column : UINT32_MAX) {}
+};
+
+bool operator<(const SourceLoc a, const SourceLoc b) {
+ if (a.line < b.line)
+ return true;
+ if (a.line > b.line)
+ return false;
+ uint32_t a_col = a.column ? a.column : UINT32_MAX;
+ uint32_t b_col = b.column ? b.column : UINT32_MAX;
+ return a_col < b_col;
+}
+} // namespace
+
+void BreakpointResolver::SetSCMatchesByLine(SearchFilter &filter,
+ SymbolContextList &sc_list,
+ bool skip_prologue,
+ llvm::StringRef log_ident,
+ uint32_t line, uint32_t column) {
+ llvm::SmallVector<SymbolContext, 16> all_scs;
+ for (uint32_t i = 0; i < sc_list.GetSize(); ++i)
+ all_scs.push_back(sc_list[i]);
+
+ while (all_scs.size()) {
+ uint32_t closest_line = UINT32_MAX;
+
+ // Move all the elements with a matching file spec to the end.
+ auto &match = all_scs[0];
+ auto worklist_begin = std::partition(
+ all_scs.begin(), all_scs.end(), [&](const SymbolContext &sc) {
+ if (sc.line_entry.file == match.line_entry.file ||
+ sc.line_entry.original_file == match.line_entry.original_file) {
+ // When a match is found, keep track of the smallest line number.
+ closest_line = std::min(closest_line, sc.line_entry.line);
+ return false;
+ }
+ return true;
+ });
+
+ // (worklist_begin, worklist_end) now contains all entries for one filespec.
+ auto worklist_end = all_scs.end();
+
+ if (column) {
+ // If a column was requested, do a more precise match and only
+ // return the first location that comes after or at the
+ // requested location.
+ SourceLoc requested(line, column);
+ // First, filter out all entries left of the requested column.
+ worklist_end = std::remove_if(
+ worklist_begin, worklist_end,
+ [&](const SymbolContext &sc) { return SourceLoc(sc) < requested; });
+ // Sort the remaining entries by (line, column).
+ llvm::sort(worklist_begin, worklist_end,
+ [](const SymbolContext &a, const SymbolContext &b) {
+ return SourceLoc(a) < SourceLoc(b);
+ });
+
+ // Filter out all locations with a source location after the closest match.
+ if (worklist_begin != worklist_end)
+ worklist_end = std::remove_if(
+ worklist_begin, worklist_end, [&](const SymbolContext &sc) {
+ return SourceLoc(*worklist_begin) < SourceLoc(sc);
+ });
+ } else {
+ // Remove all entries with a larger line number.
+ // ResolveSymbolContext will always return a number that is >=
+ // the line number you pass in. So the smaller line number is
+ // always better.
+ worklist_end = std::remove_if(worklist_begin, worklist_end,
+ [&](const SymbolContext &sc) {
+ return closest_line != sc.line_entry.line;
+ });
+ }
+
+ // Sort by file address.
+ llvm::sort(worklist_begin, worklist_end,
+ [](const SymbolContext &a, const SymbolContext &b) {
+ return a.line_entry.range.GetBaseAddress().GetFileAddress() <
+ b.line_entry.range.GetBaseAddress().GetFileAddress();
+ });
+
+ // Go through and see if there are line table entries that are
+ // contiguous, and if so keep only the first of the contiguous range.
+ // We do this by picking the first location in each lexical block.
+ llvm::SmallDenseSet<Block *, 8> blocks_with_breakpoints;
+ for (auto first = worklist_begin; first != worklist_end; ++first) {
+ assert(!blocks_with_breakpoints.count(first->block));
+ blocks_with_breakpoints.insert(first->block);
+ worklist_end =
+ std::remove_if(std::next(first), worklist_end,
+ [&](const SymbolContext &sc) {
+ return blocks_with_breakpoints.count(sc.block);
+ });
+ }
+
+ // Make breakpoints out of the closest line number match.
+ for (auto &sc : llvm::make_range(worklist_begin, worklist_end))
+ AddLocation(filter, sc, skip_prologue, log_ident);
+
+ // Remove all contexts processed by this iteration.
+ all_scs.erase(worklist_begin, all_scs.end());
+ }
+}
+
+void BreakpointResolver::AddLocation(SearchFilter &filter,
+ const SymbolContext &sc,
+ bool skip_prologue,
+ llvm::StringRef log_ident) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+ Address line_start = sc.line_entry.range.GetBaseAddress();
+ if (!line_start.IsValid()) {
+ LLDB_LOGF(log,
+ "error: Unable to set breakpoint %s at file address "
+ "0x%" PRIx64 "\n",
+ log_ident.str().c_str(), line_start.GetFileAddress());
+ return;
+ }
+
+ if (!filter.AddressPasses(line_start)) {
+ LLDB_LOGF(log,
+ "Breakpoint %s at file address 0x%" PRIx64
+ " didn't pass the filter.\n",
+ log_ident.str().c_str(), line_start.GetFileAddress());
+ }
+
+ // If the line number is before the prologue end, move it there...
+ bool skipped_prologue = false;
+ if (skip_prologue && sc.function) {
+ Address prologue_addr(sc.function->GetAddressRange().GetBaseAddress());
+ if (prologue_addr.IsValid() && (line_start == prologue_addr)) {
+ const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
+ if (prologue_byte_size) {
+ prologue_addr.Slide(prologue_byte_size);
+
+ if (filter.AddressPasses(prologue_addr)) {
+ skipped_prologue = true;
+ line_start = prologue_addr;
+ }
+ }
+ }
+ }
+
+ BreakpointLocationSP bp_loc_sp(AddLocation(line_start));
+ if (log && bp_loc_sp && !m_breakpoint->IsInternal()) {
+ StreamString s;
+ bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
+ LLDB_LOGF(log, "Added location (skipped prologue: %s): %s \n",
+ skipped_prologue ? "yes" : "no", s.GetData());
+ }
+}
+
+BreakpointLocationSP BreakpointResolver::AddLocation(Address loc_addr,
+ bool *new_location) {
+ loc_addr.Slide(m_offset);
+ return m_breakpoint->AddLocation(loc_addr, new_location);
+}
+
+void BreakpointResolver::SetOffset(lldb::addr_t offset) {
+ // There may already be an offset, so we are actually adjusting location
+ // addresses by the difference.
+ // lldb::addr_t slide = offset - m_offset;
+ // FIXME: We should go fix up all the already set locations for the new
+ // slide.
+
+ m_offset = offset;
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverAddress.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverAddress.cpp
new file mode 100644
index 00000000000..b98568098b4
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverAddress.cpp
@@ -0,0 +1,184 @@
+//===-- BreakpointResolverAddress.cpp ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointResolverAddress.h"
+
+
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// BreakpointResolverAddress:
+BreakpointResolverAddress::BreakpointResolverAddress(
+ Breakpoint *bkpt, const Address &addr, const FileSpec &module_spec)
+ : BreakpointResolver(bkpt, BreakpointResolver::AddressResolver),
+ m_addr(addr), m_resolved_addr(LLDB_INVALID_ADDRESS),
+ m_module_filespec(module_spec) {}
+
+BreakpointResolverAddress::BreakpointResolverAddress(Breakpoint *bkpt,
+ const Address &addr)
+ : BreakpointResolver(bkpt, BreakpointResolver::AddressResolver),
+ m_addr(addr), m_resolved_addr(LLDB_INVALID_ADDRESS), m_module_filespec() {
+}
+
+BreakpointResolverAddress::~BreakpointResolverAddress() {}
+
+BreakpointResolver *BreakpointResolverAddress::CreateFromStructuredData(
+ Breakpoint *bkpt, const StructuredData::Dictionary &options_dict,
+ Status &error) {
+ llvm::StringRef module_name;
+ lldb::addr_t addr_offset;
+ FileSpec module_filespec;
+ bool success;
+
+ success = options_dict.GetValueForKeyAsInteger(
+ GetKey(OptionNames::AddressOffset), addr_offset);
+ if (!success) {
+ error.SetErrorString("BRFL::CFSD: Couldn't find address offset entry.");
+ return nullptr;
+ }
+ Address address(addr_offset);
+
+ success = options_dict.HasKey(GetKey(OptionNames::ModuleName));
+ if (success) {
+ success = options_dict.GetValueForKeyAsString(
+ GetKey(OptionNames::ModuleName), module_name);
+ if (!success) {
+ error.SetErrorString("BRA::CFSD: Couldn't read module name entry.");
+ return nullptr;
+ }
+ module_filespec.SetFile(module_name, FileSpec::Style::native);
+ }
+ return new BreakpointResolverAddress(bkpt, address, module_filespec);
+}
+
+StructuredData::ObjectSP
+BreakpointResolverAddress::SerializeToStructuredData() {
+ StructuredData::DictionarySP options_dict_sp(
+ new StructuredData::Dictionary());
+ SectionSP section_sp = m_addr.GetSection();
+ if (section_sp) {
+ ModuleSP module_sp = section_sp->GetModule();
+ ConstString module_name;
+ if (module_sp)
+ module_name.SetCString(module_name.GetCString());
+
+ options_dict_sp->AddStringItem(GetKey(OptionNames::ModuleName),
+ module_name.GetCString());
+ options_dict_sp->AddIntegerItem(GetKey(OptionNames::AddressOffset),
+ m_addr.GetOffset());
+ } else {
+ options_dict_sp->AddIntegerItem(GetKey(OptionNames::AddressOffset),
+ m_addr.GetOffset());
+ if (m_module_filespec) {
+ options_dict_sp->AddStringItem(GetKey(OptionNames::ModuleName),
+ m_module_filespec.GetPath());
+ }
+ }
+
+ return WrapOptionsDict(options_dict_sp);
+ return StructuredData::ObjectSP();
+}
+
+void BreakpointResolverAddress::ResolveBreakpoint(SearchFilter &filter) {
+ // If the address is not section relative, then we should not try to re-
+ // resolve it, it is just some random address and we wouldn't know what to do
+ // on reload. But if it is section relative, we need to re-resolve it since
+ // the section it's in may have shifted on re-run.
+ bool re_resolve = false;
+ if (m_addr.GetSection() || m_module_filespec)
+ re_resolve = true;
+ else if (m_breakpoint->GetNumLocations() == 0)
+ re_resolve = true;
+
+ if (re_resolve)
+ BreakpointResolver::ResolveBreakpoint(filter);
+}
+
+void BreakpointResolverAddress::ResolveBreakpointInModules(
+ SearchFilter &filter, ModuleList &modules) {
+ // See comment in ResolveBreakpoint.
+ bool re_resolve = false;
+ if (m_addr.GetSection())
+ re_resolve = true;
+ else if (m_breakpoint->GetNumLocations() == 0)
+ re_resolve = true;
+
+ if (re_resolve)
+ BreakpointResolver::ResolveBreakpointInModules(filter, modules);
+}
+
+Searcher::CallbackReturn BreakpointResolverAddress::SearchCallback(
+ SearchFilter &filter, SymbolContext &context, Address *addr) {
+ assert(m_breakpoint != nullptr);
+
+ if (filter.AddressPasses(m_addr)) {
+ if (m_breakpoint->GetNumLocations() == 0) {
+ // If the address is just an offset, and we're given a module, see if we
+ // can find the appropriate module loaded in the binary, and fix up
+ // m_addr to use that.
+ if (!m_addr.IsSectionOffset() && m_module_filespec) {
+ Target &target = m_breakpoint->GetTarget();
+ ModuleSpec module_spec(m_module_filespec);
+ ModuleSP module_sp = target.GetImages().FindFirstModule(module_spec);
+ if (module_sp) {
+ Address tmp_address;
+ if (module_sp->ResolveFileAddress(m_addr.GetOffset(), tmp_address))
+ m_addr = tmp_address;
+ }
+ }
+
+ m_resolved_addr = m_addr.GetLoadAddress(&m_breakpoint->GetTarget());
+ BreakpointLocationSP bp_loc_sp(AddLocation(m_addr));
+ if (bp_loc_sp && !m_breakpoint->IsInternal()) {
+ StreamString s;
+ bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
+ Log *log(
+ lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+ LLDB_LOGF(log, "Added location: %s\n", s.GetData());
+ }
+ } else {
+ BreakpointLocationSP loc_sp = m_breakpoint->GetLocationAtIndex(0);
+ lldb::addr_t cur_load_location =
+ m_addr.GetLoadAddress(&m_breakpoint->GetTarget());
+ if (cur_load_location != m_resolved_addr) {
+ m_resolved_addr = cur_load_location;
+ loc_sp->ClearBreakpointSite();
+ loc_sp->ResolveBreakpointSite();
+ }
+ }
+ }
+ return Searcher::eCallbackReturnStop;
+}
+
+lldb::SearchDepth BreakpointResolverAddress::GetDepth() {
+ return lldb::eSearchDepthTarget;
+}
+
+void BreakpointResolverAddress::GetDescription(Stream *s) {
+ s->PutCString("address = ");
+ m_addr.Dump(s, m_breakpoint->GetTarget().GetProcessSP().get(),
+ Address::DumpStyleModuleWithFileAddress,
+ Address::DumpStyleLoadAddress);
+}
+
+void BreakpointResolverAddress::Dump(Stream *s) const {}
+
+lldb::BreakpointResolverSP
+BreakpointResolverAddress::CopyForBreakpoint(Breakpoint &breakpoint) {
+ lldb::BreakpointResolverSP ret_sp(
+ new BreakpointResolverAddress(&breakpoint, m_addr));
+ return ret_sp;
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp
new file mode 100644
index 00000000000..2b26f65816b
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp
@@ -0,0 +1,272 @@
+//===-- BreakpointResolverFileLine.cpp --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
+
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// BreakpointResolverFileLine:
+BreakpointResolverFileLine::BreakpointResolverFileLine(
+ Breakpoint *bkpt, const FileSpec &file_spec, uint32_t line_no,
+ uint32_t column, lldb::addr_t offset, bool check_inlines,
+ bool skip_prologue, bool exact_match)
+ : BreakpointResolver(bkpt, BreakpointResolver::FileLineResolver, offset),
+ m_file_spec(file_spec), m_line_number(line_no), m_column(column),
+ m_inlines(check_inlines), m_skip_prologue(skip_prologue),
+ m_exact_match(exact_match) {}
+
+BreakpointResolverFileLine::~BreakpointResolverFileLine() {}
+
+BreakpointResolver *BreakpointResolverFileLine::CreateFromStructuredData(
+ Breakpoint *bkpt, const StructuredData::Dictionary &options_dict,
+ Status &error) {
+ llvm::StringRef filename;
+ uint32_t line_no;
+ uint32_t column;
+ bool check_inlines;
+ bool skip_prologue;
+ bool exact_match;
+ bool success;
+
+ lldb::addr_t offset = 0;
+
+ success = options_dict.GetValueForKeyAsString(GetKey(OptionNames::FileName),
+ filename);
+ if (!success) {
+ error.SetErrorString("BRFL::CFSD: Couldn't find filename entry.");
+ return nullptr;
+ }
+
+ success = options_dict.GetValueForKeyAsInteger(
+ GetKey(OptionNames::LineNumber), line_no);
+ if (!success) {
+ error.SetErrorString("BRFL::CFSD: Couldn't find line number entry.");
+ return nullptr;
+ }
+
+ success =
+ options_dict.GetValueForKeyAsInteger(GetKey(OptionNames::Column), column);
+ if (!success) {
+ // Backwards compatibility.
+ column = 0;
+ }
+
+ success = options_dict.GetValueForKeyAsBoolean(GetKey(OptionNames::Inlines),
+ check_inlines);
+ if (!success) {
+ error.SetErrorString("BRFL::CFSD: Couldn't find check inlines entry.");
+ return nullptr;
+ }
+
+ success = options_dict.GetValueForKeyAsBoolean(
+ GetKey(OptionNames::SkipPrologue), skip_prologue);
+ if (!success) {
+ error.SetErrorString("BRFL::CFSD: Couldn't find skip prologue entry.");
+ return nullptr;
+ }
+
+ success = options_dict.GetValueForKeyAsBoolean(
+ GetKey(OptionNames::ExactMatch), exact_match);
+ if (!success) {
+ error.SetErrorString("BRFL::CFSD: Couldn't find exact match entry.");
+ return nullptr;
+ }
+
+ FileSpec file_spec(filename);
+
+ return new BreakpointResolverFileLine(bkpt, file_spec, line_no, column,
+ offset, check_inlines, skip_prologue,
+ exact_match);
+}
+
+StructuredData::ObjectSP
+BreakpointResolverFileLine::SerializeToStructuredData() {
+ StructuredData::DictionarySP options_dict_sp(
+ new StructuredData::Dictionary());
+
+ options_dict_sp->AddStringItem(GetKey(OptionNames::FileName),
+ m_file_spec.GetPath());
+ options_dict_sp->AddIntegerItem(GetKey(OptionNames::LineNumber),
+ m_line_number);
+ options_dict_sp->AddIntegerItem(GetKey(OptionNames::Column),
+ m_column);
+ options_dict_sp->AddBooleanItem(GetKey(OptionNames::Inlines), m_inlines);
+ options_dict_sp->AddBooleanItem(GetKey(OptionNames::SkipPrologue),
+ m_skip_prologue);
+ options_dict_sp->AddBooleanItem(GetKey(OptionNames::ExactMatch),
+ m_exact_match);
+
+ return WrapOptionsDict(options_dict_sp);
+}
+
+// Filter the symbol context list to remove contexts where the line number was
+// moved into a new function. We do this conservatively, so if e.g. we cannot
+// resolve the function in the context (which can happen in case of line-table-
+// only debug info), we leave the context as is. The trickiest part here is
+// handling inlined functions -- in this case we need to make sure we look at
+// the declaration line of the inlined function, NOT the function it was
+// inlined into.
+void BreakpointResolverFileLine::FilterContexts(SymbolContextList &sc_list,
+ bool is_relative) {
+ if (m_exact_match)
+ return; // Nothing to do. Contexts are precise.
+
+ llvm::StringRef relative_path;
+ if (is_relative)
+ relative_path = m_file_spec.GetDirectory().GetStringRef();
+
+ Log * log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS);
+ for(uint32_t i = 0; i < sc_list.GetSize(); ++i) {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex(i, sc);
+ if (is_relative) {
+ // If the path was relative, make sure any matches match as long as the
+ // relative parts of the path match the path from support files
+ auto sc_dir = sc.line_entry.file.GetDirectory().GetStringRef();
+ if (!sc_dir.endswith(relative_path)) {
+ // We had a relative path specified and the relative directory doesn't
+ // match so remove this one
+ LLDB_LOG(log, "removing not matching relative path {0} since it "
+ "doesn't end with {1}", sc_dir, relative_path);
+ sc_list.RemoveContextAtIndex(i);
+ --i;
+ continue;
+ }
+ }
+
+ if (!sc.block)
+ continue;
+
+ FileSpec file;
+ uint32_t line;
+ const Block *inline_block = sc.block->GetContainingInlinedBlock();
+ if (inline_block) {
+ const Declaration &inline_declaration = inline_block->GetInlinedFunctionInfo()->GetDeclaration();
+ if (!inline_declaration.IsValid())
+ continue;
+ file = inline_declaration.GetFile();
+ line = inline_declaration.GetLine();
+ } else if (sc.function)
+ sc.function->GetStartLineSourceInfo(file, line);
+ else
+ continue;
+
+ if (file != sc.line_entry.file) {
+ LLDB_LOG(log, "unexpected symbol context file {0}", sc.line_entry.file);
+ continue;
+ }
+
+ // Compare the requested line number with the line of the function
+ // declaration. In case of a function declared as:
+ //
+ // int
+ // foo()
+ // {
+ // ...
+ //
+ // the compiler will set the declaration line to the "foo" line, which is
+ // the reason why we have -1 here. This can fail in case of two inline
+ // functions defined back-to-back:
+ //
+ // inline int foo1() { ... }
+ // inline int foo2() { ... }
+ //
+ // but that's the best we can do for now.
+ // One complication, if the line number returned from GetStartLineSourceInfo
+ // is 0, then we can't do this calculation. That can happen if
+ // GetStartLineSourceInfo gets an error, or if the first line number in
+ // the function really is 0 - which happens for some languages.
+ const int decl_line_is_too_late_fudge = 1;
+ if (line && m_line_number < line - decl_line_is_too_late_fudge) {
+ LLDB_LOG(log, "removing symbol context at {0}:{1}", file, line);
+ sc_list.RemoveContextAtIndex(i);
+ --i;
+ }
+ }
+}
+
+Searcher::CallbackReturn BreakpointResolverFileLine::SearchCallback(
+ SearchFilter &filter, SymbolContext &context, Address *addr) {
+ SymbolContextList sc_list;
+
+ assert(m_breakpoint != nullptr);
+
+ // There is a tricky bit here. You can have two compilation units that
+ // #include the same file, and in one of them the function at m_line_number
+ // is used (and so code and a line entry for it is generated) but in the
+ // other it isn't. If we considered the CU's independently, then in the
+ // second inclusion, we'd move the breakpoint to the next function that
+ // actually generated code in the header file. That would end up being
+ // confusing. So instead, we do the CU iterations by hand here, then scan
+ // through the complete list of matches, and figure out the closest line
+ // number match, and only set breakpoints on that match.
+
+ // Note also that if file_spec only had a file name and not a directory,
+ // there may be many different file spec's in the resultant list. The
+ // closest line match for one will not be right for some totally different
+ // file. So we go through the match list and pull out the sets that have the
+ // same file spec in their line_entry and treat each set separately.
+
+ FileSpec search_file_spec = m_file_spec;
+ const bool is_relative = m_file_spec.IsRelative();
+ if (is_relative)
+ search_file_spec.GetDirectory().Clear();
+
+ const size_t num_comp_units = context.module_sp->GetNumCompileUnits();
+ for (size_t i = 0; i < num_comp_units; i++) {
+ CompUnitSP cu_sp(context.module_sp->GetCompileUnitAtIndex(i));
+ if (cu_sp) {
+ if (filter.CompUnitPasses(*cu_sp))
+ cu_sp->ResolveSymbolContext(search_file_spec, m_line_number, m_inlines,
+ m_exact_match, eSymbolContextEverything,
+ sc_list);
+ }
+ }
+
+ FilterContexts(sc_list, is_relative);
+
+ StreamString s;
+ s.Printf("for %s:%d ", m_file_spec.GetFilename().AsCString("<Unknown>"),
+ m_line_number);
+
+ SetSCMatchesByLine(filter, sc_list, m_skip_prologue, s.GetString(),
+ m_line_number, m_column);
+
+ return Searcher::eCallbackReturnContinue;
+}
+
+lldb::SearchDepth BreakpointResolverFileLine::GetDepth() {
+ return lldb::eSearchDepthModule;
+}
+
+void BreakpointResolverFileLine::GetDescription(Stream *s) {
+ s->Printf("file = '%s', line = %u, ", m_file_spec.GetPath().c_str(),
+ m_line_number);
+ if (m_column)
+ s->Printf("column = %u, ", m_column);
+ s->Printf("exact_match = %d", m_exact_match);
+}
+
+void BreakpointResolverFileLine::Dump(Stream *s) const {}
+
+lldb::BreakpointResolverSP
+BreakpointResolverFileLine::CopyForBreakpoint(Breakpoint &breakpoint) {
+ lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileLine(
+ &breakpoint, m_file_spec, m_line_number, m_column, m_offset, m_inlines,
+ m_skip_prologue, m_exact_match));
+
+ return ret_sp;
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp
new file mode 100644
index 00000000000..6b600a7cf12
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp
@@ -0,0 +1,172 @@
+//===-- BreakpointResolverFileRegex.cpp -------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointResolverFileRegex.h"
+
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/SourceManager.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// BreakpointResolverFileRegex:
+BreakpointResolverFileRegex::BreakpointResolverFileRegex(
+ Breakpoint *bkpt, RegularExpression regex,
+ const std::unordered_set<std::string> &func_names, bool exact_match)
+ : BreakpointResolver(bkpt, BreakpointResolver::FileRegexResolver),
+ m_regex(std::move(regex)), m_exact_match(exact_match),
+ m_function_names(func_names) {}
+
+BreakpointResolverFileRegex::~BreakpointResolverFileRegex() {}
+
+BreakpointResolver *BreakpointResolverFileRegex::CreateFromStructuredData(
+ Breakpoint *bkpt, const StructuredData::Dictionary &options_dict,
+ Status &error) {
+ bool success;
+
+ llvm::StringRef regex_string;
+ success = options_dict.GetValueForKeyAsString(
+ GetKey(OptionNames::RegexString), regex_string);
+ if (!success) {
+ error.SetErrorString("BRFR::CFSD: Couldn't find regex entry.");
+ return nullptr;
+ }
+ RegularExpression regex(regex_string);
+
+ bool exact_match;
+ success = options_dict.GetValueForKeyAsBoolean(
+ GetKey(OptionNames::ExactMatch), exact_match);
+ if (!success) {
+ error.SetErrorString("BRFL::CFSD: Couldn't find exact match entry.");
+ return nullptr;
+ }
+
+ // The names array is optional:
+ std::unordered_set<std::string> names_set;
+ StructuredData::Array *names_array;
+ success = options_dict.GetValueForKeyAsArray(
+ GetKey(OptionNames::SymbolNameArray), names_array);
+ if (success && names_array) {
+ size_t num_names = names_array->GetSize();
+ for (size_t i = 0; i < num_names; i++) {
+ llvm::StringRef name;
+ success = names_array->GetItemAtIndexAsString(i, name);
+ if (!success) {
+ error.SetErrorStringWithFormat(
+ "BRFR::CFSD: Malformed element %zu in the names array.", i);
+ return nullptr;
+ }
+ names_set.insert(name);
+ }
+ }
+
+ return new BreakpointResolverFileRegex(bkpt, std::move(regex), names_set,
+ exact_match);
+}
+
+StructuredData::ObjectSP
+BreakpointResolverFileRegex::SerializeToStructuredData() {
+ StructuredData::DictionarySP options_dict_sp(
+ new StructuredData::Dictionary());
+
+ options_dict_sp->AddStringItem(GetKey(OptionNames::RegexString),
+ m_regex.GetText());
+ options_dict_sp->AddBooleanItem(GetKey(OptionNames::ExactMatch),
+ m_exact_match);
+ if (!m_function_names.empty()) {
+ StructuredData::ArraySP names_array_sp(new StructuredData::Array());
+ for (std::string name : m_function_names) {
+ StructuredData::StringSP item(new StructuredData::String(name));
+ names_array_sp->AddItem(item);
+ }
+ options_dict_sp->AddItem(GetKey(OptionNames::LineNumber), names_array_sp);
+ }
+
+ return WrapOptionsDict(options_dict_sp);
+}
+
+Searcher::CallbackReturn BreakpointResolverFileRegex::SearchCallback(
+ SearchFilter &filter, SymbolContext &context, Address *addr) {
+
+ assert(m_breakpoint != nullptr);
+ if (!context.target_sp)
+ return eCallbackReturnContinue;
+
+ CompileUnit *cu = context.comp_unit;
+ FileSpec cu_file_spec = cu->GetPrimaryFile();
+ std::vector<uint32_t> line_matches;
+ context.target_sp->GetSourceManager().FindLinesMatchingRegex(
+ cu_file_spec, m_regex, 1, UINT32_MAX, line_matches);
+
+ uint32_t num_matches = line_matches.size();
+ for (uint32_t i = 0; i < num_matches; i++) {
+ SymbolContextList sc_list;
+ const bool search_inlines = false;
+
+ cu->ResolveSymbolContext(cu_file_spec, line_matches[i], search_inlines,
+ m_exact_match, eSymbolContextEverything, sc_list);
+ // Find all the function names:
+ if (!m_function_names.empty()) {
+ std::vector<size_t> sc_to_remove;
+ for (size_t i = 0; i < sc_list.GetSize(); i++) {
+ SymbolContext sc_ctx;
+ sc_list.GetContextAtIndex(i, sc_ctx);
+ std::string name(
+ sc_ctx
+ .GetFunctionName(
+ Mangled::NamePreference::ePreferDemangledWithoutArguments)
+ .AsCString());
+ if (!m_function_names.count(name)) {
+ sc_to_remove.push_back(i);
+ }
+ }
+
+ if (!sc_to_remove.empty()) {
+ std::vector<size_t>::reverse_iterator iter;
+ std::vector<size_t>::reverse_iterator rend = sc_to_remove.rend();
+ for (iter = sc_to_remove.rbegin(); iter != rend; iter++) {
+ sc_list.RemoveContextAtIndex(*iter);
+ }
+ }
+ }
+
+ const bool skip_prologue = true;
+
+ BreakpointResolver::SetSCMatchesByLine(filter, sc_list, skip_prologue,
+ m_regex.GetText());
+ }
+ assert(m_breakpoint != nullptr);
+
+ return Searcher::eCallbackReturnContinue;
+}
+
+lldb::SearchDepth BreakpointResolverFileRegex::GetDepth() {
+ return lldb::eSearchDepthCompUnit;
+}
+
+void BreakpointResolverFileRegex::GetDescription(Stream *s) {
+ s->Printf("source regex = \"%s\", exact_match = %d",
+ m_regex.GetText().str().c_str(), m_exact_match);
+}
+
+void BreakpointResolverFileRegex::Dump(Stream *s) const {}
+
+lldb::BreakpointResolverSP
+BreakpointResolverFileRegex::CopyForBreakpoint(Breakpoint &breakpoint) {
+ lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileRegex(
+ &breakpoint, m_regex, m_function_names, m_exact_match));
+ return ret_sp;
+}
+
+void BreakpointResolverFileRegex::AddFunctionName(const char *func_name) {
+ m_function_names.insert(func_name);
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverName.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverName.cpp
new file mode 100644
index 00000000000..ba9c88c7eae
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverName.cpp
@@ -0,0 +1,433 @@
+//===-- BreakpointResolverName.cpp ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointResolverName.h"
+
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Architecture.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Language.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointResolverName::BreakpointResolverName(
+ Breakpoint *bkpt, const char *name_cstr, FunctionNameType name_type_mask,
+ LanguageType language, Breakpoint::MatchType type, lldb::addr_t offset,
+ bool skip_prologue)
+ : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset),
+ m_class_name(), m_regex(), m_match_type(type), m_language(language),
+ m_skip_prologue(skip_prologue) {
+ if (m_match_type == Breakpoint::Regexp) {
+ m_regex = RegularExpression(llvm::StringRef::withNullAsEmpty(name_cstr));
+ if (!m_regex.IsValid()) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+
+ if (log)
+ log->Warning("function name regexp: \"%s\" did not compile.",
+ name_cstr);
+ }
+ } else {
+ AddNameLookup(ConstString(name_cstr), name_type_mask);
+ }
+}
+
+BreakpointResolverName::BreakpointResolverName(
+ Breakpoint *bkpt, const char *names[], size_t num_names,
+ FunctionNameType name_type_mask, LanguageType language, lldb::addr_t offset,
+ bool skip_prologue)
+ : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset),
+ m_match_type(Breakpoint::Exact), m_language(language),
+ m_skip_prologue(skip_prologue) {
+ for (size_t i = 0; i < num_names; i++) {
+ AddNameLookup(ConstString(names[i]), name_type_mask);
+ }
+}
+
+BreakpointResolverName::BreakpointResolverName(Breakpoint *bkpt,
+ std::vector<std::string> names,
+ FunctionNameType name_type_mask,
+ LanguageType language,
+ lldb::addr_t offset,
+ bool skip_prologue)
+ : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset),
+ m_match_type(Breakpoint::Exact), m_language(language),
+ m_skip_prologue(skip_prologue) {
+ for (const std::string &name : names) {
+ AddNameLookup(ConstString(name.c_str(), name.size()), name_type_mask);
+ }
+}
+
+BreakpointResolverName::BreakpointResolverName(Breakpoint *bkpt,
+ RegularExpression func_regex,
+ lldb::LanguageType language,
+ lldb::addr_t offset,
+ bool skip_prologue)
+ : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset),
+ m_class_name(nullptr), m_regex(std::move(func_regex)),
+ m_match_type(Breakpoint::Regexp), m_language(language),
+ m_skip_prologue(skip_prologue) {}
+
+BreakpointResolverName::~BreakpointResolverName() = default;
+
+BreakpointResolverName::BreakpointResolverName(
+ const BreakpointResolverName &rhs)
+ : BreakpointResolver(rhs.m_breakpoint, BreakpointResolver::NameResolver,
+ rhs.m_offset),
+ m_lookups(rhs.m_lookups), m_class_name(rhs.m_class_name),
+ m_regex(rhs.m_regex), m_match_type(rhs.m_match_type),
+ m_language(rhs.m_language), m_skip_prologue(rhs.m_skip_prologue) {}
+
+BreakpointResolver *BreakpointResolverName::CreateFromStructuredData(
+ Breakpoint *bkpt, const StructuredData::Dictionary &options_dict,
+ Status &error) {
+ LanguageType language = eLanguageTypeUnknown;
+ llvm::StringRef language_name;
+ bool success = options_dict.GetValueForKeyAsString(
+ GetKey(OptionNames::LanguageName), language_name);
+ if (success) {
+ language = Language::GetLanguageTypeFromString(language_name);
+ if (language == eLanguageTypeUnknown) {
+ error.SetErrorStringWithFormatv("BRN::CFSD: Unknown language: {0}.",
+ language_name);
+ return nullptr;
+ }
+ }
+
+ lldb::addr_t offset = 0;
+ success =
+ options_dict.GetValueForKeyAsInteger(GetKey(OptionNames::Offset), offset);
+ if (!success) {
+ error.SetErrorStringWithFormat("BRN::CFSD: Missing offset entry.");
+ return nullptr;
+ }
+
+ bool skip_prologue;
+ success = options_dict.GetValueForKeyAsBoolean(
+ GetKey(OptionNames::SkipPrologue), skip_prologue);
+ if (!success) {
+ error.SetErrorStringWithFormat("BRN::CFSD: Missing Skip prologue entry.");
+ return nullptr;
+ }
+
+ llvm::StringRef regex_text;
+ success = options_dict.GetValueForKeyAsString(
+ GetKey(OptionNames::RegexString), regex_text);
+ if (success) {
+ return new BreakpointResolverName(bkpt, RegularExpression(regex_text),
+ language, offset, skip_prologue);
+ } else {
+ StructuredData::Array *names_array;
+ success = options_dict.GetValueForKeyAsArray(
+ GetKey(OptionNames::SymbolNameArray), names_array);
+ if (!success) {
+ error.SetErrorStringWithFormat("BRN::CFSD: Missing symbol names entry.");
+ return nullptr;
+ }
+ StructuredData::Array *names_mask_array;
+ success = options_dict.GetValueForKeyAsArray(
+ GetKey(OptionNames::NameMaskArray), names_mask_array);
+ if (!success) {
+ error.SetErrorStringWithFormat(
+ "BRN::CFSD: Missing symbol names mask entry.");
+ return nullptr;
+ }
+
+ size_t num_elem = names_array->GetSize();
+ if (num_elem != names_mask_array->GetSize()) {
+ error.SetErrorString(
+ "BRN::CFSD: names and names mask arrays have different sizes.");
+ return nullptr;
+ }
+
+ if (num_elem == 0) {
+ error.SetErrorString(
+ "BRN::CFSD: no name entry in a breakpoint by name breakpoint.");
+ return nullptr;
+ }
+ std::vector<std::string> names;
+ std::vector<FunctionNameType> name_masks;
+ for (size_t i = 0; i < num_elem; i++) {
+ llvm::StringRef name;
+
+ success = names_array->GetItemAtIndexAsString(i, name);
+ if (!success) {
+ error.SetErrorString("BRN::CFSD: name entry is not a string.");
+ return nullptr;
+ }
+ std::underlying_type<FunctionNameType>::type fnt;
+ success = names_mask_array->GetItemAtIndexAsInteger(i, fnt);
+ if (!success) {
+ error.SetErrorString("BRN::CFSD: name mask entry is not an integer.");
+ return nullptr;
+ }
+ names.push_back(name);
+ name_masks.push_back(static_cast<FunctionNameType>(fnt));
+ }
+
+ BreakpointResolverName *resolver = new BreakpointResolverName(
+ bkpt, names[0].c_str(), name_masks[0], language,
+ Breakpoint::MatchType::Exact, offset, skip_prologue);
+ for (size_t i = 1; i < num_elem; i++) {
+ resolver->AddNameLookup(ConstString(names[i]), name_masks[i]);
+ }
+ return resolver;
+ }
+}
+
+StructuredData::ObjectSP BreakpointResolverName::SerializeToStructuredData() {
+ StructuredData::DictionarySP options_dict_sp(
+ new StructuredData::Dictionary());
+
+ if (m_regex.IsValid()) {
+ options_dict_sp->AddStringItem(GetKey(OptionNames::RegexString),
+ m_regex.GetText());
+ } else {
+ StructuredData::ArraySP names_sp(new StructuredData::Array());
+ StructuredData::ArraySP name_masks_sp(new StructuredData::Array());
+ for (auto lookup : m_lookups) {
+ names_sp->AddItem(StructuredData::StringSP(
+ new StructuredData::String(lookup.GetName().AsCString())));
+ name_masks_sp->AddItem(StructuredData::IntegerSP(
+ new StructuredData::Integer(lookup.GetNameTypeMask())));
+ }
+ options_dict_sp->AddItem(GetKey(OptionNames::SymbolNameArray), names_sp);
+ options_dict_sp->AddItem(GetKey(OptionNames::NameMaskArray), name_masks_sp);
+ }
+ if (m_language != eLanguageTypeUnknown)
+ options_dict_sp->AddStringItem(
+ GetKey(OptionNames::LanguageName),
+ Language::GetNameForLanguageType(m_language));
+ options_dict_sp->AddBooleanItem(GetKey(OptionNames::SkipPrologue),
+ m_skip_prologue);
+
+ return WrapOptionsDict(options_dict_sp);
+}
+
+void BreakpointResolverName::AddNameLookup(ConstString name,
+ FunctionNameType name_type_mask) {
+
+ Module::LookupInfo lookup(name, name_type_mask, m_language);
+ m_lookups.emplace_back(lookup);
+
+ auto add_variant_funcs = [&](Language *lang) {
+ for (ConstString variant_name : lang->GetMethodNameVariants(name)) {
+ Module::LookupInfo variant_lookup(name, name_type_mask,
+ lang->GetLanguageType());
+ variant_lookup.SetLookupName(variant_name);
+ m_lookups.emplace_back(variant_lookup);
+ }
+ return true;
+ };
+
+ if (Language *lang = Language::FindPlugin(m_language)) {
+ add_variant_funcs(lang);
+ } else {
+ // Most likely m_language is eLanguageTypeUnknown. We check each language for
+ // possible variants or more qualified names and create lookups for those as
+ // well.
+ Language::ForEach(add_variant_funcs);
+ }
+}
+
+// FIXME: Right now we look at the module level, and call the module's
+// "FindFunctions".
+// Greg says he will add function tables, maybe at the CompileUnit level to
+// accelerate function lookup. At that point, we should switch the depth to
+// CompileUnit, and look in these tables.
+
+Searcher::CallbackReturn
+BreakpointResolverName::SearchCallback(SearchFilter &filter,
+ SymbolContext &context, Address *addr) {
+ SymbolContextList func_list;
+ // SymbolContextList sym_list;
+
+ uint32_t i;
+ bool new_location;
+ Address break_addr;
+ assert(m_breakpoint != nullptr);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+
+ if (m_class_name) {
+ if (log)
+ log->Warning("Class/method function specification not supported yet.\n");
+ return Searcher::eCallbackReturnStop;
+ }
+ bool filter_by_cu =
+ (filter.GetFilterRequiredItems() & eSymbolContextCompUnit) != 0;
+ bool filter_by_language = (m_language != eLanguageTypeUnknown);
+ const bool include_symbols = !filter_by_cu;
+ const bool include_inlines = true;
+
+ switch (m_match_type) {
+ case Breakpoint::Exact:
+ if (context.module_sp) {
+ for (const auto &lookup : m_lookups) {
+ const size_t start_func_idx = func_list.GetSize();
+ context.module_sp->FindFunctions(
+ lookup.GetLookupName(), nullptr, lookup.GetNameTypeMask(),
+ include_symbols, include_inlines, func_list);
+
+ const size_t end_func_idx = func_list.GetSize();
+
+ if (start_func_idx < end_func_idx)
+ lookup.Prune(func_list, start_func_idx);
+ }
+ }
+ break;
+ case Breakpoint::Regexp:
+ if (context.module_sp) {
+ context.module_sp->FindFunctions(
+ m_regex,
+ !filter_by_cu, // include symbols only if we aren't filtering by CU
+ include_inlines, func_list);
+ }
+ break;
+ case Breakpoint::Glob:
+ if (log)
+ log->Warning("glob is not supported yet.");
+ break;
+ }
+
+ // If the filter specifies a Compilation Unit, remove the ones that don't
+ // pass at this point.
+ if (filter_by_cu || filter_by_language) {
+ uint32_t num_functions = func_list.GetSize();
+
+ for (size_t idx = 0; idx < num_functions; idx++) {
+ bool remove_it = false;
+ SymbolContext sc;
+ func_list.GetContextAtIndex(idx, sc);
+ if (filter_by_cu) {
+ if (!sc.comp_unit || !filter.CompUnitPasses(*sc.comp_unit))
+ remove_it = true;
+ }
+
+ if (filter_by_language) {
+ LanguageType sym_language = sc.GetLanguage();
+ if ((Language::GetPrimaryLanguage(sym_language) !=
+ Language::GetPrimaryLanguage(m_language)) &&
+ (sym_language != eLanguageTypeUnknown)) {
+ remove_it = true;
+ }
+ }
+
+ if (remove_it) {
+ func_list.RemoveContextAtIndex(idx);
+ num_functions--;
+ idx--;
+ }
+ }
+ }
+
+ // Remove any duplicates between the function list and the symbol list
+ SymbolContext sc;
+ if (func_list.GetSize()) {
+ for (i = 0; i < func_list.GetSize(); i++) {
+ if (func_list.GetContextAtIndex(i, sc)) {
+ bool is_reexported = false;
+
+ if (sc.block && sc.block->GetInlinedFunctionInfo()) {
+ if (!sc.block->GetStartAddress(break_addr))
+ break_addr.Clear();
+ } else if (sc.function) {
+ break_addr = sc.function->GetAddressRange().GetBaseAddress();
+ if (m_skip_prologue && break_addr.IsValid()) {
+ const uint32_t prologue_byte_size =
+ sc.function->GetPrologueByteSize();
+ if (prologue_byte_size)
+ break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
+ }
+ } else if (sc.symbol) {
+ if (sc.symbol->GetType() == eSymbolTypeReExported) {
+ const Symbol *actual_symbol =
+ sc.symbol->ResolveReExportedSymbol(m_breakpoint->GetTarget());
+ if (actual_symbol) {
+ is_reexported = true;
+ break_addr = actual_symbol->GetAddress();
+ }
+ } else {
+ break_addr = sc.symbol->GetAddress();
+ }
+
+ if (m_skip_prologue && break_addr.IsValid()) {
+ const uint32_t prologue_byte_size =
+ sc.symbol->GetPrologueByteSize();
+ if (prologue_byte_size)
+ break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
+ else {
+ const Architecture *arch =
+ m_breakpoint->GetTarget().GetArchitecturePlugin();
+ if (arch)
+ arch->AdjustBreakpointAddress(*sc.symbol, break_addr);
+ }
+ }
+ }
+
+ if (break_addr.IsValid()) {
+ if (filter.AddressPasses(break_addr)) {
+ BreakpointLocationSP bp_loc_sp(
+ AddLocation(break_addr, &new_location));
+ bp_loc_sp->SetIsReExported(is_reexported);
+ if (bp_loc_sp && new_location && !m_breakpoint->IsInternal()) {
+ if (log) {
+ StreamString s;
+ bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
+ LLDB_LOGF(log, "Added location: %s\n", s.GetData());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return Searcher::eCallbackReturnContinue;
+}
+
+lldb::SearchDepth BreakpointResolverName::GetDepth() {
+ return lldb::eSearchDepthModule;
+}
+
+void BreakpointResolverName::GetDescription(Stream *s) {
+ if (m_match_type == Breakpoint::Regexp)
+ s->Printf("regex = '%s'", m_regex.GetText().str().c_str());
+ else {
+ size_t num_names = m_lookups.size();
+ if (num_names == 1)
+ s->Printf("name = '%s'", m_lookups[0].GetName().GetCString());
+ else {
+ s->Printf("names = {");
+ for (size_t i = 0; i < num_names; i++) {
+ s->Printf("%s'%s'", (i == 0 ? "" : ", "),
+ m_lookups[i].GetName().GetCString());
+ }
+ s->Printf("}");
+ }
+ }
+ if (m_language != eLanguageTypeUnknown) {
+ s->Printf(", language = %s", Language::GetNameForLanguageType(m_language));
+ }
+}
+
+void BreakpointResolverName::Dump(Stream *s) const {}
+
+lldb::BreakpointResolverSP
+BreakpointResolverName::CopyForBreakpoint(Breakpoint &breakpoint) {
+ lldb::BreakpointResolverSP ret_sp(new BreakpointResolverName(*this));
+ ret_sp->SetBreakpoint(&breakpoint);
+ return ret_sp;
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverScripted.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverScripted.cpp
new file mode 100644
index 00000000000..288fd37c1c7
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverScripted.cpp
@@ -0,0 +1,163 @@
+//===-- BreakpointResolverScripted.cpp ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointResolverScripted.h"
+
+
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StructuredDataImpl.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// BreakpointResolverScripted:
+BreakpointResolverScripted::BreakpointResolverScripted(
+ Breakpoint *bkpt,
+ const llvm::StringRef class_name,
+ lldb::SearchDepth depth,
+ StructuredDataImpl *args_data)
+ : BreakpointResolver(bkpt, BreakpointResolver::PythonResolver),
+ m_class_name(class_name), m_depth(depth), m_args_ptr(args_data) {
+ CreateImplementationIfNeeded();
+}
+
+void BreakpointResolverScripted::CreateImplementationIfNeeded() {
+ if (m_implementation_sp)
+ return;
+
+ if (m_class_name.empty())
+ return;
+
+ if (m_breakpoint) {
+ TargetSP target_sp = m_breakpoint->GetTargetSP();
+ ScriptInterpreter *script_interp = target_sp->GetDebugger()
+ .GetScriptInterpreter();
+ if (!script_interp)
+ return;
+ lldb::BreakpointSP bkpt_sp(m_breakpoint->shared_from_this());
+ m_implementation_sp = script_interp->CreateScriptedBreakpointResolver(
+ m_class_name.c_str(), m_args_ptr, bkpt_sp);
+ }
+}
+
+void BreakpointResolverScripted::NotifyBreakpointSet() {
+ CreateImplementationIfNeeded();
+}
+
+BreakpointResolverScripted::~BreakpointResolverScripted() {}
+
+BreakpointResolver *
+BreakpointResolverScripted::CreateFromStructuredData(
+ Breakpoint *bkpt, const StructuredData::Dictionary &options_dict,
+ Status &error) {
+ llvm::StringRef class_name;
+ bool success;
+
+ success = options_dict.GetValueForKeyAsString(
+ GetKey(OptionNames::PythonClassName), class_name);
+ if (!success) {
+ error.SetErrorString("BRFL::CFSD: Couldn't find class name entry.");
+ return nullptr;
+ }
+ // The Python function will actually provide the search depth, this is a
+ // placeholder.
+ lldb::SearchDepth depth = lldb::eSearchDepthTarget;
+
+ StructuredDataImpl *args_data_impl = new StructuredDataImpl();
+ StructuredData::Dictionary *args_dict = nullptr;
+ success = options_dict.GetValueForKeyAsDictionary(
+ GetKey(OptionNames::ScriptArgs), args_dict);
+ if (success) {
+ args_data_impl->SetObjectSP(args_dict->shared_from_this());
+ }
+ return new BreakpointResolverScripted(bkpt, class_name, depth,
+ args_data_impl);
+}
+
+StructuredData::ObjectSP
+BreakpointResolverScripted::SerializeToStructuredData() {
+ StructuredData::DictionarySP options_dict_sp(
+ new StructuredData::Dictionary());
+
+ options_dict_sp->AddStringItem(GetKey(OptionNames::PythonClassName),
+ m_class_name);
+ if (m_args_ptr->IsValid())
+ options_dict_sp->AddItem(GetKey(OptionNames::ScriptArgs),
+ m_args_ptr->GetObjectSP());
+
+ return WrapOptionsDict(options_dict_sp);
+}
+
+ScriptInterpreter *BreakpointResolverScripted::GetScriptInterpreter() {
+ return m_breakpoint->GetTarget().GetDebugger().GetScriptInterpreter();
+}
+
+Searcher::CallbackReturn BreakpointResolverScripted::SearchCallback(
+ SearchFilter &filter, SymbolContext &context, Address *addr) {
+ assert(m_breakpoint != nullptr);
+ bool should_continue = true;
+ if (!m_implementation_sp)
+ return Searcher::eCallbackReturnStop;
+
+ ScriptInterpreter *interp = GetScriptInterpreter();
+ should_continue = interp->ScriptedBreakpointResolverSearchCallback(
+ m_implementation_sp,
+ &context);
+ if (should_continue)
+ return Searcher::eCallbackReturnContinue;
+ else
+ return Searcher::eCallbackReturnStop;
+}
+
+lldb::SearchDepth
+BreakpointResolverScripted::GetDepth() {
+ assert(m_breakpoint != nullptr);
+ lldb::SearchDepth depth = lldb::eSearchDepthModule;
+ if (m_implementation_sp) {
+ ScriptInterpreter *interp = GetScriptInterpreter();
+ depth = interp->ScriptedBreakpointResolverSearchDepth(
+ m_implementation_sp);
+ }
+ return depth;
+}
+
+void BreakpointResolverScripted::GetDescription(Stream *s) {
+ StructuredData::GenericSP generic_sp;
+ std::string short_help;
+
+ if (m_implementation_sp) {
+ ScriptInterpreter *interp = GetScriptInterpreter();
+ interp->GetShortHelpForCommandObject(m_implementation_sp,
+ short_help);
+ }
+ if (!short_help.empty())
+ s->PutCString(short_help.c_str());
+ else
+ s->Printf("python class = %s", m_class_name.c_str());
+}
+
+void BreakpointResolverScripted::Dump(Stream *s) const {}
+
+lldb::BreakpointResolverSP
+BreakpointResolverScripted::CopyForBreakpoint(Breakpoint &breakpoint) {
+ // FIXME: Have to make a copy of the arguments from the m_args_ptr and then
+ // pass that to the new resolver.
+ lldb::BreakpointResolverSP ret_sp(
+ new BreakpointResolverScripted(&breakpoint, m_class_name, m_depth,
+ nullptr));
+ return ret_sp;
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointSite.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointSite.cpp
new file mode 100644
index 00000000000..a757a01824c
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointSite.cpp
@@ -0,0 +1,206 @@
+//===-- BreakpointSite.cpp --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <inttypes.h>
+
+#include "lldb/Breakpoint/BreakpointSite.h"
+
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointSiteList.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointSite::BreakpointSite(BreakpointSiteList *list,
+ const BreakpointLocationSP &owner,
+ lldb::addr_t addr, bool use_hardware)
+ : StoppointLocation(GetNextID(), addr, 0, use_hardware),
+ m_type(eSoftware), // Process subclasses need to set this correctly using
+ // SetType()
+ m_saved_opcode(), m_trap_opcode(),
+ m_enabled(false), // Need to create it disabled, so the first enable turns
+ // it on.
+ m_owners(), m_owners_mutex() {
+ m_owners.Add(owner);
+}
+
+BreakpointSite::~BreakpointSite() {
+ BreakpointLocationSP bp_loc_sp;
+ const size_t owner_count = m_owners.GetSize();
+ for (size_t i = 0; i < owner_count; i++) {
+ m_owners.GetByIndex(i)->ClearBreakpointSite();
+ }
+}
+
+break_id_t BreakpointSite::GetNextID() {
+ static break_id_t g_next_id = 0;
+ return ++g_next_id;
+}
+
+// RETURNS - true if we should stop at this breakpoint, false if we
+// should continue.
+
+bool BreakpointSite::ShouldStop(StoppointCallbackContext *context) {
+ IncrementHitCount();
+ // ShouldStop can do a lot of work, and might even come come back and hit
+ // this breakpoint site again. So don't hold the m_owners_mutex the whole
+ // while. Instead make a local copy of the collection and call ShouldStop on
+ // the copy.
+ BreakpointLocationCollection owners_copy;
+ {
+ std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+ owners_copy = m_owners;
+ }
+ return owners_copy.ShouldStop(context);
+}
+
+bool BreakpointSite::IsBreakpointAtThisSite(lldb::break_id_t bp_id) {
+ std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+ const size_t owner_count = m_owners.GetSize();
+ for (size_t i = 0; i < owner_count; i++) {
+ if (m_owners.GetByIndex(i)->GetBreakpoint().GetID() == bp_id)
+ return true;
+ }
+ return false;
+}
+
+void BreakpointSite::Dump(Stream *s) const {
+ if (s == nullptr)
+ return;
+
+ s->Printf("BreakpointSite %u: addr = 0x%8.8" PRIx64
+ " type = %s breakpoint hw_index = %i hit_count = %-4u",
+ GetID(), (uint64_t)m_addr, IsHardware() ? "hardware" : "software",
+ GetHardwareIndex(), GetHitCount());
+}
+
+void BreakpointSite::GetDescription(Stream *s, lldb::DescriptionLevel level) {
+ std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+ if (level != lldb::eDescriptionLevelBrief)
+ s->Printf("breakpoint site: %d at 0x%8.8" PRIx64, GetID(),
+ GetLoadAddress());
+ m_owners.GetDescription(s, level);
+}
+
+bool BreakpointSite::IsInternal() const { return m_owners.IsInternal(); }
+
+uint8_t *BreakpointSite::GetTrapOpcodeBytes() { return &m_trap_opcode[0]; }
+
+const uint8_t *BreakpointSite::GetTrapOpcodeBytes() const {
+ return &m_trap_opcode[0];
+}
+
+size_t BreakpointSite::GetTrapOpcodeMaxByteSize() const {
+ return sizeof(m_trap_opcode);
+}
+
+bool BreakpointSite::SetTrapOpcode(const uint8_t *trap_opcode,
+ uint32_t trap_opcode_size) {
+ if (trap_opcode_size > 0 && trap_opcode_size <= sizeof(m_trap_opcode)) {
+ m_byte_size = trap_opcode_size;
+ ::memcpy(m_trap_opcode, trap_opcode, trap_opcode_size);
+ return true;
+ }
+ m_byte_size = 0;
+ return false;
+}
+
+uint8_t *BreakpointSite::GetSavedOpcodeBytes() { return &m_saved_opcode[0]; }
+
+const uint8_t *BreakpointSite::GetSavedOpcodeBytes() const {
+ return &m_saved_opcode[0];
+}
+
+bool BreakpointSite::IsEnabled() const { return m_enabled; }
+
+void BreakpointSite::SetEnabled(bool enabled) { m_enabled = enabled; }
+
+void BreakpointSite::AddOwner(const BreakpointLocationSP &owner) {
+ std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+ m_owners.Add(owner);
+}
+
+size_t BreakpointSite::RemoveOwner(lldb::break_id_t break_id,
+ lldb::break_id_t break_loc_id) {
+ std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+ m_owners.Remove(break_id, break_loc_id);
+ return m_owners.GetSize();
+}
+
+size_t BreakpointSite::GetNumberOfOwners() {
+ std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+ return m_owners.GetSize();
+}
+
+BreakpointLocationSP BreakpointSite::GetOwnerAtIndex(size_t index) {
+ std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+ return m_owners.GetByIndex(index);
+}
+
+bool BreakpointSite::ValidForThisThread(Thread *thread) {
+ std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+ return m_owners.ValidForThisThread(thread);
+}
+
+void BreakpointSite::BumpHitCounts() {
+ std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+ for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations()) {
+ loc_sp->BumpHitCount();
+ }
+}
+
+bool BreakpointSite::IntersectsRange(lldb::addr_t addr, size_t size,
+ lldb::addr_t *intersect_addr,
+ size_t *intersect_size,
+ size_t *opcode_offset) const {
+ // We only use software traps for software breakpoints
+ if (!IsHardware()) {
+ if (m_byte_size > 0) {
+ const lldb::addr_t bp_end_addr = m_addr + m_byte_size;
+ const lldb::addr_t end_addr = addr + size;
+ // Is the breakpoint end address before the passed in start address?
+ if (bp_end_addr <= addr)
+ return false;
+ // Is the breakpoint start address after passed in end address?
+ if (end_addr <= m_addr)
+ return false;
+ if (intersect_addr || intersect_size || opcode_offset) {
+ if (m_addr < addr) {
+ if (intersect_addr)
+ *intersect_addr = addr;
+ if (intersect_size)
+ *intersect_size =
+ std::min<lldb::addr_t>(bp_end_addr, end_addr) - addr;
+ if (opcode_offset)
+ *opcode_offset = addr - m_addr;
+ } else {
+ if (intersect_addr)
+ *intersect_addr = m_addr;
+ if (intersect_size)
+ *intersect_size =
+ std::min<lldb::addr_t>(bp_end_addr, end_addr) - m_addr;
+ if (opcode_offset)
+ *opcode_offset = 0;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+size_t
+BreakpointSite::CopyOwnersList(BreakpointLocationCollection &out_collection) {
+ std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+ for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations()) {
+ out_collection.Add(loc_sp);
+ }
+ return out_collection.GetSize();
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointSiteList.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointSiteList.cpp
new file mode 100644
index 00000000000..7a986fd8398
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointSiteList.cpp
@@ -0,0 +1,200 @@
+//===-- BreakpointSiteList.cpp ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointSiteList.h"
+
+#include "lldb/Utility/Stream.h"
+#include <algorithm>
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointSiteList::BreakpointSiteList() : m_mutex(), m_bp_site_list() {}
+
+BreakpointSiteList::~BreakpointSiteList() {}
+
+// Add breakpoint site to the list. However, if the element already exists in
+// the list, then we don't add it, and return LLDB_INVALID_BREAK_ID.
+
+lldb::break_id_t BreakpointSiteList::Add(const BreakpointSiteSP &bp) {
+ lldb::addr_t bp_site_load_addr = bp->GetLoadAddress();
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ collection::iterator iter = m_bp_site_list.find(bp_site_load_addr);
+
+ if (iter == m_bp_site_list.end()) {
+ m_bp_site_list.insert(iter, collection::value_type(bp_site_load_addr, bp));
+ return bp->GetID();
+ } else {
+ return LLDB_INVALID_BREAK_ID;
+ }
+}
+
+bool BreakpointSiteList::ShouldStop(StoppointCallbackContext *context,
+ lldb::break_id_t site_id) {
+ BreakpointSiteSP site_sp(FindByID(site_id));
+ if (site_sp) {
+ // Let the BreakpointSite decide if it should stop here (could not have
+ // reached it's target hit count yet, or it could have a callback that
+ // decided it shouldn't stop (shared library loads/unloads).
+ return site_sp->ShouldStop(context);
+ }
+ // We should stop here since this BreakpointSite isn't valid anymore or it
+ // doesn't exist.
+ return true;
+}
+lldb::break_id_t BreakpointSiteList::FindIDByAddress(lldb::addr_t addr) {
+ BreakpointSiteSP bp = FindByAddress(addr);
+ if (bp) {
+ // DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8"
+ // PRIx64 " ) => %u", __FUNCTION__, (uint64_t)addr, bp->GetID());
+ return bp.get()->GetID();
+ }
+ // DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8"
+ // PRIx64
+ // " ) => NONE", __FUNCTION__, (uint64_t)addr);
+ return LLDB_INVALID_BREAK_ID;
+}
+
+bool BreakpointSiteList::Remove(lldb::break_id_t break_id) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ collection::iterator pos = GetIDIterator(break_id); // Predicate
+ if (pos != m_bp_site_list.end()) {
+ m_bp_site_list.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+bool BreakpointSiteList::RemoveByAddress(lldb::addr_t address) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ collection::iterator pos = m_bp_site_list.find(address);
+ if (pos != m_bp_site_list.end()) {
+ m_bp_site_list.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+class BreakpointSiteIDMatches {
+public:
+ BreakpointSiteIDMatches(lldb::break_id_t break_id) : m_break_id(break_id) {}
+
+ bool operator()(std::pair<lldb::addr_t, BreakpointSiteSP> val_pair) const {
+ return m_break_id == val_pair.second->GetID();
+ }
+
+private:
+ const lldb::break_id_t m_break_id;
+};
+
+BreakpointSiteList::collection::iterator
+BreakpointSiteList::GetIDIterator(lldb::break_id_t break_id) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ return std::find_if(m_bp_site_list.begin(),
+ m_bp_site_list.end(), // Search full range
+ BreakpointSiteIDMatches(break_id)); // Predicate
+}
+
+BreakpointSiteList::collection::const_iterator
+BreakpointSiteList::GetIDConstIterator(lldb::break_id_t break_id) const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ return std::find_if(m_bp_site_list.begin(),
+ m_bp_site_list.end(), // Search full range
+ BreakpointSiteIDMatches(break_id)); // Predicate
+}
+
+BreakpointSiteSP BreakpointSiteList::FindByID(lldb::break_id_t break_id) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ BreakpointSiteSP stop_sp;
+ collection::iterator pos = GetIDIterator(break_id);
+ if (pos != m_bp_site_list.end())
+ stop_sp = pos->second;
+
+ return stop_sp;
+}
+
+const BreakpointSiteSP
+BreakpointSiteList::FindByID(lldb::break_id_t break_id) const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ BreakpointSiteSP stop_sp;
+ collection::const_iterator pos = GetIDConstIterator(break_id);
+ if (pos != m_bp_site_list.end())
+ stop_sp = pos->second;
+
+ return stop_sp;
+}
+
+BreakpointSiteSP BreakpointSiteList::FindByAddress(lldb::addr_t addr) {
+ BreakpointSiteSP found_sp;
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ collection::iterator iter = m_bp_site_list.find(addr);
+ if (iter != m_bp_site_list.end())
+ found_sp = iter->second;
+ return found_sp;
+}
+
+bool BreakpointSiteList::BreakpointSiteContainsBreakpoint(
+ lldb::break_id_t bp_site_id, lldb::break_id_t bp_id) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ collection::const_iterator pos = GetIDConstIterator(bp_site_id);
+ if (pos != m_bp_site_list.end())
+ return pos->second->IsBreakpointAtThisSite(bp_id);
+
+ return false;
+}
+
+void BreakpointSiteList::Dump(Stream *s) const {
+ s->Printf("%p: ", static_cast<const void *>(this));
+ // s->Indent();
+ s->Printf("BreakpointSiteList with %u BreakpointSites:\n",
+ (uint32_t)m_bp_site_list.size());
+ s->IndentMore();
+ collection::const_iterator pos;
+ collection::const_iterator end = m_bp_site_list.end();
+ for (pos = m_bp_site_list.begin(); pos != end; ++pos)
+ pos->second->Dump(s);
+ s->IndentLess();
+}
+
+void BreakpointSiteList::ForEach(
+ std::function<void(BreakpointSite *)> const &callback) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ for (auto pair : m_bp_site_list)
+ callback(pair.second.get());
+}
+
+bool BreakpointSiteList::FindInRange(lldb::addr_t lower_bound,
+ lldb::addr_t upper_bound,
+ BreakpointSiteList &bp_site_list) const {
+ if (lower_bound > upper_bound)
+ return false;
+
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ collection::const_iterator lower, upper, pos;
+ lower = m_bp_site_list.lower_bound(lower_bound);
+ if (lower == m_bp_site_list.end() || (*lower).first >= upper_bound)
+ return false;
+
+ // This is one tricky bit. The breakpoint might overlap the bottom end of
+ // the range. So we grab the breakpoint prior to the lower bound, and check
+ // that that + its byte size isn't in our range.
+ if (lower != m_bp_site_list.begin()) {
+ collection::const_iterator prev_pos = lower;
+ prev_pos--;
+ const BreakpointSiteSP &prev_bp = (*prev_pos).second;
+ if (prev_bp->GetLoadAddress() + prev_bp->GetByteSize() > lower_bound)
+ bp_site_list.Add(prev_bp);
+ }
+
+ upper = m_bp_site_list.upper_bound(upper_bound);
+
+ for (pos = lower; pos != upper; pos++) {
+ bp_site_list.Add((*pos).second);
+ }
+ return true;
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/CMakeLists.txt b/gnu/llvm/lldb/source/Breakpoint/CMakeLists.txt
new file mode 100644
index 00000000000..a7c0baf21af
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/CMakeLists.txt
@@ -0,0 +1,37 @@
+add_lldb_library(lldbBreakpoint
+ Breakpoint.cpp
+ BreakpointID.cpp
+ BreakpointIDList.cpp
+ BreakpointList.cpp
+ BreakpointLocation.cpp
+ BreakpointLocationCollection.cpp
+ BreakpointLocationList.cpp
+ BreakpointName.cpp
+ BreakpointOptions.cpp
+ BreakpointPrecondition.cpp
+ BreakpointResolver.cpp
+ BreakpointResolverAddress.cpp
+ BreakpointResolverFileLine.cpp
+ BreakpointResolverFileRegex.cpp
+ BreakpointResolverName.cpp
+ BreakpointResolverScripted.cpp
+ BreakpointSite.cpp
+ BreakpointSiteList.cpp
+ Stoppoint.cpp
+ StoppointCallbackContext.cpp
+ StoppointLocation.cpp
+ Watchpoint.cpp
+ WatchpointList.cpp
+ WatchpointOptions.cpp
+
+ LINK_LIBS
+ lldbCore
+ lldbExpression
+ lldbInterpreter
+ lldbSymbol
+ lldbTarget
+ lldbUtility
+
+ LINK_COMPONENTS
+ Support
+ )
diff --git a/gnu/llvm/lldb/source/Breakpoint/Stoppoint.cpp b/gnu/llvm/lldb/source/Breakpoint/Stoppoint.cpp
new file mode 100644
index 00000000000..4cab975fe32
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/Stoppoint.cpp
@@ -0,0 +1,24 @@
+//===-- Stoppoint.cpp -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/Stoppoint.h"
+#include "lldb/lldb-private.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Stoppoint constructor
+Stoppoint::Stoppoint() : m_bid(LLDB_INVALID_BREAK_ID) {}
+
+// Destructor
+Stoppoint::~Stoppoint() {}
+
+break_id_t Stoppoint::GetID() const { return m_bid; }
+
+void Stoppoint::SetID(break_id_t bid) { m_bid = bid; }
diff --git a/gnu/llvm/lldb/source/Breakpoint/StoppointCallbackContext.cpp b/gnu/llvm/lldb/source/Breakpoint/StoppointCallbackContext.cpp
new file mode 100644
index 00000000000..584bf0060a4
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/StoppointCallbackContext.cpp
@@ -0,0 +1,24 @@
+//===-- StoppointCallbackContext.cpp ----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+
+using namespace lldb_private;
+
+StoppointCallbackContext::StoppointCallbackContext()
+ : event(nullptr), exe_ctx_ref(), is_synchronous(false) {}
+
+StoppointCallbackContext::StoppointCallbackContext(
+ Event *e, const ExecutionContext &exe_ctx, bool synchronously)
+ : event(e), exe_ctx_ref(exe_ctx), is_synchronous(synchronously) {}
+
+void StoppointCallbackContext::Clear() {
+ event = nullptr;
+ exe_ctx_ref.Clear();
+ is_synchronous = false;
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/StoppointLocation.cpp b/gnu/llvm/lldb/source/Breakpoint/StoppointLocation.cpp
new file mode 100644
index 00000000000..8cc6791fa68
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/StoppointLocation.cpp
@@ -0,0 +1,32 @@
+//===-- StoppointLocation.cpp -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/StoppointLocation.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+// StoppointLocation constructor
+StoppointLocation::StoppointLocation(break_id_t bid, addr_t addr, bool hardware)
+ : m_loc_id(bid), m_addr(addr), m_hardware(hardware),
+ m_hardware_index(LLDB_INVALID_INDEX32), m_byte_size(0), m_hit_count(0) {}
+
+StoppointLocation::StoppointLocation(break_id_t bid, addr_t addr,
+ uint32_t byte_size, bool hardware)
+ : m_loc_id(bid), m_addr(addr), m_hardware(hardware),
+ m_hardware_index(LLDB_INVALID_INDEX32), m_byte_size(byte_size),
+ m_hit_count(0) {}
+
+// Destructor
+StoppointLocation::~StoppointLocation() {}
+
+void StoppointLocation::DecrementHitCount() {
+ assert(m_hit_count > 0);
+ --m_hit_count;
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/Watchpoint.cpp b/gnu/llvm/lldb/source/Breakpoint/Watchpoint.cpp
new file mode 100644
index 00000000000..17dcda13e9b
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/Watchpoint.cpp
@@ -0,0 +1,388 @@
+//===-- Watchpoint.cpp ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/Watchpoint.h"
+
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Expression/UserExpression.h"
+#include "lldb/Symbol/TypeSystem.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Watchpoint::Watchpoint(Target &target, lldb::addr_t addr, uint32_t size,
+ const CompilerType *type, bool hardware)
+ : StoppointLocation(0, addr, size, hardware), m_target(target),
+ m_enabled(false), m_is_hardware(hardware), m_is_watch_variable(false),
+ m_is_ephemeral(false), m_disabled_count(0), m_watch_read(0),
+ m_watch_write(0), m_watch_was_read(0), m_watch_was_written(0),
+ m_ignore_count(0), m_false_alarms(0), m_decl_str(), m_watch_spec_str(),
+ m_type(), m_error(), m_options(), m_being_created(true) {
+
+ if (type && type->IsValid())
+ m_type = *type;
+ else {
+ // If we don't have a known type, then we force it to unsigned int of the
+ // right size.
+ auto type_system_or_err =
+ target.GetScratchTypeSystemForLanguage(eLanguageTypeC);
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(
+ lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS),
+ std::move(err), "Failed to set type.");
+ } else {
+ m_type = type_system_or_err->GetBuiltinTypeForEncodingAndBitSize(
+ eEncodingUint, 8 * size);
+ }
+ }
+
+ // Set the initial value of the watched variable:
+ if (m_target.GetProcessSP()) {
+ ExecutionContext exe_ctx;
+ m_target.GetProcessSP()->CalculateExecutionContext(exe_ctx);
+ CaptureWatchedValue(exe_ctx);
+ }
+ m_being_created = false;
+}
+
+Watchpoint::~Watchpoint() = default;
+
+// This function is used when "baton" doesn't need to be freed
+void Watchpoint::SetCallback(WatchpointHitCallback callback, void *baton,
+ bool is_synchronous) {
+ // The default "Baton" class will keep a copy of "baton" and won't free or
+ // delete it when it goes goes out of scope.
+ m_options.SetCallback(callback, std::make_shared<UntypedBaton>(baton),
+ is_synchronous);
+
+ SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged);
+}
+
+// This function is used when a baton needs to be freed and therefore is
+// contained in a "Baton" subclass.
+void Watchpoint::SetCallback(WatchpointHitCallback callback,
+ const BatonSP &callback_baton_sp,
+ bool is_synchronous) {
+ m_options.SetCallback(callback, callback_baton_sp, is_synchronous);
+ SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged);
+}
+
+void Watchpoint::ClearCallback() {
+ m_options.ClearCallback();
+ SendWatchpointChangedEvent(eWatchpointEventTypeCommandChanged);
+}
+
+void Watchpoint::SetDeclInfo(const std::string &str) { m_decl_str = str; }
+
+std::string Watchpoint::GetWatchSpec() { return m_watch_spec_str; }
+
+void Watchpoint::SetWatchSpec(const std::string &str) {
+ m_watch_spec_str = str;
+}
+
+// Override default impl of StoppointLocation::IsHardware() since m_is_hardware
+// member field is more accurate.
+bool Watchpoint::IsHardware() const { return m_is_hardware; }
+
+bool Watchpoint::IsWatchVariable() const { return m_is_watch_variable; }
+
+void Watchpoint::SetWatchVariable(bool val) { m_is_watch_variable = val; }
+
+bool Watchpoint::CaptureWatchedValue(const ExecutionContext &exe_ctx) {
+ ConstString watch_name("$__lldb__watch_value");
+ m_old_value_sp = m_new_value_sp;
+ Address watch_address(GetLoadAddress());
+ if (!m_type.IsValid()) {
+ // Don't know how to report new & old values, since we couldn't make a
+ // scalar type for this watchpoint. This works around an assert in
+ // ValueObjectMemory::Create.
+ // FIXME: This should not happen, but if it does in some case we care about,
+ // we can go grab the value raw and print it as unsigned.
+ return false;
+ }
+ m_new_value_sp = ValueObjectMemory::Create(
+ exe_ctx.GetBestExecutionContextScope(), watch_name.GetStringRef(),
+ watch_address, m_type);
+ m_new_value_sp = m_new_value_sp->CreateConstantValue(watch_name);
+ return (m_new_value_sp && m_new_value_sp->GetError().Success());
+}
+
+void Watchpoint::IncrementFalseAlarmsAndReviseHitCount() {
+ ++m_false_alarms;
+ if (m_false_alarms) {
+ if (m_hit_count >= m_false_alarms) {
+ m_hit_count -= m_false_alarms;
+ m_false_alarms = 0;
+ } else {
+ m_false_alarms -= m_hit_count;
+ m_hit_count = 0;
+ }
+ }
+}
+
+// RETURNS - true if we should stop at this breakpoint, false if we
+// should continue.
+
+bool Watchpoint::ShouldStop(StoppointCallbackContext *context) {
+ IncrementHitCount();
+
+ return IsEnabled();
+}
+
+void Watchpoint::GetDescription(Stream *s, lldb::DescriptionLevel level) {
+ DumpWithLevel(s, level);
+}
+
+void Watchpoint::Dump(Stream *s) const {
+ DumpWithLevel(s, lldb::eDescriptionLevelBrief);
+}
+
+// If prefix is nullptr, we display the watch id and ignore the prefix
+// altogether.
+void Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const {
+ if (!prefix) {
+ s->Printf("\nWatchpoint %u hit:", GetID());
+ prefix = "";
+ }
+
+ if (m_old_value_sp) {
+ const char *old_value_cstr = m_old_value_sp->GetValueAsCString();
+ if (old_value_cstr && old_value_cstr[0])
+ s->Printf("\n%sold value: %s", prefix, old_value_cstr);
+ else {
+ const char *old_summary_cstr = m_old_value_sp->GetSummaryAsCString();
+ if (old_summary_cstr && old_summary_cstr[0])
+ s->Printf("\n%sold value: %s", prefix, old_summary_cstr);
+ }
+ }
+
+ if (m_new_value_sp) {
+ const char *new_value_cstr = m_new_value_sp->GetValueAsCString();
+ if (new_value_cstr && new_value_cstr[0])
+ s->Printf("\n%snew value: %s", prefix, new_value_cstr);
+ else {
+ const char *new_summary_cstr = m_new_value_sp->GetSummaryAsCString();
+ if (new_summary_cstr && new_summary_cstr[0])
+ s->Printf("\n%snew value: %s", prefix, new_summary_cstr);
+ }
+ }
+}
+
+void Watchpoint::DumpWithLevel(Stream *s,
+ lldb::DescriptionLevel description_level) const {
+ if (s == nullptr)
+ return;
+
+ assert(description_level >= lldb::eDescriptionLevelBrief &&
+ description_level <= lldb::eDescriptionLevelVerbose);
+
+ s->Printf("Watchpoint %u: addr = 0x%8.8" PRIx64
+ " size = %u state = %s type = %s%s",
+ GetID(), GetLoadAddress(), m_byte_size,
+ IsEnabled() ? "enabled" : "disabled", m_watch_read ? "r" : "",
+ m_watch_write ? "w" : "");
+
+ if (description_level >= lldb::eDescriptionLevelFull) {
+ if (!m_decl_str.empty())
+ s->Printf("\n declare @ '%s'", m_decl_str.c_str());
+ if (!m_watch_spec_str.empty())
+ s->Printf("\n watchpoint spec = '%s'", m_watch_spec_str.c_str());
+
+ // Dump the snapshots we have taken.
+ DumpSnapshots(s, " ");
+
+ if (GetConditionText())
+ s->Printf("\n condition = '%s'", GetConditionText());
+ m_options.GetCallbackDescription(s, description_level);
+ }
+
+ if (description_level >= lldb::eDescriptionLevelVerbose) {
+ s->Printf("\n hw_index = %i hit_count = %-4u ignore_count = %-4u",
+ GetHardwareIndex(), GetHitCount(), GetIgnoreCount());
+ }
+}
+
+bool Watchpoint::IsEnabled() const { return m_enabled; }
+
+// Within StopInfo.cpp, we purposely turn on the ephemeral mode right before
+// temporarily disable the watchpoint in order to perform possible watchpoint
+// actions without triggering further watchpoint events. After the temporary
+// disabled watchpoint is enabled, we then turn off the ephemeral mode.
+
+void Watchpoint::TurnOnEphemeralMode() { m_is_ephemeral = true; }
+
+void Watchpoint::TurnOffEphemeralMode() {
+ m_is_ephemeral = false;
+ // Leaving ephemeral mode, reset the m_disabled_count!
+ m_disabled_count = 0;
+}
+
+bool Watchpoint::IsDisabledDuringEphemeralMode() {
+ return m_disabled_count > 1 && m_is_ephemeral;
+}
+
+void Watchpoint::SetEnabled(bool enabled, bool notify) {
+ if (!enabled) {
+ if (!m_is_ephemeral)
+ SetHardwareIndex(LLDB_INVALID_INDEX32);
+ else
+ ++m_disabled_count;
+
+ // Don't clear the snapshots for now.
+ // Within StopInfo.cpp, we purposely do disable/enable watchpoint while
+ // performing watchpoint actions.
+ }
+ bool changed = enabled != m_enabled;
+ m_enabled = enabled;
+ if (notify && !m_is_ephemeral && changed)
+ SendWatchpointChangedEvent(enabled ? eWatchpointEventTypeEnabled
+ : eWatchpointEventTypeDisabled);
+}
+
+void Watchpoint::SetWatchpointType(uint32_t type, bool notify) {
+ int old_watch_read = m_watch_read;
+ int old_watch_write = m_watch_write;
+ m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0;
+ m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0;
+ if (notify &&
+ (old_watch_read != m_watch_read || old_watch_write != m_watch_write))
+ SendWatchpointChangedEvent(eWatchpointEventTypeTypeChanged);
+}
+
+bool Watchpoint::WatchpointRead() const { return m_watch_read != 0; }
+
+bool Watchpoint::WatchpointWrite() const { return m_watch_write != 0; }
+
+uint32_t Watchpoint::GetIgnoreCount() const { return m_ignore_count; }
+
+void Watchpoint::SetIgnoreCount(uint32_t n) {
+ bool changed = m_ignore_count != n;
+ m_ignore_count = n;
+ if (changed)
+ SendWatchpointChangedEvent(eWatchpointEventTypeIgnoreChanged);
+}
+
+bool Watchpoint::InvokeCallback(StoppointCallbackContext *context) {
+ return m_options.InvokeCallback(context, GetID());
+}
+
+void Watchpoint::SetCondition(const char *condition) {
+ if (condition == nullptr || condition[0] == '\0') {
+ if (m_condition_up)
+ m_condition_up.reset();
+ } else {
+ // Pass nullptr for expr_prefix (no translation-unit level definitions).
+ Status error;
+ m_condition_up.reset(m_target.GetUserExpressionForLanguage(
+ condition, llvm::StringRef(), lldb::eLanguageTypeUnknown,
+ UserExpression::eResultTypeAny, EvaluateExpressionOptions(), nullptr,
+ error));
+ if (error.Fail()) {
+ // FIXME: Log something...
+ m_condition_up.reset();
+ }
+ }
+ SendWatchpointChangedEvent(eWatchpointEventTypeConditionChanged);
+}
+
+const char *Watchpoint::GetConditionText() const {
+ if (m_condition_up)
+ return m_condition_up->GetUserText();
+ else
+ return nullptr;
+}
+
+void Watchpoint::SendWatchpointChangedEvent(
+ lldb::WatchpointEventType eventKind) {
+ if (!m_being_created &&
+ GetTarget().EventTypeHasListeners(
+ Target::eBroadcastBitWatchpointChanged)) {
+ WatchpointEventData *data =
+ new Watchpoint::WatchpointEventData(eventKind, shared_from_this());
+ GetTarget().BroadcastEvent(Target::eBroadcastBitWatchpointChanged, data);
+ }
+}
+
+void Watchpoint::SendWatchpointChangedEvent(WatchpointEventData *data) {
+ if (data == nullptr)
+ return;
+
+ if (!m_being_created &&
+ GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged))
+ GetTarget().BroadcastEvent(Target::eBroadcastBitWatchpointChanged, data);
+ else
+ delete data;
+}
+
+Watchpoint::WatchpointEventData::WatchpointEventData(
+ WatchpointEventType sub_type, const WatchpointSP &new_watchpoint_sp)
+ : EventData(), m_watchpoint_event(sub_type),
+ m_new_watchpoint_sp(new_watchpoint_sp) {}
+
+Watchpoint::WatchpointEventData::~WatchpointEventData() = default;
+
+ConstString Watchpoint::WatchpointEventData::GetFlavorString() {
+ static ConstString g_flavor("Watchpoint::WatchpointEventData");
+ return g_flavor;
+}
+
+ConstString Watchpoint::WatchpointEventData::GetFlavor() const {
+ return WatchpointEventData::GetFlavorString();
+}
+
+WatchpointSP &Watchpoint::WatchpointEventData::GetWatchpoint() {
+ return m_new_watchpoint_sp;
+}
+
+WatchpointEventType
+Watchpoint::WatchpointEventData::GetWatchpointEventType() const {
+ return m_watchpoint_event;
+}
+
+void Watchpoint::WatchpointEventData::Dump(Stream *s) const {}
+
+const Watchpoint::WatchpointEventData *
+Watchpoint::WatchpointEventData::GetEventDataFromEvent(const Event *event) {
+ if (event) {
+ const EventData *event_data = event->GetData();
+ if (event_data &&
+ event_data->GetFlavor() == WatchpointEventData::GetFlavorString())
+ return static_cast<const WatchpointEventData *>(event->GetData());
+ }
+ return nullptr;
+}
+
+WatchpointEventType
+Watchpoint::WatchpointEventData::GetWatchpointEventTypeFromEvent(
+ const EventSP &event_sp) {
+ const WatchpointEventData *data = GetEventDataFromEvent(event_sp.get());
+
+ if (data == nullptr)
+ return eWatchpointEventTypeInvalidType;
+ else
+ return data->GetWatchpointEventType();
+}
+
+WatchpointSP Watchpoint::WatchpointEventData::GetWatchpointFromEvent(
+ const EventSP &event_sp) {
+ WatchpointSP wp_sp;
+
+ const WatchpointEventData *data = GetEventDataFromEvent(event_sp.get());
+ if (data)
+ wp_sp = data->m_new_watchpoint_sp;
+
+ return wp_sp;
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/WatchpointList.cpp b/gnu/llvm/lldb/source/Breakpoint/WatchpointList.cpp
new file mode 100644
index 00000000000..b1c1e6f253e
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/WatchpointList.cpp
@@ -0,0 +1,252 @@
+//===-- WatchpointList.cpp --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/WatchpointList.h"
+#include "lldb/Breakpoint/Watchpoint.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+WatchpointList::WatchpointList()
+ : m_watchpoints(), m_mutex(), m_next_wp_id(0) {}
+
+WatchpointList::~WatchpointList() {}
+
+// Add a watchpoint to the list.
+lldb::watch_id_t WatchpointList::Add(const WatchpointSP &wp_sp, bool notify) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ wp_sp->SetID(++m_next_wp_id);
+ m_watchpoints.push_back(wp_sp);
+ if (notify) {
+ if (wp_sp->GetTarget().EventTypeHasListeners(
+ Target::eBroadcastBitWatchpointChanged))
+ wp_sp->GetTarget().BroadcastEvent(Target::eBroadcastBitWatchpointChanged,
+ new Watchpoint::WatchpointEventData(
+ eWatchpointEventTypeAdded, wp_sp));
+ }
+ return wp_sp->GetID();
+}
+
+void WatchpointList::Dump(Stream *s) const {
+ DumpWithLevel(s, lldb::eDescriptionLevelBrief);
+}
+
+void WatchpointList::DumpWithLevel(
+ Stream *s, lldb::DescriptionLevel description_level) const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ s->Printf("%p: ", static_cast<const void *>(this));
+ // s->Indent();
+ s->Printf("WatchpointList with %" PRIu64 " Watchpoints:\n",
+ (uint64_t)m_watchpoints.size());
+ s->IndentMore();
+ wp_collection::const_iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ (*pos)->DumpWithLevel(s, description_level);
+ s->IndentLess();
+}
+
+const WatchpointSP WatchpointList::FindByAddress(lldb::addr_t addr) const {
+ WatchpointSP wp_sp;
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (!m_watchpoints.empty()) {
+ wp_collection::const_iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos) {
+ lldb::addr_t wp_addr = (*pos)->GetLoadAddress();
+ uint32_t wp_bytesize = (*pos)->GetByteSize();
+ if ((wp_addr <= addr) && ((wp_addr + wp_bytesize) > addr)) {
+ wp_sp = *pos;
+ break;
+ }
+ }
+ }
+
+ return wp_sp;
+}
+
+const WatchpointSP WatchpointList::FindBySpec(std::string spec) const {
+ WatchpointSP wp_sp;
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (!m_watchpoints.empty()) {
+ wp_collection::const_iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ if ((*pos)->GetWatchSpec() == spec) {
+ wp_sp = *pos;
+ break;
+ }
+ }
+
+ return wp_sp;
+}
+
+class WatchpointIDMatches {
+public:
+ WatchpointIDMatches(lldb::watch_id_t watch_id) : m_watch_id(watch_id) {}
+
+ bool operator()(const WatchpointSP &wp) const {
+ return m_watch_id == wp->GetID();
+ }
+
+private:
+ const lldb::watch_id_t m_watch_id;
+};
+
+WatchpointList::wp_collection::iterator
+WatchpointList::GetIDIterator(lldb::watch_id_t watch_id) {
+ return std::find_if(m_watchpoints.begin(),
+ m_watchpoints.end(), // Search full range
+ WatchpointIDMatches(watch_id)); // Predicate
+}
+
+WatchpointList::wp_collection::const_iterator
+WatchpointList::GetIDConstIterator(lldb::watch_id_t watch_id) const {
+ return std::find_if(m_watchpoints.begin(),
+ m_watchpoints.end(), // Search full range
+ WatchpointIDMatches(watch_id)); // Predicate
+}
+
+WatchpointSP WatchpointList::FindByID(lldb::watch_id_t watch_id) const {
+ WatchpointSP wp_sp;
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ wp_collection::const_iterator pos = GetIDConstIterator(watch_id);
+ if (pos != m_watchpoints.end())
+ wp_sp = *pos;
+
+ return wp_sp;
+}
+
+lldb::watch_id_t WatchpointList::FindIDByAddress(lldb::addr_t addr) {
+ WatchpointSP wp_sp = FindByAddress(addr);
+ if (wp_sp) {
+ return wp_sp->GetID();
+ }
+ return LLDB_INVALID_WATCH_ID;
+}
+
+lldb::watch_id_t WatchpointList::FindIDBySpec(std::string spec) {
+ WatchpointSP wp_sp = FindBySpec(spec);
+ if (wp_sp) {
+ return wp_sp->GetID();
+ }
+ return LLDB_INVALID_WATCH_ID;
+}
+
+WatchpointSP WatchpointList::GetByIndex(uint32_t i) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ WatchpointSP wp_sp;
+ if (i < m_watchpoints.size()) {
+ wp_collection::const_iterator pos = m_watchpoints.begin();
+ std::advance(pos, i);
+ wp_sp = *pos;
+ }
+ return wp_sp;
+}
+
+const WatchpointSP WatchpointList::GetByIndex(uint32_t i) const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ WatchpointSP wp_sp;
+ if (i < m_watchpoints.size()) {
+ wp_collection::const_iterator pos = m_watchpoints.begin();
+ std::advance(pos, i);
+ wp_sp = *pos;
+ }
+ return wp_sp;
+}
+
+std::vector<lldb::watch_id_t> WatchpointList::GetWatchpointIDs() const {
+ std::vector<lldb::watch_id_t> IDs;
+ wp_collection::const_iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ IDs.push_back((*pos)->GetID());
+ return IDs;
+}
+
+bool WatchpointList::Remove(lldb::watch_id_t watch_id, bool notify) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ wp_collection::iterator pos = GetIDIterator(watch_id);
+ if (pos != m_watchpoints.end()) {
+ WatchpointSP wp_sp = *pos;
+ if (notify) {
+ if (wp_sp->GetTarget().EventTypeHasListeners(
+ Target::eBroadcastBitWatchpointChanged))
+ wp_sp->GetTarget().BroadcastEvent(
+ Target::eBroadcastBitWatchpointChanged,
+ new Watchpoint::WatchpointEventData(eWatchpointEventTypeRemoved,
+ wp_sp));
+ }
+ m_watchpoints.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+uint32_t WatchpointList::GetHitCount() const {
+ uint32_t hit_count = 0;
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ wp_collection::const_iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ hit_count += (*pos)->GetHitCount();
+ return hit_count;
+}
+
+bool WatchpointList::ShouldStop(StoppointCallbackContext *context,
+ lldb::watch_id_t watch_id) {
+
+ WatchpointSP wp_sp = FindByID(watch_id);
+ if (wp_sp) {
+ // Let the Watchpoint decide if it should stop here (could not have reached
+ // it's target hit count yet, or it could have a callback that decided it
+ // shouldn't stop.
+ return wp_sp->ShouldStop(context);
+ }
+ // We should stop here since this Watchpoint isn't valid anymore or it
+ // doesn't exist.
+ return true;
+}
+
+void WatchpointList::GetDescription(Stream *s, lldb::DescriptionLevel level) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ wp_collection::iterator pos, end = m_watchpoints.end();
+
+ for (pos = m_watchpoints.begin(); pos != end; ++pos) {
+ s->Printf(" ");
+ (*pos)->Dump(s);
+ }
+}
+
+void WatchpointList::SetEnabledAll(bool enabled) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+
+ wp_collection::iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ (*pos)->SetEnabled(enabled);
+}
+
+void WatchpointList::RemoveAll(bool notify) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (notify) {
+
+ {
+ wp_collection::iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos) {
+ if ((*pos)->GetTarget().EventTypeHasListeners(
+ Target::eBroadcastBitBreakpointChanged)) {
+ (*pos)->GetTarget().BroadcastEvent(
+ Target::eBroadcastBitWatchpointChanged,
+ new Watchpoint::WatchpointEventData(eWatchpointEventTypeRemoved,
+ *pos));
+ }
+ }
+ }
+ }
+ m_watchpoints.clear();
+}
+
+void WatchpointList::GetListMutex(
+ std::unique_lock<std::recursive_mutex> &lock) {
+ lock = std::unique_lock<std::recursive_mutex>(m_mutex);
+}
diff --git a/gnu/llvm/lldb/source/Breakpoint/WatchpointOptions.cpp b/gnu/llvm/lldb/source/Breakpoint/WatchpointOptions.cpp
new file mode 100644
index 00000000000..026bf2f746a
--- /dev/null
+++ b/gnu/llvm/lldb/source/Breakpoint/WatchpointOptions.cpp
@@ -0,0 +1,182 @@
+//===-- WatchpointOptions.cpp -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/WatchpointOptions.h"
+
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool WatchpointOptions::NullCallback(void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t watch_id) {
+ return true;
+}
+
+// WatchpointOptions constructor
+WatchpointOptions::WatchpointOptions()
+ : m_callback(WatchpointOptions::NullCallback), m_callback_baton_sp(),
+ m_callback_is_synchronous(false), m_thread_spec_up() {}
+
+// WatchpointOptions copy constructor
+WatchpointOptions::WatchpointOptions(const WatchpointOptions &rhs)
+ : m_callback(rhs.m_callback), m_callback_baton_sp(rhs.m_callback_baton_sp),
+ m_callback_is_synchronous(rhs.m_callback_is_synchronous),
+ m_thread_spec_up() {
+ if (rhs.m_thread_spec_up != nullptr)
+ m_thread_spec_up.reset(new ThreadSpec(*rhs.m_thread_spec_up));
+}
+
+// WatchpointOptions assignment operator
+const WatchpointOptions &WatchpointOptions::
+operator=(const WatchpointOptions &rhs) {
+ m_callback = rhs.m_callback;
+ m_callback_baton_sp = rhs.m_callback_baton_sp;
+ m_callback_is_synchronous = rhs.m_callback_is_synchronous;
+ if (rhs.m_thread_spec_up != nullptr)
+ m_thread_spec_up.reset(new ThreadSpec(*rhs.m_thread_spec_up));
+ return *this;
+}
+
+WatchpointOptions *
+WatchpointOptions::CopyOptionsNoCallback(WatchpointOptions &orig) {
+ WatchpointHitCallback orig_callback = orig.m_callback;
+ lldb::BatonSP orig_callback_baton_sp = orig.m_callback_baton_sp;
+ bool orig_is_sync = orig.m_callback_is_synchronous;
+
+ orig.ClearCallback();
+ WatchpointOptions *ret_val = new WatchpointOptions(orig);
+
+ orig.SetCallback(orig_callback, orig_callback_baton_sp, orig_is_sync);
+
+ return ret_val;
+}
+
+// Destructor
+WatchpointOptions::~WatchpointOptions() = default;
+
+// Callbacks
+void WatchpointOptions::SetCallback(WatchpointHitCallback callback,
+ const BatonSP &callback_baton_sp,
+ bool callback_is_synchronous) {
+ m_callback_is_synchronous = callback_is_synchronous;
+ m_callback = callback;
+ m_callback_baton_sp = callback_baton_sp;
+}
+
+void WatchpointOptions::ClearCallback() {
+ m_callback = WatchpointOptions::NullCallback;
+ m_callback_is_synchronous = false;
+ m_callback_baton_sp.reset();
+}
+
+Baton *WatchpointOptions::GetBaton() { return m_callback_baton_sp.get(); }
+
+const Baton *WatchpointOptions::GetBaton() const {
+ return m_callback_baton_sp.get();
+}
+
+bool WatchpointOptions::InvokeCallback(StoppointCallbackContext *context,
+ lldb::user_id_t watch_id) {
+ if (m_callback && context->is_synchronous == IsCallbackSynchronous()) {
+ return m_callback(m_callback_baton_sp ? m_callback_baton_sp->data()
+ : nullptr,
+ context, watch_id);
+ } else
+ return true;
+}
+
+bool WatchpointOptions::HasCallback() {
+ return m_callback != WatchpointOptions::NullCallback;
+}
+
+const ThreadSpec *WatchpointOptions::GetThreadSpecNoCreate() const {
+ return m_thread_spec_up.get();
+}
+
+ThreadSpec *WatchpointOptions::GetThreadSpec() {
+ if (m_thread_spec_up == nullptr)
+ m_thread_spec_up.reset(new ThreadSpec());
+
+ return m_thread_spec_up.get();
+}
+
+void WatchpointOptions::SetThreadID(lldb::tid_t thread_id) {
+ GetThreadSpec()->SetTID(thread_id);
+}
+
+void WatchpointOptions::GetCallbackDescription(
+ Stream *s, lldb::DescriptionLevel level) const {
+ if (m_callback_baton_sp.get()) {
+ s->EOL();
+ m_callback_baton_sp->GetDescription(s->AsRawOstream(), level,
+ s->GetIndentLevel());
+ }
+}
+
+void WatchpointOptions::GetDescription(Stream *s,
+ lldb::DescriptionLevel level) const {
+ // Figure out if there are any options not at their default value, and only
+ // print anything if there are:
+
+ if ((GetThreadSpecNoCreate() != nullptr &&
+ GetThreadSpecNoCreate()->HasSpecification())) {
+ if (level == lldb::eDescriptionLevelVerbose) {
+ s->EOL();
+ s->IndentMore();
+ s->Indent();
+ s->PutCString("Watchpoint Options:\n");
+ s->IndentMore();
+ s->Indent();
+ } else
+ s->PutCString(" Options: ");
+
+ if (m_thread_spec_up)
+ m_thread_spec_up->GetDescription(s, level);
+ else if (level == eDescriptionLevelBrief)
+ s->PutCString("thread spec: no ");
+ if (level == lldb::eDescriptionLevelFull) {
+ s->IndentLess();
+ s->IndentMore();
+ }
+ }
+
+ GetCallbackDescription(s, level);
+}
+
+void WatchpointOptions::CommandBaton::GetDescription(
+ llvm::raw_ostream &s, lldb::DescriptionLevel level,
+ unsigned indentation) const {
+ const CommandData *data = getItem();
+
+ if (level == eDescriptionLevelBrief) {
+ s << ", commands = %s"
+ << ((data && data->user_source.GetSize() > 0) ? "yes" : "no");
+ return;
+ }
+
+ indentation += 2;
+ s.indent(indentation);
+ s << "watchpoint commands:\n";
+
+ indentation += 2;
+ if (data && data->user_source.GetSize() > 0) {
+ for (const std::string &line : data->user_source) {
+ s.indent(indentation);
+ s << line << "\n";
+ }
+ } else
+ s << "No commands.\n";
+}