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