File indexing completed on 2025-07-09 08:27:17
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 #if defined(BOOST_MSVC)
0037
0038 extern "C" {
0039
0040 BOOST_SYMBOL_EXPORT inline void* boost_stacktrace_impl_return_nullptr() { return nullptr; }
0041 const char* boost_stacktrace_impl_current_exception_stacktrace();
0042 bool* boost_stacktrace_impl_ref_capture_stacktraces_at_throw();
0043
0044 }
0045
0046 #ifdef _M_IX86
0047 # pragma comment(linker, "/ALTERNATENAME:_boost_stacktrace_impl_current_exception_stacktrace=_boost_stacktrace_impl_return_nullptr")
0048 # pragma comment(linker, "/ALTERNATENAME:_boost_stacktrace_impl_ref_capture_stacktraces_at_throw=_boost_stacktrace_impl_return_nullptr")
0049 #else
0050 # pragma comment(linker, "/ALTERNATENAME:boost_stacktrace_impl_current_exception_stacktrace=boost_stacktrace_impl_return_nullptr")
0051 # pragma comment(linker, "/ALTERNATENAME:boost_stacktrace_impl_ref_capture_stacktraces_at_throw=boost_stacktrace_impl_return_nullptr")
0052 #endif
0053
0054 #endif
0055
0056 namespace boost { namespace stacktrace {
0057
0058 namespace impl {
0059
0060 #if defined(__GNUC__) && defined(__ELF__)
0061
0062 BOOST_NOINLINE BOOST_SYMBOL_VISIBLE __attribute__((weak))
0063 const char* current_exception_stacktrace() noexcept;
0064
0065 BOOST_NOINLINE BOOST_SYMBOL_VISIBLE __attribute__((weak))
0066 bool& ref_capture_stacktraces_at_throw() noexcept;
0067
0068 #endif
0069
0070 }
0071
0072
0073
0074 template <class Allocator>
0075 class basic_stacktrace {
0076 std::vector<boost::stacktrace::frame, Allocator> impl_;
0077 typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
0078
0079
0080 void fill(native_frame_ptr_t* begin, std::size_t size) {
0081 if (!size) {
0082 return;
0083 }
0084
0085 impl_.reserve(static_cast<std::size_t>(size));
0086 for (std::size_t i = 0; i < size; ++i) {
0087 if (!begin[i]) {
0088 return;
0089 }
0090 impl_.push_back(
0091 frame(begin[i])
0092 );
0093 }
0094 }
0095
0096 static std::size_t frames_count_from_buffer_size(std::size_t buffer_size) noexcept {
0097 const std::size_t ret = (buffer_size > sizeof(native_frame_ptr_t) ? buffer_size / sizeof(native_frame_ptr_t) : 0);
0098 return (ret > 1024 ? 1024 : ret);
0099 }
0100
0101 BOOST_NOINLINE void init(std::size_t frames_to_skip, std::size_t max_depth) {
0102 constexpr std::size_t buffer_size = 128;
0103 if (!max_depth) {
0104 return;
0105 }
0106
0107 BOOST_TRY {
0108 {
0109 native_frame_ptr_t buffer[buffer_size];
0110 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);
0111 if (buffer_size > frames_count || frames_count == max_depth) {
0112 fill(buffer, frames_count);
0113 return;
0114 }
0115 }
0116
0117
0118 #ifdef BOOST_NO_CXX11_ALLOCATOR
0119 typedef typename Allocator::template rebind<native_frame_ptr_t>::other allocator_void_t;
0120 #else
0121 typedef typename std::allocator_traits<Allocator>::template rebind_alloc<native_frame_ptr_t> allocator_void_t;
0122 #endif
0123 std::vector<native_frame_ptr_t, allocator_void_t> buf(buffer_size * 2, 0, impl_.get_allocator());
0124 do {
0125 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);
0126 if (buf.size() > frames_count || frames_count == max_depth) {
0127 fill(&buf[0], frames_count);
0128 return;
0129 }
0130
0131 buf.resize(buf.size() * 2);
0132 } while (buf.size() < buf.max_size());
0133 } BOOST_CATCH (...) {
0134
0135 }
0136 BOOST_CATCH_END
0137 }
0138
0139
0140 public:
0141 typedef typename std::vector<boost::stacktrace::frame, Allocator>::value_type value_type;
0142 typedef typename std::vector<boost::stacktrace::frame, Allocator>::allocator_type allocator_type;
0143 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_pointer pointer;
0144 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_pointer const_pointer;
0145 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reference reference;
0146 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reference const_reference;
0147 typedef typename std::vector<boost::stacktrace::frame, Allocator>::size_type size_type;
0148 typedef typename std::vector<boost::stacktrace::frame, Allocator>::difference_type difference_type;
0149 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_iterator iterator;
0150 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_iterator const_iterator;
0151 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reverse_iterator reverse_iterator;
0152 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reverse_iterator const_reverse_iterator;
0153
0154
0155
0156
0157
0158
0159 BOOST_FORCEINLINE basic_stacktrace() noexcept
0160 : impl_()
0161 {
0162 init(0 , static_cast<std::size_t>(-1));
0163 }
0164
0165
0166
0167
0168
0169
0170
0171
0172 BOOST_FORCEINLINE explicit basic_stacktrace(const allocator_type& a) noexcept
0173 : impl_(a)
0174 {
0175 init(0 , static_cast<std::size_t>(-1));
0176 }
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192 BOOST_FORCEINLINE basic_stacktrace(std::size_t skip, std::size_t max_depth, const allocator_type& a = allocator_type()) noexcept
0193 : impl_(a)
0194 {
0195 init(skip , max_depth);
0196 }
0197
0198
0199
0200
0201 basic_stacktrace(const basic_stacktrace& st)
0202 : impl_(st.impl_)
0203 {}
0204
0205
0206
0207
0208 basic_stacktrace& operator=(const basic_stacktrace& st) {
0209 impl_ = st.impl_;
0210 return *this;
0211 }
0212
0213 #ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
0214
0215
0216
0217 ~basic_stacktrace() noexcept = default;
0218 #endif
0219
0220 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
0221
0222
0223
0224 basic_stacktrace(basic_stacktrace&& st) noexcept
0225 : impl_(std::move(st.impl_))
0226 {}
0227
0228
0229
0230
0231 basic_stacktrace& operator=(basic_stacktrace&& st)
0232 #ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
0233 noexcept(( std::is_nothrow_move_assignable< std::vector<boost::stacktrace::frame, Allocator> >::value ))
0234 #else
0235 noexcept
0236 #endif
0237 {
0238 impl_ = std::move(st.impl_);
0239 return *this;
0240 }
0241 #endif
0242
0243
0244
0245
0246
0247
0248 size_type size() const noexcept {
0249 return impl_.size();
0250 }
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260 const_reference operator[](std::size_t frame_no) const noexcept {
0261 return impl_[frame_no];
0262 }
0263
0264
0265
0266
0267 const_iterator begin() const noexcept { return impl_.begin(); }
0268
0269
0270
0271 const_iterator cbegin() const noexcept { return impl_.begin(); }
0272
0273
0274
0275 const_iterator end() const noexcept { return impl_.end(); }
0276
0277
0278
0279 const_iterator cend() const noexcept { return impl_.end(); }
0280
0281
0282
0283
0284 const_reverse_iterator rbegin() const noexcept { return impl_.rbegin(); }
0285
0286
0287
0288 const_reverse_iterator crbegin() const noexcept { return impl_.rbegin(); }
0289
0290
0291
0292 const_reverse_iterator rend() const noexcept { return impl_.rend(); }
0293
0294
0295
0296 const_reverse_iterator crend() const noexcept { return impl_.rend(); }
0297
0298
0299
0300
0301
0302
0303
0304
0305 constexpr explicit operator bool () const noexcept { return !empty(); }
0306
0307
0308
0309
0310
0311
0312
0313 bool empty() const noexcept { return !size(); }
0314
0315 const std::vector<boost::stacktrace::frame, Allocator>& as_vector() const noexcept {
0316 return impl_;
0317 }
0318
0319
0320
0321
0322 template <class Char, class Trait>
0323 static basic_stacktrace from_dump(std::basic_istream<Char, Trait>& in, const allocator_type& a = allocator_type()) {
0324 typedef typename std::basic_istream<Char, Trait>::pos_type pos_type;
0325 basic_stacktrace ret(0, 0, a);
0326
0327
0328 const pos_type pos = in.tellg();
0329 in.seekg(0, in.end);
0330 const std::size_t frames_count = frames_count_from_buffer_size(static_cast<std::size_t>(in.tellg()));
0331 in.seekg(pos);
0332
0333 if (!frames_count) {
0334 return ret;
0335 }
0336
0337 native_frame_ptr_t ptr = 0;
0338 ret.impl_.reserve(frames_count);
0339 while (in.read(reinterpret_cast<Char*>(&ptr), sizeof(ptr))) {
0340 if (!ptr) {
0341 break;
0342 }
0343
0344 ret.impl_.push_back(frame(ptr));
0345 }
0346
0347 return ret;
0348 }
0349
0350
0351
0352
0353
0354
0355
0356
0357 static basic_stacktrace from_dump(const void* begin, std::size_t buffer_size_in_bytes, const allocator_type& a = allocator_type()) {
0358 basic_stacktrace ret(0, 0, a);
0359 const native_frame_ptr_t* first = static_cast<const native_frame_ptr_t*>(begin);
0360 const std::size_t frames_count = frames_count_from_buffer_size(buffer_size_in_bytes);
0361 if (!frames_count) {
0362 return ret;
0363 }
0364
0365 const native_frame_ptr_t* const last = first + frames_count;
0366 ret.impl_.reserve(frames_count);
0367 for (; first != last; ++first) {
0368 if (!*first) {
0369 break;
0370 }
0371
0372 ret.impl_.push_back(frame(*first));
0373 }
0374
0375 return ret;
0376 }
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395 static basic_stacktrace<Allocator> from_current_exception(const allocator_type& alloc = allocator_type()) noexcept {
0396
0397 constexpr std::size_t kStacktraceDumpSize = 4096;
0398
0399 const char* trace = nullptr;
0400 #if defined(__GNUC__) && defined(__ELF__)
0401 if (impl::current_exception_stacktrace) {
0402 trace = impl::current_exception_stacktrace();
0403 }
0404 #elif defined(BOOST_MSVC)
0405 trace = boost_stacktrace_impl_current_exception_stacktrace();
0406 #endif
0407
0408 if (trace) {
0409 try {
0410 return basic_stacktrace<Allocator>::from_dump(trace, kStacktraceDumpSize, alloc);
0411 } catch (const std::exception&) {
0412
0413 }
0414 }
0415 return basic_stacktrace<Allocator>{0, 0, alloc};
0416 }
0417 };
0418
0419
0420
0421
0422
0423
0424 template <class Allocator1, class Allocator2>
0425 bool operator< (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
0426 return lhs.size() < rhs.size() || (lhs.size() == rhs.size() && lhs.as_vector() < rhs.as_vector());
0427 }
0428
0429
0430
0431
0432
0433
0434 template <class Allocator1, class Allocator2>
0435 bool operator==(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
0436 return lhs.as_vector() == rhs.as_vector();
0437 }
0438
0439
0440
0441 template <class Allocator1, class Allocator2>
0442 bool operator> (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
0443 return rhs < lhs;
0444 }
0445
0446 template <class Allocator1, class Allocator2>
0447 bool operator<=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
0448 return !(lhs > rhs);
0449 }
0450
0451 template <class Allocator1, class Allocator2>
0452 bool operator>=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
0453 return !(lhs < rhs);
0454 }
0455
0456 template <class Allocator1, class Allocator2>
0457 bool operator!=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
0458 return !(lhs == rhs);
0459 }
0460
0461
0462 template <class Allocator>
0463 std::size_t hash_value(const basic_stacktrace<Allocator>& st) noexcept {
0464 return boost::hash_range(st.as_vector().begin(), st.as_vector().end());
0465 }
0466
0467
0468 template <class Allocator>
0469 std::string to_string(const basic_stacktrace<Allocator>& bt) {
0470 if (!bt) {
0471 return std::string();
0472 }
0473
0474 return boost::stacktrace::detail::to_string(&bt.as_vector()[0], bt.size());
0475 }
0476
0477
0478 template <class CharT, class TraitsT, class Allocator>
0479 std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt) {
0480 return os << boost::stacktrace::to_string(bt);
0481 }
0482
0483
0484 typedef basic_stacktrace<> stacktrace;
0485
0486 }}
0487
0488 #ifdef BOOST_INTEL
0489 # pragma warning(pop)
0490 #endif
0491
0492 #endif