Add libunwind back-end (#62)
This commit is contained in:
parent
259d596f76
commit
5541ec5519
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- name: dependencies
|
||||
run: |
|
||||
sudo apt install gcc-10 g++-10 libgcc-10-dev
|
||||
sudo apt install gcc-10 g++-10 libgcc-10-dev libunwind8-dev
|
||||
pip3 install colorama
|
||||
- name: libdwarf
|
||||
run: |
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- name: dependencies
|
||||
run: |
|
||||
sudo apt install gcc-10 g++-10 libgcc-10-dev
|
||||
sudo apt install gcc-10 g++-10 libgcc-10-dev libunwind8-dev
|
||||
pip3 install colorama
|
||||
- name: libdwarf
|
||||
run: |
|
||||
|
||||
@ -83,6 +83,7 @@ endif()
|
||||
if(
|
||||
NOT (
|
||||
CPPTRACE_UNWIND_WITH_UNWIND OR
|
||||
CPPTRACE_UNWIND_WITH_LIBUNWIND OR
|
||||
CPPTRACE_UNWIND_WITH_EXECINFO OR
|
||||
CPPTRACE_UNWIND_WITH_WINAPI OR
|
||||
CPPTRACE_UNWIND_WITH_DBGHELP OR
|
||||
@ -195,6 +196,7 @@ target_sources(
|
||||
src/symbols/symbols_with_nothing.cpp
|
||||
src/symbols/symbols_core.cpp
|
||||
src/unwind/unwind_with_execinfo.cpp
|
||||
src/unwind/unwind_with_libunwind.cpp
|
||||
src/unwind/unwind_with_nothing.cpp
|
||||
src/unwind/unwind_with_unwind.cpp
|
||||
src/unwind/unwind_with_winapi.cpp
|
||||
@ -357,6 +359,34 @@ if(CPPTRACE_UNWIND_WITH_UNWIND)
|
||||
target_compile_definitions(${target_name} PUBLIC CPPTRACE_UNWIND_WITH_UNWIND)
|
||||
endif()
|
||||
|
||||
if(CPPTRACE_UNWIND_WITH_LIBUNWIND)
|
||||
find_package(PkgConfig)
|
||||
if(PkgConfig_FOUND)
|
||||
pkg_check_modules(LIBUNWIND QUIET libunwind)
|
||||
if(libunwind_FOUND)
|
||||
target_compile_options(${target_name} PRIVATE ${LIBUNWIND_CFLAGS_OTHER})
|
||||
target_include_directories(${target_name} PRIVATE ${LIBUNWIND_INCLUDE_DIRS})
|
||||
target_link_libraries(${target_name} PRIVATE ${LIBUNWIND_LDFLAGS})
|
||||
endif()
|
||||
endif()
|
||||
if(NOT libunwind_FOUND)
|
||||
# set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS ON)
|
||||
# set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB32_PATHS ON)
|
||||
find_path(LIBUNWIND_INCLUDE_DIR NAMES "libunwind.h")
|
||||
find_library(LIBUNWIND NAMES unwind libunwind libunwind8 libunwind.so.8 REQUIRED PATHS "/usr/lib/x86_64-linux-gnu/")
|
||||
if(LIBUNWIND)
|
||||
target_compile_options(${target_name} PRIVATE ${LIBUNWIND_CFLAGS_OTHER})
|
||||
target_include_directories(${target_name} PRIVATE ${LIBUNWIND_INCLUDE_DIRS})
|
||||
target_link_libraries(${target_name} PRIVATE ${LIBUNWIND_LDFLAGS})
|
||||
set(libunwind_FOUND TRUE)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT libunwind_FOUND)
|
||||
message(FATAL_ERROR "Unable to locate libunwind")
|
||||
endif()
|
||||
target_compile_definitions(${target_name} PUBLIC CPPTRACE_UNWIND_WITH_LIBUNWIND UNW_LOCAL_ONLY)
|
||||
endif()
|
||||
|
||||
if(CPPTRACE_UNWIND_WITH_EXECINFO)
|
||||
if(NOT HAS_EXECINFO)
|
||||
message(WARNING "Cpptrace: CPPTRACE_UNWIND_WITH_EXECINFO specified but execinfo.h doesn't seem to be available.")
|
||||
|
||||
16
README.md
16
README.md
@ -578,13 +578,14 @@ back-end such as addr2line, for example, you can configure the library to do so.
|
||||
|
||||
**Unwinding**
|
||||
|
||||
| Library | CMake config | Platforms | Info |
|
||||
| ------------- | ------------------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| libgcc unwind | `CPPTRACE_UNWIND_WITH_UNWIND` | linux, macos, mingw | Frames are captured with libgcc's `_Unwind_Backtrace`, which currently produces the most accurate stack traces on gcc/clang/mingw. Libgcc is often linked by default, and llvm has something equivalent. |
|
||||
| execinfo.h | `CPPTRACE_UNWIND_WITH_EXECINFO` | linux, macos | Frames are captured with `execinfo.h`'s `backtrace`, part of libc on linux/unix systems. |
|
||||
| winapi | `CPPTRACE_UNWIND_WITH_WINAPI` | windows, mingw | Frames are captured with `CaptureStackBackTrace`. |
|
||||
| dbghelp | `CPPTRACE_UNWIND_WITH_DBGHELP` | windows, mingw | Frames are captured with `StackWalk64`. |
|
||||
| N/A | `CPPTRACE_UNWIND_WITH_NOTHING` | all | Unwinding is not done, stack traces will be empty. |
|
||||
| Library | CMake config | Platforms | Info |
|
||||
| ------------- | -------------------------------- | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| libgcc unwind | `CPPTRACE_UNWIND_WITH_UNWIND` | linux, macos, mingw | Frames are captured with libgcc's `_Unwind_Backtrace`, which currently produces the most accurate stack traces on gcc/clang/mingw. Libgcc is often linked by default, and llvm has something equivalent. |
|
||||
| execinfo.h | `CPPTRACE_UNWIND_WITH_EXECINFO` | linux, macos | Frames are captured with `execinfo.h`'s `backtrace`, part of libc on linux/unix systems. |
|
||||
| winapi | `CPPTRACE_UNWIND_WITH_WINAPI` | windows, mingw | Frames are captured with `CaptureStackBackTrace`. |
|
||||
| dbghelp | `CPPTRACE_UNWIND_WITH_DBGHELP` | windows, mingw | Frames are captured with `StackWalk64`. |
|
||||
| dbghelp | `CPPTRACE_UNWIND_WITH_LIBUNWIND` | linux, macos, windows, mingw | Frames are captured with [libunwind](https://github.com/libunwind/libunwind). **Note:** This is the only back-end that requires a library to be installed by the user, and a `CMAKE_PREFIX_PATH` may also be needed. |
|
||||
| N/A | `CPPTRACE_UNWIND_WITH_NOTHING` | all | Unwinding is not done, stack traces will be empty. |
|
||||
|
||||
Some back-ends (execinfo and `CaptureStackBackTrace`) require a fixed buffer has to be created to read addresses into
|
||||
while unwinding. By default the buffer can hold addresses for 100 frames (beyond the `skip` frames). This is
|
||||
@ -634,6 +635,7 @@ Back-ends:
|
||||
- `CPPTRACE_GET_SYMBOLS_WITH_LIBDL=On/Off`
|
||||
- `CPPTRACE_GET_SYMBOLS_WITH_NOTHING=On/Off`
|
||||
- `CPPTRACE_UNWIND_WITH_UNWIND=On/Off`
|
||||
- `CPPTRACE_UNWIND_WITH_LIBUNWIND=On/Off`
|
||||
- `CPPTRACE_UNWIND_WITH_EXECINFO=On/Off`
|
||||
- `CPPTRACE_UNWIND_WITH_WINAPI=On/Off`
|
||||
- `CPPTRACE_UNWIND_WITH_DBGHELP=On/Off`
|
||||
|
||||
@ -151,6 +151,7 @@ def main():
|
||||
"unwind": [
|
||||
"CPPTRACE_UNWIND_WITH_UNWIND",
|
||||
"CPPTRACE_UNWIND_WITH_EXECINFO",
|
||||
"CPPTRACE_UNWIND_WITH_LIBUNWIND",
|
||||
"CPPTRACE_UNWIND_WITH_NOTHING",
|
||||
],
|
||||
"symbols": [
|
||||
|
||||
@ -319,6 +319,7 @@ def main():
|
||||
"unwind": [
|
||||
"CPPTRACE_UNWIND_WITH_EXECINFO",
|
||||
"CPPTRACE_UNWIND_WITH_UNWIND",
|
||||
"CPPTRACE_UNWIND_WITH_LIBUNWIND",
|
||||
#"CPPTRACE_UNWIND_WITH_NOTHING",
|
||||
],
|
||||
"symbols": [
|
||||
|
||||
@ -128,6 +128,7 @@ option(CPPTRACE_GET_SYMBOLS_WITH_NOTHING "" OFF)
|
||||
# ---- Unwinding Options ----
|
||||
|
||||
option(CPPTRACE_UNWIND_WITH_UNWIND "" OFF)
|
||||
option(CPPTRACE_UNWIND_WITH_LIBUNWIND "" OFF)
|
||||
option(CPPTRACE_UNWIND_WITH_EXECINFO "" OFF)
|
||||
option(CPPTRACE_UNWIND_WITH_WINAPI "" OFF)
|
||||
option(CPPTRACE_UNWIND_WITH_DBGHELP "" OFF)
|
||||
|
||||
42
src/unwind/unwind_with_libunwind.cpp
Normal file
42
src/unwind/unwind_with_libunwind.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
#ifdef CPPTRACE_UNWIND_WITH_LIBUNWIND
|
||||
|
||||
#include "unwind.hpp"
|
||||
#include "../platform/common.hpp"
|
||||
#include "../platform/error.hpp"
|
||||
#include "../platform/utils.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include <libunwind.h>
|
||||
|
||||
namespace cpptrace {
|
||||
namespace detail {
|
||||
CPPTRACE_FORCE_NO_INLINE
|
||||
std::vector<frame_ptr> capture_frames(std::size_t skip, std::size_t max_depth) {
|
||||
skip++;
|
||||
std::vector<frame_ptr> frames;
|
||||
unw_context_t context;
|
||||
unw_cursor_t cursor;
|
||||
unw_getcontext(&context);
|
||||
unw_init_local(&cursor, &context);
|
||||
do {
|
||||
unw_word_t pc;
|
||||
unw_word_t sp;
|
||||
unw_get_reg(&cursor, UNW_REG_IP, &pc);
|
||||
unw_get_reg(&cursor, UNW_REG_SP, &sp);
|
||||
if(skip) {
|
||||
skip--;
|
||||
} else {
|
||||
// pc is the instruction after the `call`, adjust back to the previous instruction
|
||||
frames.push_back(to_frame_ptr(pc) - 1);
|
||||
}
|
||||
} while(unw_step(&cursor) > 0 && frames.size() < max_depth);
|
||||
return frames;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user