| //===-- BreakpointList.cpp ------------------------------------------------===// |
| // |
| // 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() = default; |
| |
| 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); |
| } |
| |
| llvm::erase_if(m_breakpoints, |
| [&](const BreakpointSP &bp) { return bp->AllowDelete(); }); |
| } |
| |
| 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); |
| } |