|
35 | 35 |
|
36 | 36 | namespace boost { namespace stacktrace { |
37 | 37 |
|
| 38 | +namespace impl { |
| 39 | + |
| 40 | +#if defined(__GNUC__) && defined(__ELF__) |
| 41 | + |
| 42 | +BOOST_NOINLINE BOOST_SYMBOL_VISIBLE __attribute__((weak)) |
| 43 | +const char* current_exception_stacktrace() noexcept; |
| 44 | + |
| 45 | +BOOST_NOINLINE BOOST_SYMBOL_VISIBLE __attribute__((weak)) |
| 46 | +bool& ref_capture_stacktraces_at_throw() noexcept; |
| 47 | + |
| 48 | +#endif |
| 49 | + |
| 50 | +} // namespace impl |
| 51 | + |
38 | 52 | /// Class that on construction copies minimal information about call stack into its internals and provides access to that information. |
39 | 53 | /// @tparam Allocator Allocator to use during stack capture. |
40 | 54 | template <class Allocator> |
@@ -65,7 +79,7 @@ class basic_stacktrace { |
65 | 79 | } |
66 | 80 |
|
67 | 81 | BOOST_NOINLINE void init(std::size_t frames_to_skip, std::size_t max_depth) { |
68 | | - BOOST_CONSTEXPR_OR_CONST std::size_t buffer_size = 128; |
| 82 | + constexpr std::size_t buffer_size = 128; |
69 | 83 | if (!max_depth) { |
70 | 84 | return; |
71 | 85 | } |
@@ -340,6 +354,44 @@ class basic_stacktrace { |
340 | 354 |
|
341 | 355 | return ret; |
342 | 356 | } |
| 357 | + |
| 358 | + /// Returns a basic_stacktrace object containing a stacktrace captured at |
| 359 | + /// the point where the currently handled exception was thrown by its |
| 360 | + /// initial throw-expression (i.e. not a rethrow), or an empty |
| 361 | + /// basic_stacktrace object if: |
| 362 | + /// |
| 363 | + /// - the `boost_stacktrace_from_exception` library is not linked to the |
| 364 | + /// current binary, or |
| 365 | + /// - the initialization of stacktrace failed, or |
| 366 | + /// - stacktrace captures are not enabled for the throwing thread, or |
| 367 | + /// - no exception is being handled, or |
| 368 | + /// - due to implementation-defined reasons. |
| 369 | + /// |
| 370 | + /// `alloc` is passed to the constructor of the stacktrace object. |
| 371 | + /// Rethrowing an exception using a throw-expression with no operand does |
| 372 | + /// not alter the captured stacktrace. |
| 373 | + /// |
| 374 | + /// Implements https://wg21.link/p2370r1 |
| 375 | + static basic_stacktrace<Allocator> from_current_exception(const allocator_type& alloc = allocator_type()) noexcept { |
| 376 | + // Matches the constant from implementation |
| 377 | + constexpr std::size_t kStacktraceDumpSize = 4096; |
| 378 | + |
| 379 | + const char* trace = nullptr; |
| 380 | +#if defined(__GNUC__) && defined(__ELF__) |
| 381 | + if (impl::current_exception_stacktrace) { |
| 382 | + trace = impl::current_exception_stacktrace(); |
| 383 | + } |
| 384 | +#endif |
| 385 | + |
| 386 | + if (trace) { |
| 387 | + try { |
| 388 | + return basic_stacktrace<Allocator>::from_dump(trace, kStacktraceDumpSize, alloc); |
| 389 | + } catch (const std::exception&) { |
| 390 | + // ignore |
| 391 | + } |
| 392 | + } |
| 393 | + return basic_stacktrace<Allocator>{0, 0, alloc}; |
| 394 | + } |
343 | 395 | }; |
344 | 396 |
|
345 | 397 | /// @brief Compares stacktraces for less, order is platform dependent. |
|
0 commit comments