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