1 //===-- StopPointSiteList.h -------------------------------------*- C++ -*-===// 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 #ifndef LLDB_BREAKPOINT_STOPPOINTSITELIST_H 10 #define LLDB_BREAKPOINT_STOPPOINTSITELIST_H 11 12 #include <functional> 13 #include <map> 14 #include <mutex> 15 16 #include <lldb/Breakpoint/BreakpointSite.h> 17 #include <lldb/Utility/Iterable.h> 18 #include <lldb/Utility/Stream.h> 19 20 namespace lldb_private { 21 22 template <typename StopPointSite> class StopPointSiteList { 23 // At present Process directly accesses the map of StopPointSites so it can 24 // do quick lookups into the map (using GetMap). 25 // FIXME: Find a better interface for this. 26 friend class Process; 27 28 public: 29 using StopPointSiteSP = std::shared_ptr<StopPointSite>; 30 31 /// Add a site to the list. 32 /// 33 /// \param[in] site_sp 34 /// A shared pointer to a site being added to the list. 35 /// 36 /// \return 37 /// The ID of the site in the list. 38 typename StopPointSite::SiteID Add(const StopPointSiteSP &site_sp) { 39 lldb::addr_t site_load_addr = site_sp->GetLoadAddress(); 40 std::lock_guard<std::recursive_mutex> guard(m_mutex); 41 // Add site to the list. However, if the element already exists in 42 // the list, then we don't add it, and return InvalidSiteID. 43 bool inserted = m_site_list.try_emplace(site_load_addr, site_sp).second; 44 return inserted ? site_sp->GetID() : UINT32_MAX; 45 } 46 47 /// Standard Dump routine, doesn't do anything at present. 48 /// \param[in] s 49 /// Stream into which to dump the description. 50 void Dump(Stream *s) const { 51 s->Printf("%p: ", static_cast<const void *>(this)); 52 s->Printf("StopPointSiteList with %u ConstituentSites:\n", 53 (uint32_t)m_site_list.size()); 54 s->IndentMore(); 55 typename collection::const_iterator pos; 56 typename collection::const_iterator end = m_site_list.end(); 57 for (pos = m_site_list.begin(); pos != end; ++pos) 58 pos->second->Dump(s); 59 s->IndentLess(); 60 } 61 62 /// Returns a shared pointer to the site at address \a addr. 63 /// 64 /// \param[in] addr 65 /// The address to look for. 66 /// 67 /// \result 68 /// A shared pointer to the site. Nullptr if no site contains 69 /// the address. 70 StopPointSiteSP FindByAddress(lldb::addr_t addr) { 71 StopPointSiteSP found_sp; 72 std::lock_guard<std::recursive_mutex> guard(m_mutex); 73 typename collection::iterator iter = m_site_list.find(addr); 74 if (iter != m_site_list.end()) 75 found_sp = iter->second; 76 return found_sp; 77 } 78 79 /// Returns a shared pointer to the site with id \a site_id. 80 /// 81 /// \param[in] site_id 82 /// The site ID to seek for. 83 /// 84 /// \result 85 /// A shared pointer to the site. Nullptr if no matching site. 86 StopPointSiteSP FindByID(typename StopPointSite::SiteID site_id) { 87 std::lock_guard<std::recursive_mutex> guard(m_mutex); 88 StopPointSiteSP stop_sp; 89 typename collection::iterator pos = GetIDIterator(site_id); 90 if (pos != m_site_list.end()) 91 stop_sp = pos->second; 92 93 return stop_sp; 94 } 95 96 /// Returns a shared pointer to the site with id \a site_id - 97 /// const version. 98 /// 99 /// \param[in] site_id 100 /// The site ID to seek for. 101 /// 102 /// \result 103 /// A shared pointer to the site. Nullptr if no matching site. 104 const StopPointSiteSP FindByID(typename StopPointSite::SiteID site_id) const { 105 std::lock_guard<std::recursive_mutex> guard(m_mutex); 106 StopPointSiteSP stop_sp; 107 typename collection::const_iterator pos = GetIDConstIterator(site_id); 108 if (pos != m_site_list.end()) 109 stop_sp = pos->second; 110 111 return stop_sp; 112 } 113 114 /// Returns the site id to the site at address \a addr. 115 /// 116 /// \param[in] addr 117 /// The address to match. 118 /// 119 /// \result 120 /// The ID of the site, or LLDB_INVALID_SITE_ID. 121 typename StopPointSite::SiteID FindIDByAddress(lldb::addr_t addr) { 122 if (StopPointSiteSP site = FindByAddress(addr)) 123 return site->GetID(); 124 return UINT32_MAX; 125 } 126 127 /// Returns whether the BreakpointSite \a site_id has a BreakpointLocation 128 /// that is part of Breakpoint \a bp_id. 129 /// 130 /// NB this is only defined when StopPointSiteList is specialized for 131 /// BreakpointSite's. 132 /// 133 /// \param[in] site_id 134 /// The site id to query. 135 /// 136 /// \param[in] bp_id 137 /// The breakpoint id to look for in \a site_id's BreakpointLocations. 138 /// 139 /// \result 140 /// True if \a site_id exists in the site list AND \a bp_id 141 /// is the breakpoint for one of the BreakpointLocations. 142 bool StopPointSiteContainsBreakpoint(typename StopPointSite::SiteID, 143 lldb::break_id_t bp_id); 144 145 void ForEach(std::function<void(StopPointSite *)> const &callback) { 146 std::lock_guard<std::recursive_mutex> guard(m_mutex); 147 for (auto pair : m_site_list) 148 callback(pair.second.get()); 149 } 150 151 /// Removes the site given by \a site_id from this list. 152 /// 153 /// \param[in] site_id 154 /// The site ID to remove. 155 /// 156 /// \result 157 /// \b true if the site \a site_id was in the list. 158 bool Remove(typename StopPointSite::SiteID site_id) { 159 std::lock_guard<std::recursive_mutex> guard(m_mutex); 160 typename collection::iterator pos = GetIDIterator(site_id); // Predicate 161 if (pos != m_site_list.end()) { 162 m_site_list.erase(pos); 163 return true; 164 } 165 return false; 166 } 167 168 /// Removes the site at address \a addr from this list. 169 /// 170 /// \param[in] addr 171 /// The address from which to remove a site. 172 /// 173 /// \result 174 /// \b true if \a addr had a site to remove from the list. 175 bool RemoveByAddress(lldb::addr_t addr) { 176 std::lock_guard<std::recursive_mutex> guard(m_mutex); 177 typename collection::iterator pos = m_site_list.find(addr); 178 if (pos != m_site_list.end()) { 179 m_site_list.erase(pos); 180 return true; 181 } 182 return false; 183 } 184 185 bool FindInRange(lldb::addr_t lower_bound, lldb::addr_t upper_bound, 186 StopPointSiteList &bp_site_list) const { 187 if (lower_bound > upper_bound) 188 return false; 189 190 std::lock_guard<std::recursive_mutex> guard(m_mutex); 191 typename collection::const_iterator lower, upper, pos; 192 lower = m_site_list.lower_bound(lower_bound); 193 if (lower == m_site_list.end() || (*lower).first >= upper_bound) 194 return false; 195 196 // This is one tricky bit. The site might overlap the bottom end of 197 // the range. So we grab the site prior to the lower bound, and check 198 // that that + its byte size isn't in our range. 199 if (lower != m_site_list.begin()) { 200 typename collection::const_iterator prev_pos = lower; 201 prev_pos--; 202 const StopPointSiteSP &prev_site = (*prev_pos).second; 203 if (prev_site->GetLoadAddress() + prev_site->GetByteSize() > lower_bound) 204 bp_site_list.Add(prev_site); 205 } 206 207 upper = m_site_list.upper_bound(upper_bound); 208 209 for (pos = lower; pos != upper; pos++) 210 bp_site_list.Add((*pos).second); 211 return true; 212 } 213 214 typedef void (*StopPointSiteSPMapFunc)(StopPointSite &site, void *baton); 215 216 /// Enquires of the site on in this list with ID \a site_id 217 /// whether we should stop for the constituent or not. 218 /// 219 /// \param[in] context 220 /// This contains the information about this stop. 221 /// 222 /// \param[in] site_id 223 /// This site ID that we hit. 224 /// 225 /// \return 226 /// \b true if we should stop, \b false otherwise. 227 bool ShouldStop(StoppointCallbackContext *context, 228 typename StopPointSite::SiteID site_id) { 229 if (StopPointSiteSP site_sp = FindByID(site_id)) { 230 // Let the site decide if it should stop here (could not have 231 // reached it's target hit count yet, or it could have a callback that 232 // decided it shouldn't stop (shared library loads/unloads). 233 return site_sp->ShouldStop(context); 234 } 235 // We should stop here since this site isn't valid anymore or it 236 // doesn't exist. 237 return true; 238 } 239 240 /// Returns the number of elements in the list. 241 /// 242 /// \result 243 /// The number of elements. 244 size_t GetSize() const { 245 std::lock_guard<std::recursive_mutex> guard(m_mutex); 246 return m_site_list.size(); 247 } 248 249 bool IsEmpty() const { 250 std::lock_guard<std::recursive_mutex> guard(m_mutex); 251 return m_site_list.empty(); 252 } 253 254 std::vector<StopPointSiteSP> Sites() { 255 std::vector<StopPointSiteSP> sites; 256 std::lock_guard<std::recursive_mutex> guard(m_mutex); 257 typename collection::iterator iter = m_site_list.begin(); 258 while (iter != m_site_list.end()) { 259 sites.push_back(iter->second); 260 ++iter; 261 } 262 263 return sites; 264 } 265 266 void Clear() { 267 std::lock_guard<std::recursive_mutex> guard(m_mutex); 268 m_site_list.clear(); 269 } 270 271 protected: 272 typedef std::map<lldb::addr_t, StopPointSiteSP> collection; 273 274 typename collection::iterator 275 GetIDIterator(typename StopPointSite::SiteID site_id) { 276 std::lock_guard<std::recursive_mutex> guard(m_mutex); 277 auto id_matches = 278 [site_id](const std::pair<lldb::addr_t, StopPointSiteSP> s) { 279 return site_id == s.second->GetID(); 280 }; 281 return std::find_if(m_site_list.begin(), 282 m_site_list.end(), // Search full range 283 id_matches); 284 } 285 286 typename collection::const_iterator 287 GetIDConstIterator(typename StopPointSite::SiteID site_id) const { 288 std::lock_guard<std::recursive_mutex> guard(m_mutex); 289 auto id_matches = 290 [site_id](const std::pair<lldb::addr_t, StopPointSiteSP> s) { 291 return site_id == s.second->GetID(); 292 }; 293 return std::find_if(m_site_list.begin(), 294 m_site_list.end(), // Search full range 295 id_matches); 296 } 297 298 mutable std::recursive_mutex m_mutex; 299 collection m_site_list; // The site list. 300 }; 301 302 } // namespace lldb_private 303 304 #endif // LLDB_BREAKPOINT_STOPPOINTSITELIST_H 305