1 //===-- WatchpointList.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 11 // C Includes 12 // C++ Includes 13 // Other libraries and framework includes 14 // Project includes 15 #include "lldb/Breakpoint/WatchpointList.h" 16 #include "lldb/Breakpoint/Watchpoint.h" 17 18 using namespace lldb; 19 using namespace lldb_private; 20 21 WatchpointList::WatchpointList() : 22 m_watchpoints (), 23 m_mutex (Mutex::eMutexTypeRecursive), 24 m_next_wp_id (0) 25 { 26 } 27 28 WatchpointList::~WatchpointList() 29 { 30 } 31 32 // Add a watchpoint to the list. 33 lldb::watch_id_t 34 WatchpointList::Add (const WatchpointSP &wp_sp, bool notify) 35 { 36 Mutex::Locker locker (m_mutex); 37 wp_sp->SetID(++m_next_wp_id); 38 m_watchpoints.push_back(wp_sp); 39 if (notify) 40 { 41 if (wp_sp->GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged)) 42 wp_sp->GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged, 43 new Watchpoint::WatchpointEventData (eWatchpointEventTypeAdded, wp_sp)); 44 } 45 return wp_sp->GetID(); 46 } 47 48 void 49 WatchpointList::Dump (Stream *s) const 50 { 51 DumpWithLevel(s, lldb::eDescriptionLevelBrief); 52 } 53 54 void 55 WatchpointList::DumpWithLevel (Stream *s, lldb::DescriptionLevel description_level) const 56 { 57 Mutex::Locker locker (m_mutex); 58 s->Printf("%p: ", static_cast<const void*>(this)); 59 //s->Indent(); 60 s->Printf("WatchpointList with %" PRIu64 " Watchpoints:\n", 61 (uint64_t)m_watchpoints.size()); 62 s->IndentMore(); 63 wp_collection::const_iterator pos, end = m_watchpoints.end(); 64 for (pos = m_watchpoints.begin(); pos != end; ++pos) 65 (*pos)->DumpWithLevel(s, description_level); 66 s->IndentLess(); 67 } 68 69 const WatchpointSP 70 WatchpointList::FindByAddress (lldb::addr_t addr) const 71 { 72 WatchpointSP wp_sp; 73 Mutex::Locker locker (m_mutex); 74 if (!m_watchpoints.empty()) 75 { 76 wp_collection::const_iterator pos, end = m_watchpoints.end(); 77 for (pos = m_watchpoints.begin(); pos != end; ++pos) 78 { 79 lldb::addr_t wp_addr = (*pos)->GetLoadAddress(); 80 uint32_t wp_bytesize = (*pos)->GetByteSize(); 81 if ((wp_addr <= addr) && ((wp_addr + wp_bytesize) > addr)) 82 { 83 wp_sp = *pos; 84 break; 85 } 86 } 87 } 88 89 return wp_sp; 90 } 91 92 const WatchpointSP 93 WatchpointList::FindBySpec (std::string spec) const 94 { 95 WatchpointSP wp_sp; 96 Mutex::Locker locker (m_mutex); 97 if (!m_watchpoints.empty()) 98 { 99 wp_collection::const_iterator pos, end = m_watchpoints.end(); 100 for (pos = m_watchpoints.begin(); pos != end; ++pos) 101 if ((*pos)->GetWatchSpec() == spec) { 102 wp_sp = *pos; 103 break; 104 } 105 } 106 107 return wp_sp; 108 } 109 110 class WatchpointIDMatches 111 { 112 public: 113 WatchpointIDMatches (lldb::watch_id_t watch_id) : 114 m_watch_id(watch_id) 115 { 116 } 117 118 bool operator() (const WatchpointSP &wp) const 119 { 120 return m_watch_id == wp->GetID(); 121 } 122 123 private: 124 const lldb::watch_id_t m_watch_id; 125 }; 126 127 WatchpointList::wp_collection::iterator 128 WatchpointList::GetIDIterator (lldb::watch_id_t watch_id) 129 { 130 return std::find_if(m_watchpoints.begin(), m_watchpoints.end(), // Search full range 131 WatchpointIDMatches(watch_id)); // Predicate 132 } 133 134 WatchpointList::wp_collection::const_iterator 135 WatchpointList::GetIDConstIterator (lldb::watch_id_t watch_id) const 136 { 137 return std::find_if(m_watchpoints.begin(), m_watchpoints.end(), // Search full range 138 WatchpointIDMatches(watch_id)); // Predicate 139 } 140 141 WatchpointSP 142 WatchpointList::FindByID (lldb::watch_id_t watch_id) const 143 { 144 WatchpointSP wp_sp; 145 Mutex::Locker locker (m_mutex); 146 wp_collection::const_iterator pos = GetIDConstIterator(watch_id); 147 if (pos != m_watchpoints.end()) 148 wp_sp = *pos; 149 150 return wp_sp; 151 } 152 153 lldb::watch_id_t 154 WatchpointList::FindIDByAddress (lldb::addr_t addr) 155 { 156 WatchpointSP wp_sp = FindByAddress (addr); 157 if (wp_sp) 158 { 159 return wp_sp->GetID(); 160 } 161 return LLDB_INVALID_WATCH_ID; 162 } 163 164 lldb::watch_id_t 165 WatchpointList::FindIDBySpec (std::string spec) 166 { 167 WatchpointSP wp_sp = FindBySpec (spec); 168 if (wp_sp) 169 { 170 return wp_sp->GetID(); 171 } 172 return LLDB_INVALID_WATCH_ID; 173 } 174 175 WatchpointSP 176 WatchpointList::GetByIndex (uint32_t i) 177 { 178 Mutex::Locker locker (m_mutex); 179 WatchpointSP wp_sp; 180 if (i < m_watchpoints.size()) 181 { 182 wp_collection::const_iterator pos = m_watchpoints.begin(); 183 std::advance(pos, i); 184 wp_sp = *pos; 185 } 186 return wp_sp; 187 } 188 189 const WatchpointSP 190 WatchpointList::GetByIndex (uint32_t i) const 191 { 192 Mutex::Locker locker (m_mutex); 193 WatchpointSP wp_sp; 194 if (i < m_watchpoints.size()) 195 { 196 wp_collection::const_iterator pos = m_watchpoints.begin(); 197 std::advance(pos, i); 198 wp_sp = *pos; 199 } 200 return wp_sp; 201 } 202 203 std::vector<lldb::watch_id_t> 204 WatchpointList::GetWatchpointIDs() const 205 { 206 std::vector<lldb::watch_id_t> IDs; 207 wp_collection::const_iterator pos, end = m_watchpoints.end(); 208 for (pos = m_watchpoints.begin(); pos != end; ++pos) 209 IDs.push_back((*pos)->GetID()); 210 return IDs; 211 } 212 213 bool 214 WatchpointList::Remove (lldb::watch_id_t watch_id, bool notify) 215 { 216 Mutex::Locker locker (m_mutex); 217 wp_collection::iterator pos = GetIDIterator(watch_id); 218 if (pos != m_watchpoints.end()) 219 { 220 WatchpointSP wp_sp = *pos; 221 if (notify) 222 { 223 if (wp_sp->GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged)) 224 wp_sp->GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged, 225 new Watchpoint::WatchpointEventData (eWatchpointEventTypeRemoved, wp_sp)); 226 } 227 m_watchpoints.erase(pos); 228 return true; 229 } 230 return false; 231 } 232 233 uint32_t 234 WatchpointList::GetHitCount () const 235 { 236 uint32_t hit_count = 0; 237 Mutex::Locker locker (m_mutex); 238 wp_collection::const_iterator pos, end = m_watchpoints.end(); 239 for (pos = m_watchpoints.begin(); pos != end; ++pos) 240 hit_count += (*pos)->GetHitCount(); 241 return hit_count; 242 } 243 244 bool 245 WatchpointList::ShouldStop (StoppointCallbackContext *context, lldb::watch_id_t watch_id) 246 { 247 248 WatchpointSP wp_sp = FindByID (watch_id); 249 if (wp_sp) 250 { 251 // Let the Watchpoint decide if it should stop here (could not have 252 // reached it's target hit count yet, or it could have a callback 253 // that decided it shouldn't stop. 254 return wp_sp->ShouldStop (context); 255 } 256 // We should stop here since this Watchpoint isn't valid anymore or it 257 // doesn't exist. 258 return true; 259 } 260 261 void 262 WatchpointList::GetDescription (Stream *s, lldb::DescriptionLevel level) 263 { 264 Mutex::Locker locker (m_mutex); 265 wp_collection::iterator pos, end = m_watchpoints.end(); 266 267 for (pos = m_watchpoints.begin(); pos != end; ++pos) 268 { 269 s->Printf(" "); 270 (*pos)->Dump(s); 271 } 272 } 273 274 void 275 WatchpointList::SetEnabledAll (bool enabled) 276 { 277 Mutex::Locker locker(m_mutex); 278 279 wp_collection::iterator pos, end = m_watchpoints.end(); 280 for (pos = m_watchpoints.begin(); pos != end; ++pos) 281 (*pos)->SetEnabled (enabled); 282 } 283 284 void 285 WatchpointList::RemoveAll (bool notify) 286 { 287 Mutex::Locker locker(m_mutex); 288 if (notify) 289 { 290 291 { 292 wp_collection::iterator pos, end = m_watchpoints.end(); 293 for (pos = m_watchpoints.begin(); pos != end; ++pos) 294 { 295 if ((*pos)->GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged)) 296 { 297 (*pos)->GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged, 298 new Watchpoint::WatchpointEventData (eWatchpointEventTypeRemoved, 299 *pos)); 300 } 301 } 302 } 303 } 304 m_watchpoints.clear(); 305 } 306 307 void 308 WatchpointList::GetListMutex (Mutex::Locker &locker) 309 { 310 return locker.Lock (m_mutex); 311 } 312