]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/stacktrace/stacktrace.hpp
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / boost / boost / stacktrace / stacktrace.hpp
1 // Copyright Antony Polukhin, 2016-2017.
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6
7 #ifndef BOOST_STACKTRACE_STACKTRACE_HPP
8 #define BOOST_STACKTRACE_STACKTRACE_HPP
9
10 #include <boost/config.hpp>
11 #ifdef BOOST_HAS_PRAGMA_ONCE
12 # pragma once
13 #endif
14
15 #include <boost/core/explicit_operator_bool.hpp>
16 #include <boost/container_hash/hash_fwd.hpp>
17
18 #include <iosfwd>
19 #include <string>
20 #include <vector>
21
22 #ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
23 # include <type_traits>
24 #endif
25
26 #include <boost/stacktrace/stacktrace_fwd.hpp>
27 #include <boost/stacktrace/safe_dump_to.hpp>
28 #include <boost/stacktrace/detail/frame_decl.hpp>
29
30 #ifdef BOOST_INTEL
31 # pragma warning(push)
32 # pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
33 #endif
34
35 namespace boost { namespace stacktrace {
36
37 /// Class that on construction copies minimal information about call stack into its internals and provides access to that information.
38 /// @tparam Allocator Allocator to use during stack capture.
39 template <class Allocator>
40 class basic_stacktrace {
41 std::vector<boost::stacktrace::frame, Allocator> impl_;
42 typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
43
44 /// @cond
45 void fill(native_frame_ptr_t* begin, std::size_t size) {
46 if (!size) {
47 return;
48 }
49
50 impl_.reserve(static_cast<std::size_t>(size));
51 for (std::size_t i = 0; i < size; ++i) {
52 if (!begin[i]) {
53 return;
54 }
55 impl_.push_back(
56 frame(begin[i])
57 );
58 }
59 }
60
61 static std::size_t frames_count_from_buffer_size(std::size_t buffer_size) BOOST_NOEXCEPT {
62 const std::size_t ret = (buffer_size > sizeof(native_frame_ptr_t) ? buffer_size / sizeof(native_frame_ptr_t) : 0);
63 return (ret > 1024 ? 1024 : ret); // Dealing with suspiciously big sizes
64 }
65
66 BOOST_NOINLINE void init(std::size_t frames_to_skip, std::size_t max_depth) {
67 BOOST_CONSTEXPR_OR_CONST std::size_t buffer_size = 128;
68 if (!max_depth) {
69 return;
70 }
71
72 try {
73 { // Fast path without additional allocations
74 native_frame_ptr_t buffer[buffer_size];
75 const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, buffer_size, frames_to_skip + 1);
76 if (buffer_size > frames_count || frames_count >= max_depth) {
77 const std::size_t size = (max_depth < frames_count ? max_depth : frames_count);
78 fill(buffer, size);
79 return;
80 }
81 }
82
83 // Failed to fit in `buffer_size`. Allocating memory:
84 #ifdef BOOST_NO_CXX11_ALLOCATOR
85 typedef typename Allocator::template rebind<native_frame_ptr_t>::other allocator_void_t;
86 #else
87 typedef typename std::allocator_traits<Allocator>::template rebind_alloc<native_frame_ptr_t> allocator_void_t;
88 #endif
89 std::vector<native_frame_ptr_t, allocator_void_t> buf(buffer_size * 2, 0, impl_.get_allocator());
90 do {
91 const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(&buf[0], buf.size(), frames_to_skip + 1);
92 if (buf.size() > frames_count || frames_count >= max_depth) {
93 const std::size_t size = (max_depth < frames_count ? max_depth : frames_count);
94 fill(&buf[0], size);
95 return;
96 }
97
98 buf.resize(buf.size() * 2);
99 } while (buf.size() < buf.max_size()); // close to `true`, but suppresses `C4127: conditional expression is constant`.
100 } catch (...) {
101 // ignore exception
102 }
103 }
104 /// @endcond
105
106 public:
107 typedef typename std::vector<boost::stacktrace::frame, Allocator>::value_type value_type;
108 typedef typename std::vector<boost::stacktrace::frame, Allocator>::allocator_type allocator_type;
109 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_pointer pointer;
110 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_pointer const_pointer;
111 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reference reference;
112 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reference const_reference;
113 typedef typename std::vector<boost::stacktrace::frame, Allocator>::size_type size_type;
114 typedef typename std::vector<boost::stacktrace::frame, Allocator>::difference_type difference_type;
115 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_iterator iterator;
116 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_iterator const_iterator;
117 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reverse_iterator reverse_iterator;
118 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reverse_iterator const_reverse_iterator;
119
120 /// @brief Stores the current function call sequence inside *this without any decoding or any other heavy platform specific operations.
121 ///
122 /// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
123 ///
124 /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
125 BOOST_FORCEINLINE basic_stacktrace() BOOST_NOEXCEPT
126 : impl_()
127 {
128 init(0 , static_cast<std::size_t>(-1));
129 }
130
131 /// @brief Stores the current function call sequence inside *this without any decoding or any other heavy platform specific operations.
132 ///
133 /// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
134 ///
135 /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
136 ///
137 /// @param a Allocator that would be passed to underlying storeage.
138 BOOST_FORCEINLINE explicit basic_stacktrace(const allocator_type& a) BOOST_NOEXCEPT
139 : impl_(a)
140 {
141 init(0 , static_cast<std::size_t>(-1));
142 }
143
144 /// @brief Stores [skip, skip + max_depth) of the current function call sequence inside *this without any decoding or any other heavy platform specific operations.
145 ///
146 /// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
147 ///
148 /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
149 ///
150 /// @param skip How many top calls to skip and do not store in *this.
151 ///
152 /// @param max_depth Max call sequence depth to collect.
153 ///
154 /// @param a Allocator that would be passed to underlying storeage.
155 ///
156 /// @throws Nothing. Note that default construction of allocator may throw, however it is
157 /// performed outside the constructor and exception in `allocator_type()` would not result in calling `std::terminate`.
158 BOOST_FORCEINLINE basic_stacktrace(std::size_t skip, std::size_t max_depth, const allocator_type& a = allocator_type()) BOOST_NOEXCEPT
159 : impl_(a)
160 {
161 init(skip , max_depth);
162 }
163
164 /// @b Complexity: O(st.size())
165 ///
166 /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
167 basic_stacktrace(const basic_stacktrace& st)
168 : impl_(st.impl_)
169 {}
170
171 /// @b Complexity: O(st.size())
172 ///
173 /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
174 basic_stacktrace& operator=(const basic_stacktrace& st) {
175 impl_ = st.impl_;
176 return *this;
177 }
178
179 #ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
180 /// @b Complexity: O(1)
181 ///
182 /// @b Async-Handler-Safety: Safe if Allocator::deallocate is async signal safe.
183 ~basic_stacktrace() BOOST_NOEXCEPT = default;
184 #endif
185
186 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
187 /// @b Complexity: O(1)
188 ///
189 /// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe.
190 basic_stacktrace(basic_stacktrace&& st) BOOST_NOEXCEPT
191 : impl_(std::move(st.impl_))
192 {}
193
194 /// @b Complexity: O(st.size())
195 ///
196 /// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe.
197 basic_stacktrace& operator=(basic_stacktrace&& st)
198 #ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
199 BOOST_NOEXCEPT_IF(( std::is_nothrow_move_assignable< std::vector<boost::stacktrace::frame, Allocator> >::value ))
200 #else
201 BOOST_NOEXCEPT
202 #endif
203 {
204 impl_ = std::move(st.impl_);
205 return *this;
206 }
207 #endif
208
209 /// @returns Number of function names stored inside the class.
210 ///
211 /// @b Complexity: O(1)
212 ///
213 /// @b Async-Handler-Safety: Safe.
214 size_type size() const BOOST_NOEXCEPT {
215 return impl_.size();
216 }
217
218 /// @param frame_no Zero based index of frame to return. 0
219 /// is the function index where stacktrace was constructed and
220 /// index close to this->size() contains function `main()`.
221 /// @returns frame that references the actual frame info, stored inside *this.
222 ///
223 /// @b Complexity: O(1).
224 ///
225 /// @b Async-Handler-Safety: Safe.
226 const_reference operator[](std::size_t frame_no) const BOOST_NOEXCEPT {
227 return impl_[frame_no];
228 }
229
230 /// @b Complexity: O(1)
231 ///
232 /// @b Async-Handler-Safety: Safe.
233 const_iterator begin() const BOOST_NOEXCEPT { return impl_.begin(); }
234 /// @b Complexity: O(1)
235 ///
236 /// @b Async-Handler-Safety: Safe.
237 const_iterator cbegin() const BOOST_NOEXCEPT { return impl_.begin(); }
238 /// @b Complexity: O(1)
239 ///
240 /// @b Async-Handler-Safety: Safe.
241 const_iterator end() const BOOST_NOEXCEPT { return impl_.end(); }
242 /// @b Complexity: O(1)
243 ///
244 /// @b Async-Handler-Safety: Safe.
245 const_iterator cend() const BOOST_NOEXCEPT { return impl_.end(); }
246
247 /// @b Complexity: O(1)
248 ///
249 /// @b Async-Handler-Safety: Safe.
250 const_reverse_iterator rbegin() const BOOST_NOEXCEPT { return impl_.rbegin(); }
251 /// @b Complexity: O(1)
252 ///
253 /// @b Async-Handler-Safety: Safe.
254 const_reverse_iterator crbegin() const BOOST_NOEXCEPT { return impl_.rbegin(); }
255 /// @b Complexity: O(1)
256 ///
257 /// @b Async-Handler-Safety: Safe.
258 const_reverse_iterator rend() const BOOST_NOEXCEPT { return impl_.rend(); }
259 /// @b Complexity: O(1)
260 ///
261 /// @b Async-Handler-Safety: Safe.
262 const_reverse_iterator crend() const BOOST_NOEXCEPT { return impl_.rend(); }
263
264
265 /// @brief Allows to check that stack trace capturing was successful.
266 /// @returns `true` if `this->size() != 0`
267 ///
268 /// @b Complexity: O(1)
269 ///
270 /// @b Async-Handler-Safety: Safe.
271 BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
272
273 /// @brief Allows to check that stack trace failed.
274 /// @returns `true` if `this->size() == 0`
275 ///
276 /// @b Complexity: O(1)
277 ///
278 /// @b Async-Handler-Safety: Safe.
279 bool empty() const BOOST_NOEXCEPT { return !size(); }
280
281 /// @cond
282 bool operator!() const BOOST_NOEXCEPT { return !size(); }
283 /// @endcond
284
285 const std::vector<boost::stacktrace::frame, Allocator>& as_vector() const BOOST_NOEXCEPT {
286 return impl_;
287 }
288
289 /// Constructs stacktrace from basic_istreamable that references the dumped stacktrace. Terminating zero frame is discarded.
290 ///
291 /// @b Complexity: O(N)
292 template <class Char, class Trait>
293 static basic_stacktrace from_dump(std::basic_istream<Char, Trait>& in, const allocator_type& a = allocator_type()) {
294 typedef typename std::basic_istream<Char, Trait>::pos_type pos_type;
295 basic_stacktrace ret(0, 0, a);
296
297 // reserving space
298 const pos_type pos = in.tellg();
299 in.seekg(0, in.end);
300 const std::size_t frames_count = frames_count_from_buffer_size(static_cast<std::size_t>(in.tellg()));
301 in.seekg(pos);
302
303 if (!frames_count) {
304 return ret;
305 }
306
307 native_frame_ptr_t ptr = 0;
308 ret.impl_.reserve(frames_count);
309 while (in.read(reinterpret_cast<Char*>(&ptr), sizeof(ptr))) {
310 if (!ptr) {
311 break;
312 }
313
314 ret.impl_.push_back(frame(ptr));
315 }
316
317 return ret;
318 }
319
320 /// Constructs stacktrace from raw memory dump. Terminating zero frame is discarded.
321 ///
322 /// @b Complexity: O(size) in worst case
323 static basic_stacktrace from_dump(const void* begin, std::size_t buffer_size_in_bytes, const allocator_type& a = allocator_type()) {
324 basic_stacktrace ret(0, 0, a);
325 const native_frame_ptr_t* first = static_cast<const native_frame_ptr_t*>(begin);
326 const std::size_t frames_count = frames_count_from_buffer_size(buffer_size_in_bytes);
327 if (!frames_count) {
328 return ret;
329 }
330
331 const native_frame_ptr_t* const last = first + frames_count;
332 ret.impl_.reserve(frames_count);
333 for (; first != last; ++first) {
334 if (!*first) {
335 break;
336 }
337
338 ret.impl_.push_back(frame(*first));
339 }
340
341 return ret;
342 }
343 };
344
345 /// @brief Compares stacktraces for less, order is platform dependent.
346 ///
347 /// @b Complexity: Amortized O(1); worst case O(size())
348 ///
349 /// @b Async-Handler-Safety: Safe.
350 template <class Allocator1, class Allocator2>
351 bool operator< (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
352 return lhs.size() < rhs.size() || (lhs.size() == rhs.size() && lhs.as_vector() < rhs.as_vector());
353 }
354
355 /// @brief Compares stacktraces for equality.
356 ///
357 /// @b Complexity: Amortized O(1); worst case O(size())
358 ///
359 /// @b Async-Handler-Safety: Safe.
360 template <class Allocator1, class Allocator2>
361 bool operator==(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
362 return lhs.as_vector() == rhs.as_vector();
363 }
364
365
366 /// Comparison operators that provide platform dependant ordering and have amortized O(1) complexity; O(size()) worst case complexity; are Async-Handler-Safe.
367 template <class Allocator1, class Allocator2>
368 bool operator> (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
369 return rhs < lhs;
370 }
371
372 template <class Allocator1, class Allocator2>
373 bool operator<=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
374 return !(lhs > rhs);
375 }
376
377 template <class Allocator1, class Allocator2>
378 bool operator>=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
379 return !(lhs < rhs);
380 }
381
382 template <class Allocator1, class Allocator2>
383 bool operator!=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
384 return !(lhs == rhs);
385 }
386
387 /// Fast hashing support, O(st.size()) complexity; Async-Handler-Safe.
388 template <class Allocator>
389 std::size_t hash_value(const basic_stacktrace<Allocator>& st) BOOST_NOEXCEPT {
390 return boost::hash_range(st.as_vector().begin(), st.as_vector().end());
391 }
392
393 /// Outputs stacktrace in a human readable format to output stream; unsafe to use in async handlers.
394 template <class CharT, class TraitsT, class Allocator>
395 std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt) {
396 if (bt) {
397 os << boost::stacktrace::detail::to_string(&bt.as_vector()[0], bt.size());
398 }
399
400 return os;
401 }
402
403 /// This is the typedef to use unless you'd like to provide a specific allocator to boost::stacktrace::basic_stacktrace.
404 typedef basic_stacktrace<> stacktrace;
405
406 }} // namespace boost::stacktrace
407
408 #ifdef BOOST_INTEL
409 # pragma warning(pop)
410 #endif
411
412 #endif // BOOST_STACKTRACE_STACKTRACE_HPP