xref: /llvm-project/lldb/include/lldb/Breakpoint/StopPointSiteList.h (revision bad04dc6da187bc0af3b27b882201bab6f90c5f0)
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