nim-libbacktrace/README.md

116 lines
3.9 KiB
Markdown

# All the backtrace, none of the overhead
[![Build Status](https://travis-ci.org/status-im/nim-libbacktrace.svg?branch=master)](https://travis-ci.org/status-im/nim-libbacktrace)
[![Build status](https://ci.appveyor.com/api/projects/status/mrvu6ks50dl5y5y4/branch/master?svg=true)](https://ci.appveyor.com/project/nimbus/nim-libbacktrace/branch/master)
[![License: Apache](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
![Stability: experimental](https://img.shields.io/badge/stability-experimental-orange.svg)
Nim's default stack tracing functionality comes with significant
overhead, by adding `nimln_()`, `nimfr_()` calls all over the place. The
problem is being discussed upstream in [this GitHub
issue](https://github.com/nim-lang/Nim/issues/12702).
That `popFrame()` at the end of each C function is particularly problematic,
since it prevents the C compiler from doing tail-call optimisations.
This is a lightweight alternative based on libbacktrace, meant to offer the
same stack traces without the runtime overhead.
C++ function name demangling is supported using "\_\_cxa\_demangle()".
## Building & Testing
This project uses Git submodules, so get it with:
```bash
git clone https://github.com/status-im/nim-libbacktrace.git
cd nim-libbacktrace
git submodule update --init
```
You build the library (or libraries, on macOS) with `make`. You test it with
`make test`.
Nimble is grudgingly supported, so `nimble install` works. (No, we will not
let a silly package manager dictate our project's structure. People have the
power!)
## Supported platforms
Tested with GCC and LLVM on Linux, macOS and 64-bit Windows (with Mingw-w64 and
the MSYS that comes with "Git for Windows").
## Usage
bttest.nim:
```nim
import libbacktrace
# presumably in some procedure:
echo getBacktrace()
# Should be the same output as writeStackTrace() - minus the header.
# When the C compiler inlines some procs, libbacktrace might get confused with proc names,
# but it gets the files and line numbers right nonetheless.
```
We need debugging symbols in the binary and we can do without Nim's bloated and
slow stack trace implementation:
```bash
nim c -f --debugger:native --stacktrace:off bttest.nim
```
If you're unfortunate enough to need this on macOS, [there's an extra
step](https://github.com/nim-lang/Nim/issues/12735) for creating debugging
symbols:
```bash
dsymutil bttest
```
Now you can run it:
```bash
./bttest
```
### Debugging
`export NIM_LIBBACKTRACE_DEBUG=1` to see the trace lines hidden by default.
## Dependencies
You need Make, CMake and, of course, Nim up and running.
The other dependencies are bundled, for your convenience. We use a [libbacktrace
fork](https://github.com/rust-lang-nursery/libbacktrace/tree/rust-snapshot-2018-05-22)
with macOS support and [LLVM's libunwind
variant](https://github.com/llvm-mirror/libunwind) that's needed on macOS and Windows.
If you know better and want to use your system's libbacktrace package instead
of the bundled one, you can, with `make USE_SYSTEM_LIBS=1` and by passing
`-d:libbacktraceUseSystemLibs` to the Nim compiler.
How does libbacktrace work on systems without libunwind installed, I hear you
asking? It uses GCC's basic unwind support in libgcc\_s.so.1 - that runtime's so
good that even Clang links it by default ;-)
To get the running binary's path in a cross-platform way, we rely on
[whereami](https://github.com/gpakosz/whereami).
## License
Licensed and distributed under either of
* MIT license: [LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT
or
* Apache License, Version 2.0, ([LICENSE-APACHEv2](LICENSE-APACHEv2) or http://www.apache.org/licenses/LICENSE-2.0)
at your option. These files may not be copied, modified, or distributed except according to those terms.