std::stacktraceThe public interface follows the C++23 <stacktrace> header section by
section: stacktrace_entry ([stacktrace.entry]), stacktrace
([stacktrace.basic]), the non-member functions, hashing and formatting.
Code written against eggs::stacktrace should port to std::stacktrace
by changing the namespace. The deviations are deliberate and small:
eggs::stacktrace is a plain class, not
an alias of a basic_stacktrace<Allocator> template, and there is no
pmr alias.reference is const_reference. No mutable element access is
provided, so iterators are stacktrace_entry const*.native_handle_type is void*. It is the instruction address.std::ostream only. Stream insertion is not templated on the
character type.current() is [[nodiscard]] (where the compiler supports it).constexpr. operator<=> on entries
orders by address, which needs reinterpret_cast.Capture and symbolization are the only platform-specific parts. They
sit behind a small contract (capture, plus one function each for
description, source file and source line) that every backend
implements. Everything else -- containers, comparison, hashing,
formatting -- lives in a common object library shared by all backends.
| Backend | Capture | Symbolization |
|---|---|---|
Null |
none (always empty) | none |
Execinfo |
backtrace() |
dladdr() + __cxa_demangle(); no source file or line |
Libbacktrace |
libbacktrace | function, file and line from debug info |
Win32 |
CaptureStackBackTrace |
DbgHelp; function, file and line from the PDB |
Each backend is a separate static library, so several can be built in
the same project (for example to compare them in tests). The
Eggs::Stacktrace target aliases one of them: by default the first
available of Libbacktrace, Execinfo and Win32, falling back to Null.
The Null backend exists so that code using the library always
builds and links. It never fails and never captures anything, which
makes it a safe choice where no real backend is available.
stacktrace::current is noexcept. If a trace cannot be obtained the
result is an empty stacktrace. Likewise, description(),
source_file() and source_line() return an empty string or 0 when
the backend has no information; only memory allocation failures throw.
Stacktraces are diagnostic aids and must not turn a diagnostic path into
a new failure path.
current(skip) and current(skip, max_depth) count from the caller of
current. The library's own frames are accounted for internally, so
current(0) starts at the function that called current, and
current(1) starts at its caller. This is what makes the idiom of
capturing in a constructor and skipping the constructor itself work.
Capture is thread-safe. DbgHelp, used by the Win32 backend, is not:
the backend serializes its own Sym* calls with a mutex, but cannot
protect against other code in the process that calls DbgHelp directly.
Copyright © 2026 Agustin Berge
Distributed under the Boost Software License, Version 1.0.
See accompanying file LICENSE.txt or copy at
http://www.boost.org/LICENSE_1_0.txt