1 //===-- BreakpointList.cpp --------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Breakpoint/BreakpointList.h" 10 11 #include "lldb/Target/Target.h" 12 13 using namespace lldb; 14 using namespace lldb_private; 15 16 static void NotifyChange(const BreakpointSP &bp, BreakpointEventType event) { 17 Target &target = bp->GetTarget(); 18 if (target.EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged)) 19 target.BroadcastEvent(Target::eBroadcastBitBreakpointChanged, 20 new Breakpoint::BreakpointEventData(event, bp)); 21 } 22 23 BreakpointList::BreakpointList(bool is_internal) 24 : m_mutex(), m_breakpoints(), m_next_break_id(0), 25 m_is_internal(is_internal) {} 26 27 BreakpointList::~BreakpointList() {} 28 29 break_id_t BreakpointList::Add(BreakpointSP &bp_sp, bool notify) { 30 std::lock_guard<std::recursive_mutex> guard(m_mutex); 31 32 // Internal breakpoint IDs are negative, normal ones are positive 33 bp_sp->SetID(m_is_internal ? --m_next_break_id : ++m_next_break_id); 34 35 m_breakpoints.push_back(bp_sp); 36 37 if (notify) 38 NotifyChange(bp_sp, eBreakpointEventTypeAdded); 39 40 return bp_sp->GetID(); 41 } 42 43 bool BreakpointList::Remove(break_id_t break_id, bool notify) { 44 std::lock_guard<std::recursive_mutex> guard(m_mutex); 45 46 auto it = std::find_if( 47 m_breakpoints.begin(), m_breakpoints.end(), 48 [&](const BreakpointSP &bp) { return bp->GetID() == break_id; }); 49 50 if (it == m_breakpoints.end()) 51 return false; 52 53 if (notify) 54 NotifyChange(*it, eBreakpointEventTypeRemoved); 55 56 m_breakpoints.erase(it); 57 58 return true; 59 } 60 61 void BreakpointList::RemoveInvalidLocations(const ArchSpec &arch) { 62 std::lock_guard<std::recursive_mutex> guard(m_mutex); 63 for (const auto &bp_sp : m_breakpoints) 64 bp_sp->RemoveInvalidLocations(arch); 65 } 66 67 void BreakpointList::SetEnabledAll(bool enabled) { 68 std::lock_guard<std::recursive_mutex> guard(m_mutex); 69 for (const auto &bp_sp : m_breakpoints) 70 bp_sp->SetEnabled(enabled); 71 } 72 73 void BreakpointList::SetEnabledAllowed(bool enabled) { 74 std::lock_guard<std::recursive_mutex> guard(m_mutex); 75 for (const auto &bp_sp : m_breakpoints) 76 if (bp_sp->AllowDisable()) 77 bp_sp->SetEnabled(enabled); 78 } 79 80 void BreakpointList::RemoveAll(bool notify) { 81 std::lock_guard<std::recursive_mutex> guard(m_mutex); 82 ClearAllBreakpointSites(); 83 84 if (notify) { 85 for (const auto &bp_sp : m_breakpoints) 86 NotifyChange(bp_sp, eBreakpointEventTypeRemoved); 87 } 88 89 m_breakpoints.clear(); 90 } 91 92 void BreakpointList::RemoveAllowed(bool notify) { 93 std::lock_guard<std::recursive_mutex> guard(m_mutex); 94 95 for (const auto &bp_sp : m_breakpoints) { 96 if (bp_sp->AllowDelete()) 97 bp_sp->ClearAllBreakpointSites(); 98 if (notify) 99 NotifyChange(bp_sp, eBreakpointEventTypeRemoved); 100 } 101 102 m_breakpoints.erase( 103 std::remove_if(m_breakpoints.begin(), m_breakpoints.end(), 104 [&](const BreakpointSP &bp) { return bp->AllowDelete(); }), 105 m_breakpoints.end()); 106 } 107 108 BreakpointList::bp_collection::iterator 109 BreakpointList::GetBreakpointIDIterator(break_id_t break_id) { 110 return std::find_if( 111 m_breakpoints.begin(), m_breakpoints.end(), 112 [&](const BreakpointSP &bp) { return bp->GetID() == break_id; }); 113 } 114 115 BreakpointList::bp_collection::const_iterator 116 BreakpointList::GetBreakpointIDConstIterator(break_id_t break_id) const { 117 return std::find_if( 118 m_breakpoints.begin(), m_breakpoints.end(), 119 [&](const BreakpointSP &bp) { return bp->GetID() == break_id; }); 120 } 121 122 BreakpointSP BreakpointList::FindBreakpointByID(break_id_t break_id) const { 123 std::lock_guard<std::recursive_mutex> guard(m_mutex); 124 125 auto it = GetBreakpointIDConstIterator(break_id); 126 if (it != m_breakpoints.end()) 127 return *it; 128 return {}; 129 } 130 131 bool BreakpointList::FindBreakpointsByName(const char *name, 132 BreakpointList &matching_bps) { 133 Status error; 134 if (!name) 135 return false; 136 137 if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(name), error)) 138 return false; 139 140 for (BreakpointSP bkpt_sp : Breakpoints()) { 141 if (bkpt_sp->MatchesName(name)) { 142 matching_bps.Add(bkpt_sp, false); 143 } 144 } 145 146 return true; 147 } 148 149 void BreakpointList::Dump(Stream *s) const { 150 std::lock_guard<std::recursive_mutex> guard(m_mutex); 151 s->Printf("%p: ", static_cast<const void *>(this)); 152 s->Indent(); 153 s->Printf("BreakpointList with %u Breakpoints:\n", 154 (uint32_t)m_breakpoints.size()); 155 s->IndentMore(); 156 for (const auto &bp_sp : m_breakpoints) 157 bp_sp->Dump(s); 158 s->IndentLess(); 159 } 160 161 BreakpointSP BreakpointList::GetBreakpointAtIndex(size_t i) const { 162 std::lock_guard<std::recursive_mutex> guard(m_mutex); 163 if (i < m_breakpoints.size()) 164 return m_breakpoints[i]; 165 return {}; 166 } 167 168 void BreakpointList::UpdateBreakpoints(ModuleList &module_list, bool added, 169 bool delete_locations) { 170 std::lock_guard<std::recursive_mutex> guard(m_mutex); 171 for (const auto &bp_sp : m_breakpoints) 172 bp_sp->ModulesChanged(module_list, added, delete_locations); 173 } 174 175 void BreakpointList::UpdateBreakpointsWhenModuleIsReplaced( 176 ModuleSP old_module_sp, ModuleSP new_module_sp) { 177 std::lock_guard<std::recursive_mutex> guard(m_mutex); 178 for (const auto &bp_sp : m_breakpoints) 179 bp_sp->ModuleReplaced(old_module_sp, new_module_sp); 180 } 181 182 void BreakpointList::ClearAllBreakpointSites() { 183 std::lock_guard<std::recursive_mutex> guard(m_mutex); 184 for (const auto &bp_sp : m_breakpoints) 185 bp_sp->ClearAllBreakpointSites(); 186 } 187 188 void BreakpointList::GetListMutex( 189 std::unique_lock<std::recursive_mutex> &lock) { 190 lock = std::unique_lock<std::recursive_mutex>(m_mutex); 191 } 192