2013-03-14 23:10:06 -07:00
|
|
|
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).
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
All "Source" lines and code snippet prefixed by a pipe "|" are frames inline
|
|
|
|
the next frame.
|
2013-03-14 23:10:06 -07:00
|
|
|
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
|
|
|
|
|
2013-03-14 23:19:17 -07:00
|
|
|
#### Install backward.hpp
|
2013-03-14 23:10:06 -07:00
|
|
|
|
|
|
|
Backward is a header only library. So installing Backward is easy, simply drop
|
2013-03-15 10:57:40 -04:00
|
|
|
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`.
|
2013-03-14 23:10:06 -07:00
|
|
|
|
2013-03-14 23:19:17 -07:00
|
|
|
#### Install backward.cpp
|
2013-03-14 23:10:06 -07:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
The code in `backward.cpp` is trivial anyway, you can simply copy what it's
|
2013-03-14 23:10:06 -07:00
|
|
|
doing at your convenience.
|
|
|
|
|
|
|
|
##Configuration & Dependencies
|
|
|
|
|
2014-10-24 16:51:13 +02:00
|
|
|
### 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:
|
|
|
|
```
|
|
|
|
add_subdirectory(/path/to/backward-cpp)
|
|
|
|
|
|
|
|
# This will add backward.cpp to your target
|
|
|
|
add_executable(myproject mysource.cpp ${backward_ENABLE})
|
|
|
|
|
|
|
|
# This will add libraries, definitions and include directories needed by backward
|
|
|
|
add_backward(myproject)
|
|
|
|
```
|
|
|
|
|
2013-03-14 23:10:06 -07:00
|
|
|
### Compile with debug info
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
You need to compile your project with generation of debug symbols enabled,
|
|
|
|
usually `-g` with clang++ and g++.
|
2013-03-14 23:10:06 -07:00
|
|
|
|
|
|
|
Note that you can use `-g` with any level of optimization, with modern debug
|
2013-03-15 10:57:40 -04:00
|
|
|
information encoding like DWARF, it only takes space in the binary (it'ss not
|
2013-03-14 23:10:06 -07:00
|
|
|
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
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
Backward support pretty printed stack traces on GNU/Linux only, it will compile
|
2013-03-14 23:10:06 -07:00
|
|
|
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. Two
|
2013-03-15 10:57:40 -04:00
|
|
|
libraries are currently supported, the only difference is which one is the
|
|
|
|
easiest for you to install, so pick your poison:
|
2013-03-14 23:10:06 -07:00
|
|
|
|
|
|
|
#### libbfd from the [GNU/binutils](http://www.gnu.org/software/binutils/)
|
|
|
|
|
|
|
|
apt-get install binutils-dev (or equivalent)
|
|
|
|
|
|
|
|
And do not forget to link with the lib: `g++/clang++ -lbfd ...`
|
|
|
|
|
|
|
|
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](https://fedorahosted.org/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.
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
That'ss it, you are all set, you should be getting nice stack traces like the
|
|
|
|
one at the beginning of this document.
|
2013-03-14 23:10:06 -07:00
|
|
|
|
|
|
|
## API
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
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
|
2013-03-14 23:17:11 -07:00
|
|
|
print them the way you love or you decide to send them all to your buddies over
|
2013-03-15 10:57:40 -04:00
|
|
|
the Internet, you will appreciate the simplicity of Backward's API.
|
2013-03-14 23:10:06 -07:00
|
|
|
|
|
|
|
### Stacktrace
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
The Stacktrace class lets you take a "snapshot" of the current stack.
|
2013-03-14 23:10:06 -07:00
|
|
|
You can use it like this:
|
|
|
|
|
|
|
|
```c++
|
|
|
|
using namespace backward;
|
|
|
|
Stacktrace st; st.load_here(32);
|
|
|
|
Printer p; p.print(st);
|
|
|
|
```
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
The public methods are:
|
2013-03-14 23:10:06 -07:00
|
|
|
|
|
|
|
```c++
|
|
|
|
class StackTrace { public:
|
|
|
|
// Take a snapshot of the current stack, with at most "trace_cnt_max"
|
|
|
|
// traces in it. The first trace is the most recent (ie the current
|
|
|
|
// frame). You can also provide a trace address to load_from() assuming
|
|
|
|
// the address is a valid stack frame (useful for signal handling traces).
|
|
|
|
// Both function return size().
|
|
|
|
size_t load_here(size_t trace_cnt_max)
|
|
|
|
size_t load_from(void* address, size_t trace_cnt_max)
|
|
|
|
|
|
|
|
// The number of traces loaded. This can be less than "trace_cnt_max".
|
|
|
|
size_t size() const
|
|
|
|
|
|
|
|
// A unique id for the thread in which the trace was taken. The value
|
|
|
|
// 0 means the stack trace comes from the main thread.
|
|
|
|
size_t thread_id() const
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
// Retrieve a trace by index. 0 is the most recent trace, size()-1 is
|
|
|
|
// the oldest one.
|
2013-03-14 23:10:06 -07:00
|
|
|
Trace operator[](size_t trace_idx)
|
|
|
|
};
|
|
|
|
```
|
|
|
|
|
|
|
|
### TraceResolver
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
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.
|
2013-03-14 23:10:06 -07:00
|
|
|
|
|
|
|
You can use it like this:
|
|
|
|
|
|
|
|
```c++
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
The public methods are:
|
2013-03-14 23:10:06 -07:00
|
|
|
|
|
|
|
```c++
|
|
|
|
class TraceResolver { public:
|
2013-03-15 10:57:40 -04:00
|
|
|
// Pre-load whatever is necessary from the stack trace.
|
2013-03-14 23:10:06 -07:00
|
|
|
template <class ST>
|
|
|
|
void load_stacktrace(ST&)
|
|
|
|
|
|
|
|
// Resolve a trace. It takes a ResolvedTrace, because a `Trace` or a
|
|
|
|
// `TraceWithLocals` are implicitly convertible to a ResolvedTrace.
|
|
|
|
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.
|
|
|
|
|
|
|
|
```c++
|
|
|
|
class SnippetFactory { public:
|
2013-03-15 10:57:40 -04:00
|
|
|
// A snippet is a list of line numbers and line contents.
|
2013-03-14 23:10:06 -07:00
|
|
|
typedef std::vector<std::pair<size_t, std::string> > lines_t;
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
// Return a snippet starting at line_start with up to context_size lines.
|
2013-03-14 23:10:06 -07:00
|
|
|
lines_t get_snippet(const std::string& filename,
|
|
|
|
size_t line_start, size_t context_size)
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
// Return a combined snippet from two different locations and combine them.
|
|
|
|
// context_size / 2 lines will be extracted from each location.
|
2013-03-14 23:10:06 -07:00
|
|
|
lines_t get_combined_snippet(
|
|
|
|
const std::string& filename_a, size_t line_a,
|
|
|
|
const std::string& filename_b, size_t line_b,
|
|
|
|
size_t context_size)
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
// Tries to return a unified snippet if the two locations from the same
|
2013-03-14 23:10:06 -07:00
|
|
|
// file are close enough to fit inside one context_size, else returns
|
|
|
|
// the equivalent of get_combined_snippet().
|
|
|
|
lines_t get_coalesced_snippet(const std::string& filename,
|
|
|
|
size_t line_a, size_t line_b, size_t context_size)
|
|
|
|
```
|
|
|
|
|
|
|
|
### Printer
|
|
|
|
|
|
|
|
A simpler way to pretty print a stack trace to the terminal. It will
|
|
|
|
automatically resolve the traces for you:
|
|
|
|
|
|
|
|
```c++
|
|
|
|
using namespace backward;
|
|
|
|
Stacktrace st; st.load_here(32);
|
|
|
|
Printer p;
|
|
|
|
p.object = true;
|
|
|
|
p.color = false;
|
|
|
|
p.address = true;
|
|
|
|
p.print(st, stderr);
|
|
|
|
```
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
You can set a few options:
|
2013-03-14 23:10:06 -07:00
|
|
|
|
|
|
|
```c++
|
|
|
|
class Printer { public:
|
|
|
|
// Print a little snippet of code if possible.
|
|
|
|
bool snippet = true;
|
|
|
|
|
|
|
|
// Colorize the trace (only set a color when printing on a terminal)
|
|
|
|
bool color = true;
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
// Add the addresses of every source location to the trace.
|
2013-03-14 23:10:06 -07:00
|
|
|
bool address = false;
|
|
|
|
|
|
|
|
// Even if there is a source location, prints the object the trace comes
|
|
|
|
// from as well.
|
|
|
|
bool object = false;
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
// Resolve and print a stack trace. It takes a C FILE* object, only because
|
|
|
|
// it is possible to access the underalying OS-level file descriptor, which
|
|
|
|
// is then used to determine if the output is a terminal to print in color.
|
2013-03-14 23:10:06 -07:00
|
|
|
template <typename StackTrace>
|
|
|
|
FILE* print(StackTrace& st, FILE* os = stderr)
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### SignalHandling
|
|
|
|
|
|
|
|
A simple helper class that registers for you the most common signals and other
|
|
|
|
callbacks to segfault, hardware exception, un-handled exception etc.
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
`backward.cpp` simply uses it like that:
|
2013-03-14 23:10:06 -07:00
|
|
|
|
|
|
|
```c++
|
|
|
|
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:
|
|
|
|
|
|
|
|
```c++
|
|
|
|
bool loaded() const // true if loaded with success
|
|
|
|
```
|
|
|
|
|
|
|
|
### 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
|
|
|
|
|
|
|
|
```c++
|
|
|
|
struct Trace {
|
|
|
|
void* addr; // address of the trace
|
|
|
|
size_t idx; // its index (0 == most recent)
|
|
|
|
};
|
|
|
|
```
|
|
|
|
|
|
|
|
#### Trace with local variables
|
|
|
|
|
|
|
|
This is not used for now, but it might be used to carry Traces with snapshotted
|
|
|
|
variables in the future.
|
|
|
|
|
|
|
|
```c++
|
|
|
|
struct TraceWithLocals: public Trace {
|
|
|
|
std::vector<Variable> locals; // Locals variable and values.
|
|
|
|
};
|
|
|
|
```
|
|
|
|
|
|
|
|
#### 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.
|
|
|
|
|
|
|
|
```c++
|
|
|
|
struct ResolvedTrace: public TraceWithLocals {
|
|
|
|
|
|
|
|
struct SourceLoc {
|
|
|
|
std::string function;
|
|
|
|
std::string filename;
|
|
|
|
size_t line;
|
|
|
|
size_t col;
|
|
|
|
};
|
|
|
|
|
|
|
|
// In which binary object this trace is located.
|
|
|
|
std::string object_filename;
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
// The function in the object that contains the trace. This is not the same
|
2013-03-14 23:10:06 -07:00
|
|
|
// as source.function which can be an function inlined in object_function.
|
|
|
|
std::string object_function;
|
|
|
|
|
|
|
|
// The source location of this trace. It is possible for filename to be
|
|
|
|
// empty and for line/col to be invalid (value 0) if this information
|
|
|
|
// couldn't be deduced, for example if there is no debug information in the
|
|
|
|
// binary object.
|
|
|
|
SourceLoc source;
|
|
|
|
|
2013-03-15 10:57:40 -04:00
|
|
|
// An optional list of "inliners". All of these sources locations where
|
|
|
|
// inlined in the source location of the trace (the attribute right above).
|
|
|
|
// This is especially useful when you compile with optimizations turned on.
|
2013-03-14 23:10:06 -07:00
|
|
|
typedef std::vector<SourceLoc> source_locs_t;
|
|
|
|
source_locs_t inliners;
|
|
|
|
};
|
|
|
|
```
|
|
|
|
|
|
|
|
## Contact and copyright
|
|
|
|
|
2013-03-15 13:15:28 -07:00
|
|
|
François-Xavier Bourlet <bombela@gmail.com>
|
|
|
|
|
|
|
|
Copyright 2013 Google Inc. All Rights Reserved.
|
2013-03-14 23:10:06 -07:00
|
|
|
MIT License.
|
2013-03-15 13:15:28 -07:00
|
|
|
|
|
|
|
### Disclaimer
|
|
|
|
|
|
|
|
Although this project is owned by Google Inc. this is not a Google supported or
|
|
|
|
affiliated project.
|