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(format: "%p: ", static_cast<const void *>(this));
58 s->Printf(format: "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

source code of lldb/include/lldb/Breakpoint/StopPointSiteList.h