File indexing completed on 2025-01-18 09:52:31
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_STACKTRACE_STACKTRACE_HPP
0008 #define BOOST_STACKTRACE_STACKTRACE_HPP
0009
0010 #include <boost/config.hpp>
0011 #ifdef BOOST_HAS_PRAGMA_ONCE
0012 # pragma once
0013 #endif
0014
0015 #include <boost/core/no_exceptions_support.hpp>
0016 #include <boost/container_hash/hash_fwd.hpp>
0017
0018 #include <iosfwd>
0019 #include <string>
0020 #include <vector>
0021
0022 #ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
0023 # include <type_traits>
0024 #endif
0025
0026 #include <boost/stacktrace/stacktrace_fwd.hpp>
0027 #include <boost/stacktrace/safe_dump_to.hpp>
0028 #include <boost/stacktrace/detail/frame_decl.hpp>
0029 #include <boost/stacktrace/frame.hpp>
0030
0031 #ifdef BOOST_INTEL
0032 # pragma warning(push)
0033 # pragma warning(disable:2196)
0034 #endif
0035
0036 namespace boost { namespace stacktrace {
0037
0038
0039
0040 template <class Allocator>
0041 class basic_stacktrace {
0042 std::vector<boost::stacktrace::frame, Allocator> impl_;
0043 typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
0044
0045
0046 void fill(native_frame_ptr_t* begin, std::size_t size) {
0047 if (!size) {
0048 return;
0049 }
0050
0051 impl_.reserve(static_cast<std::size_t>(size));
0052 for (std::size_t i = 0; i < size; ++i) {
0053 if (!begin[i]) {
0054 return;
0055 }
0056 impl_.push_back(
0057 frame(begin[i])
0058 );
0059 }
0060 }
0061
0062 static std::size_t frames_count_from_buffer_size(std::size_t buffer_size) noexcept {
0063 const std::size_t ret = (buffer_size > sizeof(native_frame_ptr_t) ? buffer_size / sizeof(native_frame_ptr_t) : 0);
0064 return (ret > 1024 ? 1024 : ret);
0065 }
0066
0067 BOOST_NOINLINE void init(std::size_t frames_to_skip, std::size_t max_depth) {
0068 BOOST_CONSTEXPR_OR_CONST std::size_t buffer_size = 128;
0069 if (!max_depth) {
0070 return;
0071 }
0072
0073 BOOST_TRY {
0074 {
0075 native_frame_ptr_t buffer[buffer_size];
0076 const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, buffer_size < max_depth ? buffer_size : max_depth, frames_to_skip + 1);
0077 if (buffer_size > frames_count || frames_count == max_depth) {
0078 fill(buffer, frames_count);
0079 return;
0080 }
0081 }
0082
0083
0084 #ifdef BOOST_NO_CXX11_ALLOCATOR
0085 typedef typename Allocator::template rebind<native_frame_ptr_t>::other allocator_void_t;
0086 #else
0087 typedef typename std::allocator_traits<Allocator>::template rebind_alloc<native_frame_ptr_t> allocator_void_t;
0088 #endif
0089 std::vector<native_frame_ptr_t, allocator_void_t> buf(buffer_size * 2, 0, impl_.get_allocator());
0090 do {
0091 const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(&buf[0], buf.size() < max_depth ? buf.size() : max_depth, frames_to_skip + 1);
0092 if (buf.size() > frames_count || frames_count == max_depth) {
0093 fill(&buf[0], frames_count);
0094 return;
0095 }
0096
0097 buf.resize(buf.size() * 2);
0098 } while (buf.size() < buf.max_size());
0099 } BOOST_CATCH (...) {
0100
0101 }
0102 BOOST_CATCH_END
0103 }
0104
0105
0106 public:
0107 typedef typename std::vector<boost::stacktrace::frame, Allocator>::value_type value_type;
0108 typedef typename std::vector<boost::stacktrace::frame, Allocator>::allocator_type allocator_type;
0109 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_pointer pointer;
0110 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_pointer const_pointer;
0111 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reference reference;
0112 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reference const_reference;
0113 typedef typename std::vector<boost::stacktrace::frame, Allocator>::size_type size_type;
0114 typedef typename std::vector<boost::stacktrace::frame, Allocator>::difference_type difference_type;
0115 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_iterator iterator;
0116 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_iterator const_iterator;
0117 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reverse_iterator reverse_iterator;
0118 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reverse_iterator const_reverse_iterator;
0119
0120
0121
0122
0123
0124
0125 BOOST_FORCEINLINE basic_stacktrace() noexcept
0126 : impl_()
0127 {
0128 init(0 , static_cast<std::size_t>(-1));
0129 }
0130
0131
0132
0133
0134
0135
0136
0137
0138 BOOST_FORCEINLINE explicit basic_stacktrace(const allocator_type& a) noexcept
0139 : impl_(a)
0140 {
0141 init(0 , static_cast<std::size_t>(-1));
0142 }
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158 BOOST_FORCEINLINE basic_stacktrace(std::size_t skip, std::size_t max_depth, const allocator_type& a = allocator_type()) noexcept
0159 : impl_(a)
0160 {
0161 init(skip , max_depth);
0162 }
0163
0164
0165
0166
0167 basic_stacktrace(const basic_stacktrace& st)
0168 : impl_(st.impl_)
0169 {}
0170
0171
0172
0173
0174 basic_stacktrace& operator=(const basic_stacktrace& st) {
0175 impl_ = st.impl_;
0176 return *this;
0177 }
0178
0179 #ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
0180
0181
0182
0183 ~basic_stacktrace() noexcept = default;
0184 #endif
0185
0186 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
0187
0188
0189
0190 basic_stacktrace(basic_stacktrace&& st) noexcept
0191 : impl_(std::move(st.impl_))
0192 {}
0193
0194
0195
0196
0197 basic_stacktrace& operator=(basic_stacktrace&& st)
0198 #ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
0199 noexcept(( std::is_nothrow_move_assignable< std::vector<boost::stacktrace::frame, Allocator> >::value ))
0200 #else
0201 noexcept
0202 #endif
0203 {
0204 impl_ = std::move(st.impl_);
0205 return *this;
0206 }
0207 #endif
0208
0209
0210
0211
0212
0213
0214 size_type size() const noexcept {
0215 return impl_.size();
0216 }
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226 const_reference operator[](std::size_t frame_no) const noexcept {
0227 return impl_[frame_no];
0228 }
0229
0230
0231
0232
0233 const_iterator begin() const noexcept { return impl_.begin(); }
0234
0235
0236
0237 const_iterator cbegin() const noexcept { return impl_.begin(); }
0238
0239
0240
0241 const_iterator end() const noexcept { return impl_.end(); }
0242
0243
0244
0245 const_iterator cend() const noexcept { return impl_.end(); }
0246
0247
0248
0249
0250 const_reverse_iterator rbegin() const noexcept { return impl_.rbegin(); }
0251
0252
0253
0254 const_reverse_iterator crbegin() const noexcept { return impl_.rbegin(); }
0255
0256
0257
0258 const_reverse_iterator rend() const noexcept { return impl_.rend(); }
0259
0260
0261
0262 const_reverse_iterator crend() const noexcept { return impl_.rend(); }
0263
0264
0265
0266
0267
0268
0269
0270
0271 constexpr explicit operator bool () const noexcept { return !empty(); }
0272
0273
0274
0275
0276
0277
0278
0279 bool empty() const noexcept { return !size(); }
0280
0281 const std::vector<boost::stacktrace::frame, Allocator>& as_vector() const noexcept {
0282 return impl_;
0283 }
0284
0285
0286
0287
0288 template <class Char, class Trait>
0289 static basic_stacktrace from_dump(std::basic_istream<Char, Trait>& in, const allocator_type& a = allocator_type()) {
0290 typedef typename std::basic_istream<Char, Trait>::pos_type pos_type;
0291 basic_stacktrace ret(0, 0, a);
0292
0293
0294 const pos_type pos = in.tellg();
0295 in.seekg(0, in.end);
0296 const std::size_t frames_count = frames_count_from_buffer_size(static_cast<std::size_t>(in.tellg()));
0297 in.seekg(pos);
0298
0299 if (!frames_count) {
0300 return ret;
0301 }
0302
0303 native_frame_ptr_t ptr = 0;
0304 ret.impl_.reserve(frames_count);
0305 while (in.read(reinterpret_cast<Char*>(&ptr), sizeof(ptr))) {
0306 if (!ptr) {
0307 break;
0308 }
0309
0310 ret.impl_.push_back(frame(ptr));
0311 }
0312
0313 return ret;
0314 }
0315
0316
0317
0318
0319
0320
0321
0322
0323 static basic_stacktrace from_dump(const void* begin, std::size_t buffer_size_in_bytes, const allocator_type& a = allocator_type()) {
0324 basic_stacktrace ret(0, 0, a);
0325 const native_frame_ptr_t* first = static_cast<const native_frame_ptr_t*>(begin);
0326 const std::size_t frames_count = frames_count_from_buffer_size(buffer_size_in_bytes);
0327 if (!frames_count) {
0328 return ret;
0329 }
0330
0331 const native_frame_ptr_t* const last = first + frames_count;
0332 ret.impl_.reserve(frames_count);
0333 for (; first != last; ++first) {
0334 if (!*first) {
0335 break;
0336 }
0337
0338 ret.impl_.push_back(frame(*first));
0339 }
0340
0341 return ret;
0342 }
0343 };
0344
0345
0346
0347
0348
0349
0350 template <class Allocator1, class Allocator2>
0351 bool operator< (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
0352 return lhs.size() < rhs.size() || (lhs.size() == rhs.size() && lhs.as_vector() < rhs.as_vector());
0353 }
0354
0355
0356
0357
0358
0359
0360 template <class Allocator1, class Allocator2>
0361 bool operator==(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
0362 return lhs.as_vector() == rhs.as_vector();
0363 }
0364
0365
0366
0367 template <class Allocator1, class Allocator2>
0368 bool operator> (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
0369 return rhs < lhs;
0370 }
0371
0372 template <class Allocator1, class Allocator2>
0373 bool operator<=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
0374 return !(lhs > rhs);
0375 }
0376
0377 template <class Allocator1, class Allocator2>
0378 bool operator>=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
0379 return !(lhs < rhs);
0380 }
0381
0382 template <class Allocator1, class Allocator2>
0383 bool operator!=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
0384 return !(lhs == rhs);
0385 }
0386
0387
0388 template <class Allocator>
0389 std::size_t hash_value(const basic_stacktrace<Allocator>& st) noexcept {
0390 return boost::hash_range(st.as_vector().begin(), st.as_vector().end());
0391 }
0392
0393
0394 template <class Allocator>
0395 std::string to_string(const basic_stacktrace<Allocator>& bt) {
0396 if (!bt) {
0397 return std::string();
0398 }
0399
0400 return boost::stacktrace::detail::to_string(&bt.as_vector()[0], bt.size());
0401 }
0402
0403
0404 template <class CharT, class TraitsT, class Allocator>
0405 std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt) {
0406 return os << boost::stacktrace::to_string(bt);
0407 }
0408
0409
0410 typedef basic_stacktrace<> stacktrace;
0411
0412 }}
0413
0414 #ifdef BOOST_INTEL
0415 # pragma warning(pop)
0416 #endif
0417
0418 #endif