1 //===-- BreakpointSiteList.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/BreakpointSiteList.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 #include "lldb/Core/Stream.h" 17 #include <algorithm> 18 19 using namespace lldb; 20 using namespace lldb_private; 21 22 BreakpointSiteList::BreakpointSiteList() : 23 m_mutex (Mutex::eMutexTypeRecursive), 24 m_bp_site_list() 25 { 26 } 27 28 BreakpointSiteList::~BreakpointSiteList() 29 { 30 } 31 32 // Add breakpoint site to the list. However, if the element already exists in the 33 // list, then we don't add it, and return LLDB_INVALID_BREAK_ID. 34 35 lldb::break_id_t 36 BreakpointSiteList::Add(const BreakpointSiteSP &bp) 37 { 38 lldb::addr_t bp_site_load_addr = bp->GetLoadAddress(); 39 Mutex::Locker locker(m_mutex); 40 collection::iterator iter = m_bp_site_list.find (bp_site_load_addr); 41 42 if (iter == m_bp_site_list.end()) 43 { 44 m_bp_site_list.insert (iter, collection::value_type (bp_site_load_addr, bp)); 45 return bp->GetID(); 46 } 47 else 48 { 49 return LLDB_INVALID_BREAK_ID; 50 } 51 } 52 53 bool 54 BreakpointSiteList::ShouldStop (StoppointCallbackContext *context, lldb::break_id_t site_id) 55 { 56 BreakpointSiteSP site_sp (FindByID (site_id)); 57 if (site_sp) 58 { 59 // Let the BreakpointSite decide if it should stop here (could not have 60 // reached it's target hit count yet, or it could have a callback 61 // that decided it shouldn't stop (shared library loads/unloads). 62 return site_sp->ShouldStop (context); 63 } 64 // We should stop here since this BreakpointSite isn't valid anymore or it 65 // doesn't exist. 66 return true; 67 } 68 lldb::break_id_t 69 BreakpointSiteList::FindIDByAddress (lldb::addr_t addr) 70 { 71 BreakpointSiteSP bp = FindByAddress (addr); 72 if (bp) 73 { 74 //DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8" PRIx64 " ) => %u", __FUNCTION__, (uint64_t)addr, bp->GetID()); 75 return bp.get()->GetID(); 76 } 77 //DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8" PRIx64 " ) => NONE", __FUNCTION__, (uint64_t)addr); 78 return LLDB_INVALID_BREAK_ID; 79 } 80 81 bool 82 BreakpointSiteList::Remove (lldb::break_id_t break_id) 83 { 84 Mutex::Locker locker(m_mutex); 85 collection::iterator pos = GetIDIterator(break_id); // Predicate 86 if (pos != m_bp_site_list.end()) 87 { 88 m_bp_site_list.erase(pos); 89 return true; 90 } 91 return false; 92 } 93 94 bool 95 BreakpointSiteList::RemoveByAddress (lldb::addr_t address) 96 { 97 Mutex::Locker locker(m_mutex); 98 collection::iterator pos = m_bp_site_list.find(address); 99 if (pos != m_bp_site_list.end()) 100 { 101 m_bp_site_list.erase(pos); 102 return true; 103 } 104 return false; 105 } 106 107 class BreakpointSiteIDMatches 108 { 109 public: 110 BreakpointSiteIDMatches (lldb::break_id_t break_id) : 111 m_break_id(break_id) 112 { 113 } 114 115 bool operator() (std::pair <lldb::addr_t, BreakpointSiteSP> val_pair) const 116 { 117 return m_break_id == val_pair.second.get()->GetID(); 118 } 119 120 private: 121 const lldb::break_id_t m_break_id; 122 }; 123 124 BreakpointSiteList::collection::iterator 125 BreakpointSiteList::GetIDIterator (lldb::break_id_t break_id) 126 { 127 Mutex::Locker locker(m_mutex); 128 return std::find_if(m_bp_site_list.begin(), m_bp_site_list.end(), // Search full range 129 BreakpointSiteIDMatches(break_id)); // Predicate 130 } 131 132 BreakpointSiteList::collection::const_iterator 133 BreakpointSiteList::GetIDConstIterator (lldb::break_id_t break_id) const 134 { 135 Mutex::Locker locker(m_mutex); 136 return std::find_if(m_bp_site_list.begin(), m_bp_site_list.end(), // Search full range 137 BreakpointSiteIDMatches(break_id)); // Predicate 138 } 139 140 BreakpointSiteSP 141 BreakpointSiteList::FindByID (lldb::break_id_t break_id) 142 { 143 Mutex::Locker locker(m_mutex); 144 BreakpointSiteSP stop_sp; 145 collection::iterator pos = GetIDIterator(break_id); 146 if (pos != m_bp_site_list.end()) 147 stop_sp = pos->second; 148 149 return stop_sp; 150 } 151 152 const BreakpointSiteSP 153 BreakpointSiteList::FindByID (lldb::break_id_t break_id) const 154 { 155 Mutex::Locker locker(m_mutex); 156 BreakpointSiteSP stop_sp; 157 collection::const_iterator pos = GetIDConstIterator(break_id); 158 if (pos != m_bp_site_list.end()) 159 stop_sp = pos->second; 160 161 return stop_sp; 162 } 163 164 BreakpointSiteSP 165 BreakpointSiteList::FindByAddress (lldb::addr_t addr) 166 { 167 BreakpointSiteSP found_sp; 168 Mutex::Locker locker(m_mutex); 169 collection::iterator iter = m_bp_site_list.find(addr); 170 if (iter != m_bp_site_list.end()) 171 found_sp = iter->second; 172 return found_sp; 173 } 174 175 bool 176 BreakpointSiteList::BreakpointSiteContainsBreakpoint (lldb::break_id_t bp_site_id, lldb::break_id_t bp_id) 177 { 178 Mutex::Locker locker(m_mutex); 179 collection::const_iterator pos = GetIDConstIterator(bp_site_id); 180 if (pos != m_bp_site_list.end()) 181 return pos->second->IsBreakpointAtThisSite (bp_id); 182 183 return false; 184 } 185 186 void 187 BreakpointSiteList::Dump (Stream *s) const 188 { 189 s->Printf("%p: ", this); 190 //s->Indent(); 191 s->Printf("BreakpointSiteList with %u BreakpointSites:\n", (uint32_t)m_bp_site_list.size()); 192 s->IndentMore(); 193 collection::const_iterator pos; 194 collection::const_iterator end = m_bp_site_list.end(); 195 for (pos = m_bp_site_list.begin(); pos != end; ++pos) 196 pos->second.get()->Dump(s); 197 s->IndentLess(); 198 } 199 200 void 201 BreakpointSiteList::ForEach (std::function <void(BreakpointSite *)> const &callback) 202 { 203 Mutex::Locker locker(m_mutex); 204 for (auto pair : m_bp_site_list) 205 callback (pair.second.get()); 206 } 207 208 bool 209 BreakpointSiteList::FindInRange (lldb::addr_t lower_bound, lldb::addr_t upper_bound, BreakpointSiteList &bp_site_list) const 210 { 211 if (lower_bound > upper_bound) 212 return false; 213 214 Mutex::Locker locker(m_mutex); 215 collection::const_iterator lower, upper, pos; 216 lower = m_bp_site_list.lower_bound(lower_bound); 217 if (lower == m_bp_site_list.end() 218 || (*lower).first >= upper_bound) 219 return false; 220 221 // This is one tricky bit. The breakpoint might overlap the bottom end of the range. So we grab the 222 // breakpoint prior to the lower bound, and check that that + its byte size isn't in our range. 223 if (lower != m_bp_site_list.begin()) 224 { 225 collection::const_iterator prev_pos = lower; 226 prev_pos--; 227 const BreakpointSiteSP &prev_bp = (*prev_pos).second; 228 if (prev_bp->GetLoadAddress() + prev_bp->GetByteSize() > lower_bound) 229 bp_site_list.Add (prev_bp); 230 231 } 232 233 upper = m_bp_site_list.upper_bound(upper_bound); 234 235 for (pos = lower; pos != upper; pos++) 236 { 237 bp_site_list.Add ((*pos).second); 238 } 239 return true; 240 } 241