1 //===-- BreakpointList.cpp --------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/Breakpoint/BreakpointList.h" 11 12 #include "lldb/Target/Target.h" 13 14 using namespace lldb; 15 using namespace lldb_private; 16 17 BreakpointList::BreakpointList(bool is_internal) 18 : m_mutex(), m_breakpoints(), m_next_break_id(0), 19 m_is_internal(is_internal) {} 20 21 BreakpointList::~BreakpointList() {} 22 23 break_id_t BreakpointList::Add(BreakpointSP &bp_sp, bool notify) { 24 std::lock_guard<std::recursive_mutex> guard(m_mutex); 25 // Internal breakpoint IDs are negative, normal ones are positive 26 bp_sp->SetID(m_is_internal ? --m_next_break_id : ++m_next_break_id); 27 28 m_breakpoints.push_back(bp_sp); 29 if (notify) { 30 if (bp_sp->GetTarget().EventTypeHasListeners( 31 Target::eBroadcastBitBreakpointChanged)) 32 bp_sp->GetTarget().BroadcastEvent(Target::eBroadcastBitBreakpointChanged, 33 new Breakpoint::BreakpointEventData( 34 eBreakpointEventTypeAdded, bp_sp)); 35 } 36 return bp_sp->GetID(); 37 } 38 39 bool BreakpointList::Remove(break_id_t break_id, bool notify) { 40 std::lock_guard<std::recursive_mutex> guard(m_mutex); 41 bp_collection::iterator pos = GetBreakpointIDIterator(break_id); // Predicate 42 if (pos != m_breakpoints.end()) { 43 BreakpointSP bp_sp(*pos); 44 m_breakpoints.erase(pos); 45 if (notify) { 46 if (bp_sp->GetTarget().EventTypeHasListeners( 47 Target::eBroadcastBitBreakpointChanged)) 48 bp_sp->GetTarget().BroadcastEvent( 49 Target::eBroadcastBitBreakpointChanged, 50 new Breakpoint::BreakpointEventData(eBreakpointEventTypeRemoved, 51 bp_sp)); 52 } 53 return true; 54 } 55 return false; 56 } 57 58 void BreakpointList::RemoveInvalidLocations(const ArchSpec &arch) { 59 std::lock_guard<std::recursive_mutex> guard(m_mutex); 60 for (const auto &bp_sp : m_breakpoints) 61 bp_sp->RemoveInvalidLocations(arch); 62 } 63 64 void BreakpointList::SetEnabledAll(bool enabled) { 65 std::lock_guard<std::recursive_mutex> guard(m_mutex); 66 for (const auto &bp_sp : m_breakpoints) 67 bp_sp->SetEnabled(enabled); 68 } 69 70 void BreakpointList::SetEnabledAllowed(bool enabled) { 71 std::lock_guard<std::recursive_mutex> guard(m_mutex); 72 for (const auto &bp_sp : m_breakpoints) 73 if (bp_sp->AllowDisable()) 74 bp_sp->SetEnabled(enabled); 75 } 76 77 void BreakpointList::RemoveAll(bool notify) { 78 std::lock_guard<std::recursive_mutex> guard(m_mutex); 79 ClearAllBreakpointSites(); 80 81 if (notify) { 82 bp_collection::iterator pos, end = m_breakpoints.end(); 83 for (pos = m_breakpoints.begin(); pos != end; ++pos) { 84 if ((*pos)->GetTarget().EventTypeHasListeners( 85 Target::eBroadcastBitBreakpointChanged)) { 86 (*pos)->GetTarget().BroadcastEvent( 87 Target::eBroadcastBitBreakpointChanged, 88 new Breakpoint::BreakpointEventData(eBreakpointEventTypeRemoved, 89 *pos)); 90 } 91 } 92 } 93 m_breakpoints.erase(m_breakpoints.begin(), m_breakpoints.end()); 94 } 95 96 void BreakpointList::RemoveAllowed(bool notify) { 97 std::lock_guard<std::recursive_mutex> guard(m_mutex); 98 99 bp_collection::iterator pos, end = m_breakpoints.end(); 100 if (notify) { 101 for (pos = m_breakpoints.begin(); pos != end; ++pos) { 102 if(!(*pos)->AllowDelete()) 103 continue; 104 if ((*pos)->GetTarget().EventTypeHasListeners( 105 Target::eBroadcastBitBreakpointChanged)) { 106 (*pos)->GetTarget().BroadcastEvent( 107 Target::eBroadcastBitBreakpointChanged, 108 new Breakpoint::BreakpointEventData(eBreakpointEventTypeRemoved, 109 *pos)); 110 } 111 } 112 } 113 pos = m_breakpoints.begin(); 114 while ( pos != end) { 115 auto bp = *pos; 116 if (bp->AllowDelete()) { 117 bp->ClearAllBreakpointSites(); 118 pos = m_breakpoints.erase(pos); 119 } else 120 pos++; 121 } 122 } 123 124 class BreakpointIDMatches { 125 public: 126 BreakpointIDMatches(break_id_t break_id) : m_break_id(break_id) {} 127 128 bool operator()(const BreakpointSP &bp) const { 129 return m_break_id == bp->GetID(); 130 } 131 132 private: 133 const break_id_t m_break_id; 134 }; 135 136 BreakpointList::bp_collection::iterator 137 BreakpointList::GetBreakpointIDIterator(break_id_t break_id) { 138 return std::find_if(m_breakpoints.begin(), 139 m_breakpoints.end(), // Search full range 140 BreakpointIDMatches(break_id)); // Predicate 141 } 142 143 BreakpointList::bp_collection::const_iterator 144 BreakpointList::GetBreakpointIDConstIterator(break_id_t break_id) const { 145 return std::find_if(m_breakpoints.begin(), 146 m_breakpoints.end(), // Search full range 147 BreakpointIDMatches(break_id)); // Predicate 148 } 149 150 BreakpointSP BreakpointList::FindBreakpointByID(break_id_t break_id) { 151 std::lock_guard<std::recursive_mutex> guard(m_mutex); 152 BreakpointSP stop_sp; 153 bp_collection::iterator pos = GetBreakpointIDIterator(break_id); 154 if (pos != m_breakpoints.end()) 155 stop_sp = *pos; 156 157 return stop_sp; 158 } 159 160 const BreakpointSP 161 BreakpointList::FindBreakpointByID(break_id_t break_id) const { 162 std::lock_guard<std::recursive_mutex> guard(m_mutex); 163 BreakpointSP stop_sp; 164 bp_collection::const_iterator pos = GetBreakpointIDConstIterator(break_id); 165 if (pos != m_breakpoints.end()) 166 stop_sp = *pos; 167 168 return stop_sp; 169 } 170 171 bool BreakpointList::FindBreakpointsByName(const char *name, 172 BreakpointList &matching_bps) { 173 Status error; 174 if (!name) 175 return false; 176 177 if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(name), error)) 178 return false; 179 180 for (BreakpointSP bkpt_sp : Breakpoints()) { 181 if (bkpt_sp->MatchesName(name)) { 182 matching_bps.Add(bkpt_sp, false); 183 } 184 } 185 return true; 186 } 187 188 void BreakpointList::Dump(Stream *s) const { 189 std::lock_guard<std::recursive_mutex> guard(m_mutex); 190 s->Printf("%p: ", static_cast<const void *>(this)); 191 s->Indent(); 192 s->Printf("BreakpointList with %u Breakpoints:\n", 193 (uint32_t)m_breakpoints.size()); 194 s->IndentMore(); 195 for (const auto &bp_sp : m_breakpoints) 196 bp_sp->Dump(s); 197 s->IndentLess(); 198 } 199 200 BreakpointSP BreakpointList::GetBreakpointAtIndex(size_t i) { 201 std::lock_guard<std::recursive_mutex> guard(m_mutex); 202 BreakpointSP stop_sp; 203 bp_collection::iterator end = m_breakpoints.end(); 204 bp_collection::iterator pos; 205 size_t curr_i = 0; 206 for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i) { 207 if (curr_i == i) 208 stop_sp = *pos; 209 } 210 return stop_sp; 211 } 212 213 const BreakpointSP BreakpointList::GetBreakpointAtIndex(size_t i) const { 214 std::lock_guard<std::recursive_mutex> guard(m_mutex); 215 BreakpointSP stop_sp; 216 bp_collection::const_iterator end = m_breakpoints.end(); 217 bp_collection::const_iterator pos; 218 size_t curr_i = 0; 219 for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i) { 220 if (curr_i == i) 221 stop_sp = *pos; 222 } 223 return stop_sp; 224 } 225 226 void BreakpointList::UpdateBreakpoints(ModuleList &module_list, bool added, 227 bool delete_locations) { 228 std::lock_guard<std::recursive_mutex> guard(m_mutex); 229 for (const auto &bp_sp : m_breakpoints) 230 bp_sp->ModulesChanged(module_list, added, delete_locations); 231 } 232 233 void BreakpointList::UpdateBreakpointsWhenModuleIsReplaced( 234 ModuleSP old_module_sp, ModuleSP new_module_sp) { 235 std::lock_guard<std::recursive_mutex> guard(m_mutex); 236 for (const auto &bp_sp : m_breakpoints) 237 bp_sp->ModuleReplaced(old_module_sp, new_module_sp); 238 } 239 240 void BreakpointList::ClearAllBreakpointSites() { 241 std::lock_guard<std::recursive_mutex> guard(m_mutex); 242 for (const auto &bp_sp : m_breakpoints) 243 bp_sp->ClearAllBreakpointSites(); 244 } 245 246 void BreakpointList::GetListMutex( 247 std::unique_lock<std::recursive_mutex> &lock) { 248 lock = std::unique_lock<std::recursive_mutex>(m_mutex); 249 } 250