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 auto event_data_sp = 22 std::make_shared<Breakpoint::BreakpointEventData>(event, bp); 23 target.BroadcastEvent(Target::eBroadcastBitBreakpointChanged, 24 event_data_sp); 25 } 26 } 27 28 BreakpointList::BreakpointList(bool is_internal) 29 : m_next_break_id(0), m_is_internal(is_internal) {} 30 31 BreakpointList::~BreakpointList() = default; 32 33 break_id_t BreakpointList::Add(BreakpointSP &bp_sp, bool notify) { 34 std::lock_guard<std::recursive_mutex> guard(m_mutex); 35 36 // Internal breakpoint IDs are negative, normal ones are positive 37 bp_sp->SetID(m_is_internal ? --m_next_break_id : ++m_next_break_id); 38 39 m_breakpoints.push_back(bp_sp); 40 41 if (notify) 42 NotifyChange(bp_sp, eBreakpointEventTypeAdded); 43 44 return bp_sp->GetID(); 45 } 46 47 bool BreakpointList::Remove(break_id_t break_id, bool notify) { 48 std::lock_guard<std::recursive_mutex> guard(m_mutex); 49 50 auto it = std::find_if( 51 m_breakpoints.begin(), m_breakpoints.end(), 52 [&](const BreakpointSP &bp) { return bp->GetID() == break_id; }); 53 54 if (it == m_breakpoints.end()) 55 return false; 56 57 if (notify) 58 NotifyChange(*it, eBreakpointEventTypeRemoved); 59 60 m_breakpoints.erase(it); 61 62 return true; 63 } 64 65 void BreakpointList::RemoveInvalidLocations(const ArchSpec &arch) { 66 std::lock_guard<std::recursive_mutex> guard(m_mutex); 67 for (const auto &bp_sp : m_breakpoints) 68 bp_sp->RemoveInvalidLocations(arch); 69 } 70 71 void BreakpointList::SetEnabledAll(bool enabled) { 72 std::lock_guard<std::recursive_mutex> guard(m_mutex); 73 for (const auto &bp_sp : m_breakpoints) 74 bp_sp->SetEnabled(enabled); 75 } 76 77 void BreakpointList::SetEnabledAllowed(bool enabled) { 78 std::lock_guard<std::recursive_mutex> guard(m_mutex); 79 for (const auto &bp_sp : m_breakpoints) 80 if (bp_sp->AllowDisable()) 81 bp_sp->SetEnabled(enabled); 82 } 83 84 void BreakpointList::RemoveAll(bool notify) { 85 std::lock_guard<std::recursive_mutex> guard(m_mutex); 86 ClearAllBreakpointSites(); 87 88 if (notify) { 89 for (const auto &bp_sp : m_breakpoints) 90 NotifyChange(bp_sp, eBreakpointEventTypeRemoved); 91 } 92 93 m_breakpoints.clear(); 94 } 95 96 void BreakpointList::RemoveAllowed(bool notify) { 97 std::lock_guard<std::recursive_mutex> guard(m_mutex); 98 99 for (const auto &bp_sp : m_breakpoints) { 100 if (bp_sp->AllowDelete()) 101 bp_sp->ClearAllBreakpointSites(); 102 if (notify) 103 NotifyChange(bp_sp, eBreakpointEventTypeRemoved); 104 } 105 106 llvm::erase_if(m_breakpoints, 107 [&](const BreakpointSP &bp) { return bp->AllowDelete(); }); 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::ResetHitCounts() { 193 std::lock_guard<std::recursive_mutex> guard(m_mutex); 194 for (const auto &bp_sp : m_breakpoints) 195 bp_sp->ResetHitCount(); 196 } 197 198 void BreakpointList::GetListMutex( 199 std::unique_lock<std::recursive_mutex> &lock) { 200 lock = std::unique_lock<std::recursive_mutex>(m_mutex); 201 } 202