| //===-- 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) { | |
| bp->GetTarget().NotifyBreakpointChanged(*bp, event); | |
| } | |
| BreakpointList::BreakpointList(bool is_internal) | |
| : 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 = llvm::find_if(m_breakpoints, [&](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 llvm::find_if(m_breakpoints, [&](const BreakpointSP &bp) { | |
| return bp->GetID() == break_id; | |
| }); | |
| } | |
| BreakpointList::bp_collection::const_iterator | |
| BreakpointList::GetBreakpointIDConstIterator(break_id_t break_id) const { | |
| return llvm::find_if(m_breakpoints, [&](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(llvm::StringRef name) { | |
| if (name.empty()) | |
| return llvm::createStringError(llvm::errc::invalid_argument, | |
| "FindBreakpointsByName requires a name"); | |
| Status error; | |
| if (!BreakpointID::StringIsBreakpointName(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::ResetHitCounts() { | |
| std::lock_guard<std::recursive_mutex> guard(m_mutex); | |
| for (const auto &bp_sp : m_breakpoints) | |
| bp_sp->ResetHitCount(); | |
| } | |
| void BreakpointList::GetListMutex( | |
| std::unique_lock<std::recursive_mutex> &lock) { | |
| lock = std::unique_lock<std::recursive_mutex>(m_mutex); | |
| } |