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