Skip to content

Commit a8a2efd

Browse files
author
Pedro Navarro
committed
Added libunwind support to Linux and macOS
libunwind interprets the signal handler frame and provides better stacktraces. Because it lets us inspect the stack we can manipulate it to unwind across bad function dereferences. Clang in macOS provides an API compatible version of libunwind, so there's no need to link against any library.
1 parent 1efdd14 commit a8a2efd

File tree

4 files changed

+320
-24
lines changed

4 files changed

+320
-24
lines changed

Diff for: BackwardConfig.cmake

+33-3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ set(STACK_WALKING_UNWIND TRUE CACHE BOOL
2828
"Use compiler's unwind API")
2929
set(STACK_WALKING_BACKTRACE FALSE CACHE BOOL
3030
"Use backtrace from (e)glibc for stack walking")
31+
set(STACK_WALKING_LIBUNWIND FALSE CACHE BOOL
32+
"Use libunwind for stack walking")
3133

3234
set(STACK_DETAILS_AUTO_DETECT TRUE CACHE BOOL
3335
"Auto detect backward's stack details dependencies")
@@ -50,9 +52,37 @@ endif()
5052
###############################################################################
5153
# CONFIGS
5254
###############################################################################
53-
if (${STACK_DETAILS_AUTO_DETECT})
54-
include(FindPackageHandleStandardArgs)
55+
include(FindPackageHandleStandardArgs)
5556

57+
if (STACK_WALKING_LIBUNWIND)
58+
# libunwind works on the macOS without having to add special include
59+
# paths or libraries
60+
if (NOT APPLE)
61+
find_path(LIBUNWIND_INCLUDE_DIR NAMES "libunwind.h")
62+
find_library(LIBUNWIND_LIBRARY unwind)
63+
64+
if (LIBUNWIND_LIBRARY)
65+
include(CheckSymbolExists)
66+
check_symbol_exists(UNW_INIT_SIGNAL_FRAME libunwind.h HAVE_UNW_INIT_SIGNAL_FRAME)
67+
if (NOT HAVE_UNW_INIT_SIGNAL_FRAME)
68+
message(STATUS "libunwind does not support unwinding from signal handler frames")
69+
endif()
70+
endif()
71+
72+
set(LIBUNWIND_INCLUDE_DIRS ${LIBUNWIND_INCLUDE_DIR})
73+
set(LIBDWARF_LIBRARIES ${LIBUNWIND_LIBRARY})
74+
find_package_handle_standard_args(libunwind DEFAULT_MSG
75+
LIBUNWIND_LIBRARY LIBUNWIND_INCLUDE_DIR)
76+
mark_as_advanced(LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARY)
77+
list(APPEND _BACKWARD_LIBRARIES ${LIBUNWIND_LIBRARY})
78+
endif()
79+
80+
# Disable other unwinders if libunwind is found
81+
set(STACK_WALKING_UNWIND FALSE)
82+
set(STACK_WALKING_BACKTRACE FALSE)
83+
endif()
84+
85+
if (${STACK_DETAILS_AUTO_DETECT})
5686
# find libdw
5787
find_path(LIBDW_INCLUDE_DIR NAMES "elfutils/libdw.h" "elfutils/libdwfl.h")
5888
find_library(LIBDW_LIBRARY dw)
@@ -152,7 +182,7 @@ macro(map_definitions var_prefix define_prefix)
152182
endmacro()
153183

154184
if (NOT _BACKWARD_DEFINITIONS)
155-
map_definitions("STACK_WALKING_" "BACKWARD_HAS_" UNWIND BACKTRACE)
185+
map_definitions("STACK_WALKING_" "BACKWARD_HAS_" UNWIND LIBUNWIND BACKTRACE)
156186
map_definitions("STACK_DETAILS_" "BACKWARD_HAS_" BACKTRACE_SYMBOL DW BFD DWARF)
157187
endif()
158188

Diff for: README.md

+34-5
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,35 @@ find_package(Backward)
9393
# through an IMPORTED target.
9494
target_link_libraries(mytarget PUBLIC Backward::Backward)
9595
```
96+
### Libraries to unwind the stack
97+
98+
On Linux and macOS, backtrace can back-trace or "walk" the stack using the
99+
following libraries:
100+
101+
#### unwind
102+
103+
Unwind comes from libgcc, but there is an equivalent inside clang itself. With
104+
unwind, the stacktrace is as accurate as it can possibly be, since this is
105+
used by the C++ runtine in gcc/clang for stack unwinding on exception.
106+
107+
Normally libgcc is already linked to your program by default.
108+
109+
#### libunwind from the [libunwind project](https://github.com/libunwind/libunwind)
110+
111+
apt-get install binutils-dev (or equivalent)
112+
113+
Libunwind provides, in some cases, a more accurate stacktrace as it knows
114+
to decode signal handler frames and lets us edit the context registers when
115+
unwinding, allowing stack traces over bad function references.
116+
117+
For best results make sure you are using libunwind 1.3 or later, which added
118+
`unw_init_local2` and support for handling signal frames.
119+
120+
CMake will warn you when configuring if your libunwind version doesn't support
121+
signal frames.
122+
123+
On macOS clang provides a libunwind API compatible library as part of its
124+
environment, so no third party libraries are necessary.
96125

97126
### Compile with debug info
98127

@@ -110,17 +139,17 @@ your sources.
110139

111140
### Libraries to read the debug info
112141

113-
Backward support pretty printed stack traces on GNU/Linux only, it will compile
114-
fine under other platforms but will not do anything. **Pull requests are
115-
welcome :)**
142+
Backward supports pretty printed stack traces on GNU/Linux, macOS and Windows,
143+
it will compile fine under other platforms but will not do anything. **Pull
144+
requests are welcome :)**
116145

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

120149
![default trace](doc/nice.png)
121150

122-
You will need to install some dependencies to get the ultimate stack trace. Two
123-
libraries are currently supported, the only difference is which one is the
151+
You will need to install some dependencies to get the ultimate stack trace.
152+
Three libraries are currently supported, the only difference is which one is the
124153
easiest for you to install, so pick your poison:
125154

126155
#### libbfd from the [GNU/binutils](http://www.gnu.org/software/binutils/)

Diff for: backward.cpp

+11-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
// - line and column numbers
1212
// - source code snippet (assuming the file is accessible)
1313

14-
// Install one of the following library then uncomment one of the macro (or
14+
// Install one of the following libraries then uncomment one of the macro (or
1515
// better, add the detection of the lib and the macro definition in your build
1616
// system)
1717

@@ -23,6 +23,16 @@
2323
// - g++/clang++ -lbfd ...
2424
// #define BACKWARD_HAS_BFD 1
2525

26+
// - apt-get install libdwarf-dev ...
27+
// - g++/clang++ -ldwarf ...
28+
// #define BACKWARD_HAS_DWARF 1
29+
30+
// Regardless of the library you choose to read the debug information,
31+
// for potentially more detailed stack traces you can use libunwind
32+
// - apt-get install libunwind-dev
33+
// - g++/clang++ -lunwind
34+
// #define BACKWARD_HAS_LIBUNWIND 1
35+
2636
#include "backward.hpp"
2737

2838
namespace backward {

0 commit comments

Comments
 (0)