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