xref: /freebsd-src/contrib/llvm-project/lldb/include/lldb/Breakpoint/StopPointSiteList.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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.
Add(const StopPointSiteSP & site_sp)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.
Dump(Stream * s)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.
FindByAddress(lldb::addr_t addr)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.
FindByID(typename StopPointSite::SiteID site_id)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.
FindByID(typename StopPointSite::SiteID site_id)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.
FindIDByAddress(lldb::addr_t addr)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 
ForEach(std::function<void (StopPointSite *)> const & callback)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.
Remove(typename StopPointSite::SiteID site_id)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.
RemoveByAddress(lldb::addr_t addr)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 
FindInRange(lldb::addr_t lower_bound,lldb::addr_t upper_bound,StopPointSiteList & bp_site_list)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.
ShouldStop(StoppointCallbackContext * context,typename StopPointSite::SiteID site_id)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.
GetSize()250   size_t GetSize() const {
251     std::lock_guard<std::recursive_mutex> guard(m_mutex);
252     return m_site_list.size();
253   }
254 
IsEmpty()255   bool IsEmpty() const {
256     std::lock_guard<std::recursive_mutex> guard(m_mutex);
257     return m_site_list.empty();
258   }
259 
Sites()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 
Clear()272   void Clear() {
273     std::lock_guard<std::recursive_mutex> guard(m_mutex);
274     m_site_list.clear();
275   }
276 
277 protected:
278   typedef std::map<lldb::addr_t, StopPointSiteSP> collection;
279 
280   typename collection::iterator
GetIDIterator(typename StopPointSite::SiteID site_id)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
GetIDConstIterator(typename StopPointSite::SiteID site_id)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