Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
B

backward-cpp

> 编程语言
Open source

A beautiful stack trace pretty printer for C++

4.3K stars0 likes0 views
WebsiteGitHub

About

A beautiful stack trace pretty printer for C++

Backward-cpp

Backward is a beautiful stack trace pretty printer for C++.

If you are bored to see this:

Backward will spice it up for you:

There is not much to say. Of course it will be able to display the code snippets only if the source files are accessible (else see trace #4 in the example).

All "Source" lines and code snippet prefixed by a pipe "|" are frames inline the next frame. You can see that for the trace #1 in the example, the function you_shall_not_pass() was inlined in the function ...read2::do_test() by the compiler.

Installation

Install backward.hpp

Backward is a header only library. So installing Backward is easy, simply drop a copy of backward.hpp along with your other source files in your C++ project. You can also use a git submodule or really any other way that best fits your environment, as long as you can include backward.hpp.

Install backward.cpp

If you want Backward to automatically print a stack trace on most common fatal errors (segfault, abort, un-handled exception...), simply add a copy of backward.cpp to your project, and don't forget to tell your build system.

The code in backward.cpp is trivial anyway, you can simply copy what it's doing at your convenience.

Note for folly library users: must define backward::SignalHandling sh; after folly::init(&argc, &argv);.

Configuration & Dependencies

Integration with CMake

If you are using CMake and want to use its configuration abilities to save you the trouble, you can easily integrate Backward, depending on how you obtained the library.

Notice that all approaches are equivalent in the way Backward is added to a CMake target, the difference is in how CMake is pointed to the Backward sources. Backward defines three targets:

  • Backward::Interface is an interface target that brings compiler definition flags, include directory, and external libraries. This is all you need to use the backward.hpp header library.
  • Backward::Object brings Backward::Interface and backward.cpp as an OBJECT CMake library. This target cannot be exported, so it is not available when Backward is used via find_package.
  • Backward::Backward brings Backward::Interface and backward.cpp as either STATIC or SHARED library (depending on the BACKWARD_SHARED option). This target is exported and always available, however note that the linker will not include unused objects from a static library, unless the -Wl,--whole-archive option (or similar) is used.

With FetchContent():

If you are using a recent version of CMake, you can integrate backward via FetchContent like below:

include(FetchContent)

# Also requires one of: libbfd (gnu binutils), libdwarf, libdw (elfutils)
FetchContent_Declare(backward
    GIT_REPOSITORY https://github.com/bombela/backward-cpp
    GIT_TAG master  # or a version tag, such as v1.6
    SYSTEM          # optional, the Backward include directory will be treated as system directory
)
FetchContent_MakeAvailable(backward)

# Add Backward to your target (either Backward::Interface, Backward::Object, or Backward::Backward)
target_link_libraries(mytarget PUBLIC Backward::Interface)

As a subdirectory:

In this case you have a subdirectory containing the whole repository of Backward (e.g. using git-submodule), in this case you can do:

add_subdirectory(/path/to/backward-cpp)

# Add Backward to your target (either Backward::Interface, Backward::Object, or Backward::Backward)
target_link_libraries(mytarget PUBLIC Backward::Interface)

Modifying CMAKE_MODULE_PATH:

In this case you can have Backward installed as a subdirectory:

list(APPEND CMAKE_MODULE_PATH /path/to/backward-cpp)
find_package(Backward)

# Add Backward to your target (either Backward::Interface or Backward::Backward)
target_link_libraries(mytarget PUBLIC Backward::Interface)

Installation through a regular package manager

In this case you have obtained Backward through a package manager.

Packages currently available:

  • conda-forge
find_package(Backward)

# Add Backward to your target (either Backward::Interface or Backward::Backward)
target_link_libraries(mytarget PUBLIC Backward::Interface)

Libraries to unwind the stack

On Linux and macOS, backtrace can back-trace or "walk" the stack using the following libraries:

unwind

Unwind comes from libgcc, but there is an equivalent inside clang itself. With unwind, the stacktrace is as accurate as it can possibly be, since this is used by the C++ runtine in gcc/clang for stack unwinding on exception.

Normally libgcc is already linked to your program by default.

libunwind from the libunwind project

apt-get install binutils-dev (or equivalent)

Libunwind provides, in some cases, a more accurate stacktrace as it knows to decode signal handler frames and lets us edit the context registers when unwinding, allowing stack traces over bad function references.

For best results make sure you are using libunwind 1.3 or later, which added unw_init_local2 and support for handling signal frames.

CMake will warn you when configuring if your libunwind version doesn't support signal frames.

On macOS clang provides a libunwind API compatible library as part of its environment, so no third party libraries are necessary.

Compile with debug info

You need to compile your project with generation of debug symbols enabled, usually -g with clang++ and g++.

Note that you can use -g with any level of optimization, with modern debug information encoding like DWARF, it only takes space in the binary (it's not loaded in memory until your debugger or Backward makes use of it, don't worry), and it doesn't impact the code generation (at least on GNU/Linux x86_64 for what I know).

If you are missing debug information, the stack trace will lack details about your sources.

Libraries to read the debug info

Backward supports pretty printed stack traces on GNU/Linux, macOS and Windows, it will compile fine under other platforms but will not do anything. Pull requests are welcome :)

Also, by default you will get a really basic stack trace, based on the backtrace_symbols API:

You will need to install some dependencies to get the ultimate stack trace. Three libraries are currently supported, the only difference is which one is the easiest for you to install, so pick your poison:

libbfd from the GNU/binutils

apt-get install binutils-dev (or equivalent)

And do not forget to link with the lib: g++/clang++ -lbfd -ldl ...

This library requires dynamic loading. Which is provided by the library dl. Hence why we also link with -ldl.

Then define the following before every inclusion of backward.hpp (don't forget to update backward.cpp as well):

#define BACKWARD_HAS_BFD 1

libdw from the elfutils

apt-get install libdw-dev (or equivalent)

And do not forget to link with the lib and inform Backward to use it:

#define BACKWARD_HAS_DW 1

Of course you can simply add the define (-DBACKWARD_HAS_...=1) and the linkage details in your build system and even auto-detect which library is installed, it's up to you.

libdwarf and libelf

apt-get install libdwarf-dev (or equivalent)

And do not forget to link with the lib and inform Backward to use it:

#define BACKWARD_HAS_DWARF 1

There are several alternative implementations of libdwarf and libelf that are API compatible so it's possible, although it hasn't been tested, to replace the ones used when developing backward (in bold, below):

  • libelf by Michael "Tired" Riepe
  • libdwarf by David Anderson
  • libelf from elfutils
  • libelf and libdwarf from FreeBSD's ELF Tool Chain project

Of course you can simply add the define (-DBACKWARD_HAS_...=1) and the linkage details in your build system and even auto-detect which library is installed, it's up to you.

That's it, you are all set, you should be getting nice stack traces like the one at the beginning of this document.

API

If you don't want to limit yourself to the defaults offered by backward.cpp, and you want to take some random stack traces for whatever reason and pretty print them the way you love or you decide to send them all to your buddies over the Internet, you will appreciate the simplicity of Backward's API.

Stacktrace

The StackTrace class lets you take a "snapshot" of the current stack. You can use it like this:

using namespace backward;
StackTrace st; st.load_here(32);
Printer p; p.print(st);

The public methods are:

…

TraceResolver

The TraceResolver does the heavy lifting, and intends to transform a simple Trace from its address into a fully detailed ResolvedTrace with the filename of the source, line numbers, inlined functions and so on.

You can use it like this:

using namespace backward;
StackTrace st; st.load_here(32);

TraceResolver tr; tr.load_stacktrace(st);
for (size_t i = 0; i < st.size(); ++i) {
	ResolvedTrace trace = tr.resolve(st[i]);
	std::cout << "#" << i
		<< " " << trace.object_filename
		<< " " << trace.object_function
		<< " [" << trace.addr << "]"
	<< std::endl;
}

The public methods are:

class TraceResolver { public:
	// Pre-load whatever is necessary from the stack trace.
	template <class ST>
		void load_stacktrace(ST&)

	// Resolve a trace. It takes a ResolvedTrace, because a `Trace` is
	// implicitly convertible to it.
	ResolvedTrace resolve(ResolvedTrace t)
};

SnippetFactory

The SnippetFactory is a simple helper class to automatically load and cache source files in order to extract code snippets.

…

Printer

A simpler way to pretty print a stack trace to the terminal. It will automatically resolve the traces for you:

using namespace backward;
StackTrace st; st.load_here(32);
Printer p;
p.object = true;
p.color_mode = ColorMode::always;
p.address = true;
p.print(st, stderr);

You can set a few options:

…

SignalHandling

A simple helper class that registers for you the most common signals and other callbacks to segfault, hardware exception, un-handled exception etc.

backward.cpp simply uses it like that:

backward::SignalHandling sh;

Creating the object registers all the different signals and hooks. Destroying this object doesn't do anything. It exposes only one method:

bool loaded() const // true if loaded with success

Warning: The registered signal handlers are not signal safe, mostly because backward-cpp and the DWARF decoding libraries are using malloc. In case a signal is raised while malloc is holding a lock, a deadlock will occur.

Trace object

To keep the memory footprint of a loaded StackTrace on the low-side, there a hierarchy of trace object, from a minimal Trace to a ResolvedTrace.

Simple trace

struct Trace {
	void*  addr; // address of the trace
	size_t idx;  // its index (0 == most recent)
};

Resolved trace

A ResolvedTrace should contains a maximum of details about the location of the trace in the source code. Note that not all fields might be set.

…

Contact and copyright

François-Xavier Bourlet [email protected]

Copyright 2013-2017 Google Inc. All Rights Reserved. MIT License.

Disclaimer

Although this p

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

C++

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言