Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fac4d08fd0 | ||
|
|
c0354799c7 | ||
|
|
c37b5ed736 | ||
|
|
a32e22aa44 | ||
|
|
6cec10601e | ||
|
|
c9dc51aa61 | ||
|
|
e6d55b5e7d |
46
.github/workflows/ci.yml
vendored
46
.github/workflows/ci.yml
vendored
@ -25,6 +25,26 @@ jobs:
|
||||
- name: build and test
|
||||
run: |
|
||||
python3 ci/test-all-configs.py --${{matrix.compiler}} --default-config
|
||||
test-linux-arm:
|
||||
runs-on: ubuntu-22.04-arm
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
compiler: [gcc, clang]
|
||||
shared: [--shared, ""]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: dependencies
|
||||
run: |
|
||||
sudo apt install gcc-10 g++-10 libgcc-10-dev libunwind8-dev
|
||||
pip3 install colorama
|
||||
- name: libdwarf
|
||||
run: |
|
||||
cd ..
|
||||
cpptrace/ci/setup-prerequisites.sh
|
||||
- name: build and test
|
||||
run: |
|
||||
python3 ci/test-all-configs.py --${{matrix.compiler}} --default-config
|
||||
test-macos:
|
||||
runs-on: macos-14
|
||||
strategy:
|
||||
@ -562,6 +582,32 @@ jobs:
|
||||
- name: test opt
|
||||
run: |
|
||||
bazel test //... -c opt
|
||||
unittest-linux-arm:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
compiler: [g++-10, clang++-18]
|
||||
stdlib: [libstdc++, libc++]
|
||||
dwarf_version: [4, 5]
|
||||
split_dwarf: [OFF, ON]
|
||||
exclude:
|
||||
- compiler: g++-10
|
||||
stdlib: libc++
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: dependencies
|
||||
run: |
|
||||
sudo apt install gcc-10 g++-10 libgcc-10-dev ninja-build libc++-dev
|
||||
cd ..
|
||||
cpptrace/ci/setup-prerequisites-unittest.sh
|
||||
- name: build and test
|
||||
run: |
|
||||
python3 ci/unittest.py \
|
||||
--slice=compiler:${{matrix.compiler}} \
|
||||
--slice=stdlib:${{matrix.stdlib}} \
|
||||
--slice=dwarf_version:${{matrix.dwarf_version}} \
|
||||
--slice=split_dwarf:${{matrix.split_dwarf}}
|
||||
unittest-macos:
|
||||
runs-on: macos-14
|
||||
steps:
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
# Changelog
|
||||
|
||||
- [Changelog](#changelog)
|
||||
- [v0.8.2](#v082)
|
||||
- [v0.8.1](#v081)
|
||||
- [v0.8.0](#v080)
|
||||
- [v0.7.5](#v075)
|
||||
@ -27,6 +28,14 @@
|
||||
- [v0.1.1](#v011)
|
||||
- [v0.1](#v01)
|
||||
|
||||
# v0.8.2
|
||||
|
||||
Fixed:
|
||||
- Fixed printing of internal error messages when an object file can't be loaded, mainly affecting MacOS https://github.com/jeremy-rifkin/cpptrace/issues/217
|
||||
|
||||
Other:
|
||||
- Bumped zstd via FetchContent to 1.5.7
|
||||
|
||||
# v0.8.1
|
||||
|
||||
Fixed:
|
||||
|
||||
@ -9,7 +9,7 @@ set(package_name "cpptrace")
|
||||
|
||||
project(
|
||||
cpptrace
|
||||
VERSION 0.8.1
|
||||
VERSION 0.8.2
|
||||
DESCRIPTION "Simple, portable, and self-contained stacktrace library for C++11 and newer "
|
||||
HOMEPAGE_URL "https://github.com/jeremy-rifkin/cpptrace"
|
||||
LANGUAGES C CXX
|
||||
|
||||
95
README.md
95
README.md
@ -16,9 +16,6 @@ Cpptrace also has a C API, docs [here](docs/c-api.md).
|
||||
|
||||
- [30-Second Overview](#30-second-overview)
|
||||
- [CMake FetchContent Usage](#cmake-fetchcontent-usage)
|
||||
- [FAQ](#faq)
|
||||
- [What about C++23 `<stacktrace>`?](#what-about-c23-stacktrace)
|
||||
- [What does cpptrace have over other C++ stacktrace libraries?](#what-does-cpptrace-have-over-other-c-stacktrace-libraries)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Basic Usage](#basic-usage)
|
||||
- [`namespace cpptrace`](#namespace-cpptrace)
|
||||
@ -57,6 +54,10 @@ Cpptrace also has a C API, docs [here](docs/c-api.md).
|
||||
- [Summary of Library Configurations](#summary-of-library-configurations)
|
||||
- [Testing Methodology](#testing-methodology)
|
||||
- [Notes About the Library](#notes-about-the-library)
|
||||
- [FAQ](#faq)
|
||||
- [What about C++23 `<stacktrace>`?](#what-about-c23-stacktrace)
|
||||
- [What does cpptrace have over other C++ stacktrace libraries?](#what-does-cpptrace-have-over-other-c-stacktrace-libraries)
|
||||
- [I'm getting undefined standard library symbols like `std::__1::basic_string` on MacOS](#im-getting-undefined-standard-library-symbols-like-std__1basic_string-on-macos)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
|
||||
@ -138,7 +139,7 @@ include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
cpptrace
|
||||
GIT_REPOSITORY https://github.com/jeremy-rifkin/cpptrace.git
|
||||
GIT_TAG v0.8.1 # <HASH or TAG>
|
||||
GIT_TAG v0.8.2 # <HASH or TAG>
|
||||
)
|
||||
FetchContent_MakeAvailable(cpptrace)
|
||||
target_link_libraries(your_target cpptrace::cpptrace)
|
||||
@ -163,33 +164,6 @@ On macOS it is recommended to generate a `.dSYM` file, see [Platform Logistics](
|
||||
For other ways to use the library, such as through package managers, a system-wide installation, or on a platform
|
||||
without internet access see [How to Include The Library](#how-to-include-the-library) below.
|
||||
|
||||
# FAQ
|
||||
|
||||
## What about C++23 `<stacktrace>`?
|
||||
|
||||
Some day C++23's `<stacktrace>` will be ubiquitous. And maybe one day the msvc implementation will be acceptable.
|
||||
The original motivation for cpptrace was to support projects using older C++ standards and as the library has grown its
|
||||
functionality has extended beyond the standard library's implementation.
|
||||
|
||||
Cpptrace provides functionality beyond what the standard library provides and what implementations provide, such as:
|
||||
- Walking inlined function calls
|
||||
- Providing a lightweight interface for "raw traces"
|
||||
- Resolving function parameter types
|
||||
- Providing traced exception objects
|
||||
- Providing an API for signal-safe stacktrace generation
|
||||
- Providing a way to retrieve stack traces from arbitrary exceptions, not just special cpptrace traced exception
|
||||
objects. This is a feature coming to C++26, but cpptrace provides a solution for C++11.
|
||||
|
||||
## What does cpptrace have over other C++ stacktrace libraries?
|
||||
|
||||
Other C++ stacktrace libraries, such as boost stacktrace and backward-cpp, fall short when it comes to portability and
|
||||
ease of use. In testing, I found neither to provide adaquate coverage of various environments. Even when they can be
|
||||
made to work in an environment they require manual configuration from the end-user, possibly requiring manual
|
||||
installation of third-party dependencies. This is a highly undesirable burden to impose on users, especially when it is
|
||||
for a software package which just provides diagnostics as opposed to core functionality. Additionally, cpptrace provides
|
||||
support for resolving inlined calls by default for DWARF symbols (boost does not do this, backward-cpp can do this but
|
||||
only for some back-ends), better support for resolving full function signatures, and nicer API, among other features.
|
||||
|
||||
# Prerequisites
|
||||
|
||||
> [!IMPORTANT]
|
||||
@ -465,6 +439,8 @@ thrown exception object, with minimal or no overhead in the non-throwing path:
|
||||
|
||||
```cpp
|
||||
#include <cpptrace/from_current.hpp>
|
||||
#include <iostream>
|
||||
|
||||
void foo() {
|
||||
throw std::runtime_error("foo failed");
|
||||
}
|
||||
@ -929,7 +905,7 @@ include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
cpptrace
|
||||
GIT_REPOSITORY https://github.com/jeremy-rifkin/cpptrace.git
|
||||
GIT_TAG v0.8.1 # <HASH or TAG>
|
||||
GIT_TAG v0.8.2 # <HASH or TAG>
|
||||
)
|
||||
FetchContent_MakeAvailable(cpptrace)
|
||||
target_link_libraries(your_target cpptrace::cpptrace)
|
||||
@ -945,7 +921,7 @@ information.
|
||||
|
||||
```sh
|
||||
git clone https://github.com/jeremy-rifkin/cpptrace.git
|
||||
git checkout v0.8.1
|
||||
git checkout v0.8.2
|
||||
mkdir cpptrace/build
|
||||
cd cpptrace/build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release
|
||||
@ -988,7 +964,7 @@ you when installing new libraries.
|
||||
|
||||
```ps1
|
||||
git clone https://github.com/jeremy-rifkin/cpptrace.git
|
||||
git checkout v0.8.1
|
||||
git checkout v0.8.2
|
||||
mkdir cpptrace/build
|
||||
cd cpptrace/build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release
|
||||
@ -1006,7 +982,7 @@ To install just for the local user (or any custom prefix):
|
||||
|
||||
```sh
|
||||
git clone https://github.com/jeremy-rifkin/cpptrace.git
|
||||
git checkout v0.8.1
|
||||
git checkout v0.8.2
|
||||
mkdir cpptrace/build
|
||||
cd cpptrace/build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$HOME/wherever
|
||||
@ -1089,7 +1065,7 @@ make install
|
||||
cd ~/scratch/cpptrace-test
|
||||
git clone https://github.com/jeremy-rifkin/cpptrace.git
|
||||
cd cpptrace
|
||||
git checkout v0.8.1
|
||||
git checkout v0.8.2
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=On -DCPPTRACE_USE_EXTERNAL_LIBDWARF=On -DCMAKE_PREFIX_PATH=~/scratch/cpptrace-test/resources -DCMAKE_INSTALL_PREFIX=~/scratch/cpptrace-test/resources
|
||||
@ -1109,7 +1085,7 @@ cpptrace and its dependencies.
|
||||
Cpptrace is available through conan at https://conan.io/center/recipes/cpptrace.
|
||||
```
|
||||
[requires]
|
||||
cpptrace/0.8.1
|
||||
cpptrace/0.8.2
|
||||
[generators]
|
||||
CMakeDeps
|
||||
CMakeToolchain
|
||||
@ -1318,6 +1294,51 @@ A couple things I'd like to improve in the future:
|
||||
in dbghelp the library cannot accurately show const and volatile qualifiers or rvalue references (these appear as
|
||||
pointers).
|
||||
|
||||
# FAQ
|
||||
|
||||
## What about C++23 `<stacktrace>`?
|
||||
|
||||
Some day C++23's `<stacktrace>` will be ubiquitous. And maybe one day the msvc implementation will be acceptable.
|
||||
The original motivation for cpptrace was to support projects using older C++ standards and as the library has grown its
|
||||
functionality has extended beyond the standard library's implementation.
|
||||
|
||||
Cpptrace provides functionality beyond what the standard library provides and what implementations provide, such as:
|
||||
- Walking inlined function calls
|
||||
- Providing a lightweight interface for "raw traces"
|
||||
- Resolving function parameter types
|
||||
- Providing traced exception objects
|
||||
- Providing an API for signal-safe stacktrace generation
|
||||
- Providing a way to retrieve stack traces from arbitrary exceptions, not just special cpptrace traced exception
|
||||
objects. This is a feature coming to C++26, but cpptrace provides a solution for C++11.
|
||||
|
||||
## What does cpptrace have over other C++ stacktrace libraries?
|
||||
|
||||
Other C++ stacktrace libraries, such as boost stacktrace and backward-cpp, fall short when it comes to portability and
|
||||
ease of use. In testing, I found neither to provide adaquate coverage of various environments. Even when they can be
|
||||
made to work in an environment they require manual configuration from the end-user, possibly requiring manual
|
||||
installation of third-party dependencies. This is a highly undesirable burden to impose on users, especially when it is
|
||||
for a software package which just provides diagnostics as opposed to core functionality. Additionally, cpptrace provides
|
||||
support for resolving inlined calls by default for DWARF symbols (boost does not do this, backward-cpp can do this but
|
||||
only for some back-ends), better support for resolving full function signatures, and nicer API, among other features.
|
||||
|
||||
## I'm getting undefined standard library symbols like `std::__1::basic_string` on MacOS
|
||||
|
||||
If you see a linker error along the lines of the following on MacOS then it's highly likely you are mixing standard
|
||||
library ABIs.
|
||||
|
||||
```
|
||||
Undefined symbols for architecture arm64:
|
||||
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::find(char, unsigned long) const", referenced from:
|
||||
cpptrace::detail::demangle(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool) in libcpptrace.a(demangle_with_cxxabi.cpp.o)
|
||||
cpptrace::detail::snippet_manager::build_line_table() in libcpptrace.a(snippet.cpp.o)
|
||||
```
|
||||
|
||||
This can happen when using apple clang to compile cpptrace and gcc to compile your code, or vice versa. The reason is
|
||||
that apple clang defaults to libc++ and gcc defaults to libstdc++ and these two standard library implementations are not
|
||||
ABI-compatible. To resolve this, ensure you are compiling both cpptrace and your code with the same standard library by
|
||||
either using the same compiler for both or using `-stdlib=libc++`/`-stdlib=libstdc++` to control which standard library
|
||||
is used.
|
||||
|
||||
# Contributing
|
||||
|
||||
I'm grateful for the help I've received with this library and I welcome contributions! For information on contributing
|
||||
|
||||
@ -180,7 +180,7 @@ option(CPPTRACE_SKIP_UNIT "" OFF)
|
||||
option(CPPTRACE_STD_FORMAT "" ON)
|
||||
option(CPPTRACE_UNPREFIXED_TRY_CATCH "" OFF)
|
||||
option(CPPTRACE_USE_EXTERNAL_GTEST "" OFF)
|
||||
set(CPPTRACE_ZSTD_URL "https://github.com/facebook/zstd/releases/download/v1.5.6/zstd-1.5.6.tar.gz" CACHE STRING "")
|
||||
set(CPPTRACE_ZSTD_URL "https://github.com/facebook/zstd/releases/download/v1.5.7/zstd-1.5.7.tar.gz" CACHE STRING "")
|
||||
set(CPPTRACE_LIBDWARF_REPO "https://github.com/jeremy-rifkin/libdwarf-lite.git" CACHE STRING "")
|
||||
set(CPPTRACE_LIBDWARF_TAG "fe09ca800b988e2ff21225ac5e7468ceade2a30e" CACHE STRING "") # v0.11.1
|
||||
set(CPPTRACE_LIBDWARF_SHALLOW "1" CACHE STRING "")
|
||||
|
||||
@ -78,7 +78,9 @@ namespace detail {
|
||||
- reinterpret_cast<std::uintptr_t>(info.dli_fbase)
|
||||
+ base.unwrap_value();
|
||||
} else {
|
||||
base.drop_error();
|
||||
if(!should_absorb_trace_exceptions()) {
|
||||
base.drop_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
return frame;
|
||||
@ -101,7 +103,9 @@ namespace detail {
|
||||
- reinterpret_cast<std::uintptr_t>(info.dli_fbase)
|
||||
+ base.unwrap_value();
|
||||
} else {
|
||||
base.drop_error();
|
||||
if(!should_absorb_trace_exceptions()) {
|
||||
base.drop_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
return frame;
|
||||
@ -146,7 +150,9 @@ namespace detail {
|
||||
- reinterpret_cast<std::uintptr_t>(handle)
|
||||
+ base.unwrap_value();
|
||||
} else {
|
||||
base.drop_error();
|
||||
if(!should_absorb_trace_exceptions()) {
|
||||
base.drop_error();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::fprintf(stderr, "%s\n", std::system_error(GetLastError(), std::system_category()).what());
|
||||
|
||||
@ -208,18 +208,19 @@ namespace cpptrace {
|
||||
const auto yellow = color ? YELLOW : "";
|
||||
const auto blue = color ? BLUE : "";
|
||||
if(frame.is_inline) {
|
||||
microfmt::print(stream, "{<{}}", 2 * sizeof(frame_ptr) + 2, "(inlined)");
|
||||
} else {
|
||||
microfmt::print(stream, "{<{}} ", 2 * sizeof(frame_ptr) + 2, "(inlined)");
|
||||
} else if(options.addresses != address_mode::none) {
|
||||
auto address = options.addresses == address_mode::raw ? frame.raw_address : frame.object_address;
|
||||
microfmt::print(stream, "{}0x{>{}:0h}{}", blue, 2 * sizeof(frame_ptr), address, reset);
|
||||
microfmt::print(stream, "{}0x{>{}:0h}{} ", blue, 2 * sizeof(frame_ptr), address, reset);
|
||||
}
|
||||
if(!frame.symbol.empty()) {
|
||||
microfmt::print(stream, " in {}{}{}", yellow, frame.symbol, reset);
|
||||
microfmt::print(stream, "in {}{}{}", yellow, frame.symbol, reset);
|
||||
}
|
||||
if(!frame.filename.empty()) {
|
||||
microfmt::print(
|
||||
stream,
|
||||
" at {}{}{}",
|
||||
"{}at {}{}{}",
|
||||
frame.symbol.empty() ? "" : " ",
|
||||
green,
|
||||
options.paths == path_mode::full ? frame.filename : detail::basename(frame.filename, true),
|
||||
reset
|
||||
|
||||
@ -83,6 +83,8 @@ namespace detail {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Symbol resolution code should probably handle when object addresses are 0
|
||||
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<object_frame>& frames) {
|
||||
#if defined(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF) && defined(CPPTRACE_GET_SYMBOLS_WITH_DBGHELP)
|
||||
std::vector<stacktrace_frame> trace = libdwarf::resolve_frames(frames);
|
||||
|
||||
@ -96,6 +96,21 @@ TEST(FormatterTest, ObjectAddresses) {
|
||||
);
|
||||
}
|
||||
|
||||
TEST(FormatterTest, NoAddresses) {
|
||||
auto formatter = cpptrace::formatter{}
|
||||
.addresses(cpptrace::formatter::address_mode::none);
|
||||
auto res = split(formatter.format(make_test_stacktrace()), "\n");
|
||||
EXPECT_THAT(
|
||||
res,
|
||||
ElementsAre(
|
||||
"Stack trace (most recent call first):",
|
||||
"#0 in foo() at foo.cpp:20:30",
|
||||
"#1 in bar() at bar.cpp:30:40",
|
||||
"#2 in main at foo.cpp:40:25"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
TEST(FormatterTest, PathShortening) {
|
||||
cpptrace::stacktrace trace;
|
||||
trace.frames.push_back({0x1, 0x1001, {20}, {30}, "/home/foo/foo.cpp", "foo()", false});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user