Added C++23 stacktrace backend

This commit is contained in:
Jeremy 2023-07-02 14:58:10 -04:00
parent 69581c9d58
commit f56e8c5869
No known key found for this signature in database
GPG Key ID: BE03111EB7ED6E2E
5 changed files with 108 additions and 9 deletions

View File

@ -106,6 +106,34 @@ jobs:
-DLIBCPP_BACKTRACE_PATH=/usr/lib/gcc/x86_64-linux-gnu/10/include/backtrace.h \ -DLIBCPP_BACKTRACE_PATH=/usr/lib/gcc/x86_64-linux-gnu/10/include/backtrace.h \
${{matrix.config}} ${{matrix.config}}
make make
# TODO: -DCMAKE_CXX_STANDARD isn't being honored?
# build-linux-full-or-auto-23:
# runs-on: ubuntu-22.04
# strategy:
# fail-fast: false
# matrix:
# compiler: [g++-12, clang++-14]
# target: [Debug]
# std: [23]
# config: ["-DCPPTRACE_FULL_TRACE_WITH_STACKTRACE=On", ""]
# exclude:
# - config: "-DCPPTRACE_FULL_TRACE_WITH_STACKTRACE=On"
# compiler: clang++-14
# steps:
# - uses: actions/checkout@v2
# - name: dependencies
# run: sudo apt install gcc-12 g++-12 libgcc-12-dev
# - name: build
# run: |
# mkdir -p build
# cd build
# cmake .. \
# -DCMAKE_BUILD_TYPE=${{matrix.target}} \
# -DCMAKE_CXX_COMPILER=${{matrix.compiler}} \
# -DCMAKE_CXX_STANDARD=${{matrix.std}} \
# -DLIBCPP_BACKTRACE_PATH=/usr/lib/gcc/x86_64-linux-gnu/12/include/backtrace.h \
# ${{matrix.config}}
# make
build-windows-full-or-auto: build-windows-full-or-auto:
runs-on: windows-2019 runs-on: windows-2019
strategy: strategy:

View File

@ -27,11 +27,11 @@ target_include_directories(
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cpptrace/cpptrace> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cpptrace/cpptrace>
) )
target_compile_features( #target_compile_features(
cpptrace # cpptrace
PUBLIC # PUBLIC
cxx_std_11 # cxx_std_11
) #)
set_target_properties( set_target_properties(
cpptrace cpptrace
@ -48,6 +48,7 @@ target_compile_options(
) )
option(CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE "" OFF) option(CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE "" OFF)
option(CPPTRACE_FULL_TRACE_WITH_STACKTRACE "" OFF)
option(CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE "" OFF) option(CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE "" OFF)
option(CPPTRACE_GET_SYMBOLS_WITH_LIBDL "" OFF) option(CPPTRACE_GET_SYMBOLS_WITH_LIBDL "" OFF)
@ -92,13 +93,23 @@ endfunction()
check_support(HAS_EXECINFO has_execinfo.cpp "" "" "") check_support(HAS_EXECINFO has_execinfo.cpp "" "" "")
check_support(HAS_BACKTRACE has_backtrace.cpp "" "backtrace" "${LIBCPP_BACKTRACE_PATH_DEFINITION}") check_support(HAS_BACKTRACE has_backtrace.cpp "" "backtrace" "${LIBCPP_BACKTRACE_PATH_DEFINITION}")
check_support(HAS_CXXABI has_cxxabi.cpp "" "" "") check_support(HAS_CXXABI has_cxxabi.cpp "" "" "")
if(NOT MSVC)
set(STACKTRACE_LINK_LIB "stdc++_libbacktrace")
else()
set(STACKTRACE_LINK_LIB "")
endif()
check_support(HAS_STACKTRACE has_stacktrace.cpp "" "${STACKTRACE_LINK_LIB}" "")
# =============================================== Autoconfig full dump =============================================== # =============================================== Autoconfig full dump ===============================================
# If nothing is specified, attempt to use libbacktrace's full dump # If nothing is specified, attempt to use libbacktrace's full dump
if( if(
NOT ( NOT (
CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE OR CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE OR
CPPTRACE_FULL_TRACE_WITH_STACKTRACE OR
CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE OR CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE OR
CPPTRACE_GET_SYMBOLS_WITH_LIBDL OR
CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE OR
CPPTRACE_GET_SYMBOLS_WITH_DBGHELP OR
CPPTRACE_GET_SYMBOLS_WITH_NOTHING OR CPPTRACE_GET_SYMBOLS_WITH_NOTHING OR
CPPTRACE_UNWIND_WITH_EXECINFO OR CPPTRACE_UNWIND_WITH_EXECINFO OR
CPPTRACE_UNWIND_WITH_WINAPI OR CPPTRACE_UNWIND_WITH_WINAPI OR
@ -106,7 +117,10 @@ if(
) )
) )
# Attempt to auto-config # Attempt to auto-config
if(HAS_BACKTRACE) if(HAS_STACKTRACE AND NOT WIN32)
set(CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE On)
message(STATUS "Cpptrace auto config: Using C++23 <stacktrace> for the full trace")
elseif(HAS_BACKTRACE)
set(CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE On) set(CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE On)
message(STATUS "Cpptrace auto config: Using libbacktrace for the full trace") message(STATUS "Cpptrace auto config: Using libbacktrace for the full trace")
endif() endif()
@ -117,6 +131,7 @@ endif()
if( if(
NOT ( NOT (
CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE OR CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE OR
CPPTRACE_FULL_TRACE_WITH_STACKTRACE OR
CPPTRACE_UNWIND_WITH_EXECINFO OR CPPTRACE_UNWIND_WITH_EXECINFO OR
CPPTRACE_UNWIND_WITH_WINAPI OR CPPTRACE_UNWIND_WITH_WINAPI OR
CPPTRACE_UNWIND_WITH_NOTHING CPPTRACE_UNWIND_WITH_NOTHING
@ -144,7 +159,11 @@ endif()
if( if(
NOT ( NOT (
CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE OR CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE OR
CPPTRACE_FULL_TRACE_WITH_STACKTRACE OR
CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE OR CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE OR
CPPTRACE_GET_SYMBOLS_WITH_LIBDL OR
CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE OR
CPPTRACE_GET_SYMBOLS_WITH_DBGHELP OR
CPPTRACE_GET_SYMBOLS_WITH_NOTHING CPPTRACE_GET_SYMBOLS_WITH_NOTHING
) )
) )
@ -200,6 +219,14 @@ if(CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE)
target_link_libraries(cpptrace PRIVATE backtrace) target_link_libraries(cpptrace PRIVATE backtrace)
endif() endif()
if(CPPTRACE_FULL_TRACE_WITH_STACKTRACE)
if(NOT HAS_STACKTRACE)
message(WARNING "Cpptrace: CPPTRACE_FULL_TRACE_WITH_STACKTRACE specified but <stacktrace> doesn't seem to be available.")
endif()
target_compile_definitions(cpptrace PUBLIC CPPTRACE_FULL_TRACE_WITH_STACKTRACE)
target_link_libraries(cpptrace PRIVATE "${STACKTRACE_LINK_LIB}")
endif()
# Symbols # Symbols
if(CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE) if(CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE)
check_backtrace_error() check_backtrace_error()

View File

@ -67,7 +67,7 @@ can hold addresses for 100 frames. This is configurable with `CPPTRACE_HARD_MAX_
| libbacktrace | `CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE` | ❌ | ✔️ | Libbacktrace is already installed on most systems, or available through the compiler directly. If it is installed but backtrace.h is not already in the include path (this can happen when using clang when backtrace lives in gcc's include folder), `LIBCPP_BACKTRACE_PATH` can be used to specify where the library should be looked for. | | libbacktrace | `CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE` | ❌ | ✔️ | Libbacktrace is already installed on most systems, or available through the compiler directly. If it is installed but backtrace.h is not already in the include path (this can happen when using clang when backtrace lives in gcc's include folder), `LIBCPP_BACKTRACE_PATH` can be used to specify where the library should be looked for. |
| libdl | `CPPTRACE_GET_SYMBOLS_WITH_LIBDL` | ❌ | ✔️ | Libdl uses dynamic export information. Compiling with `-rdynamic` is often needed. | | libdl | `CPPTRACE_GET_SYMBOLS_WITH_LIBDL` | ❌ | ✔️ | Libdl uses dynamic export information. Compiling with `-rdynamic` is often needed. |
| addr2line | `CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE` | ❌ | ✔️ | Symbols are resolved by invoking `addr2line` via `fork()`. | | addr2line | `CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE` | ❌ | ✔️ | Symbols are resolved by invoking `addr2line` via `fork()`. |
| dbghelp.h | `CPPTRACE_GET_SYMBOLS_WITH_DBGHELP` | ✔️ | ❌ | Dbghelp.h allows access to symbols via debug info. | | dbghelp | `CPPTRACE_GET_SYMBOLS_WITH_DBGHELP` | ✔️ | ❌ | Dbghelp.h allows access to symbols via debug info. |
| N/A | `CPPTRACE_GET_SYMBOLS_WITH_NOTHING` | ✔️ | ✔️ | No attempt is made to resolve symbols. | | N/A | `CPPTRACE_GET_SYMBOLS_WITH_NOTHING` | ✔️ | ✔️ | No attempt is made to resolve symbols. |
**Demangling** **Demangling**
@ -83,8 +83,14 @@ mangled.
**Full tracing** **Full tracing**
Libbacktrace can generate a full stack trace itself, both unwinding and resolving symbols. This can be chosen with Libbacktrace can generate a full stack trace itself, both unwinding and resolving symbols. This can be chosen with
`CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE`. This is also the first configuration the auto config attempts to use. Full `CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE`. The auto config attempts to use this if it is available. Full tracing with
tracing with libbacktrace ignores `CPPTRACE_HARD_MAX_FRAMES`. libbacktrace ignores `CPPTRACE_HARD_MAX_FRAMES`.
`<stacktrace>` can of course also generate a full trace, if you're using >=C++23 and your compiler supports it. This is
controlled by `CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE`. The cmake script will attempt to auto configure to this if
possible. `CPPTRACE_HARD_MAX_FRAMES` is ignored.
**More?**
There are plenty more libraries that can be used for unwinding, parsing debug information, and demangling. In the future There are plenty more libraries that can be used for unwinding, parsing debug information, and demangling. In the future
more back-ends can be added. Ideally this library can "just work" on systems, without additional installation work. more back-ends can be added. Ideally this library can "just work" on systems, without additional installation work.

8
cmake/has_stacktrace.cpp Normal file
View File

@ -0,0 +1,8 @@
#include <stacktrace>
int main() {
std::stacktrace trace = std::stacktrace::current();
for(const auto entry : trace) {
(void)entry;
}
}

View File

@ -0,0 +1,30 @@
#ifdef CPPTRACE_FULL_TRACE_WITH_STACKTRACE
#include <cpptrace/cpptrace.hpp>
#include "libcpp_full_trace.hpp"
#include "../platform/libcpp_common.hpp"
#include <vector>
#include <stacktrace>
namespace cpptrace {
namespace detail {
CPPTRACE_FORCE_NO_INLINE
std::vector<stacktrace_frame> generate_trace(size_t skip) {
std::vector<stacktrace_frame> frames;
std::stacktrace trace = std::stacktrace::current(skip + 1);
for(const auto entry : trace) {
frames.push_back({
entry.native_handle(),
entry.source_line(),
-1,
entry.source_file(),
entry.description()
});
}
return frames;
}
}
}
#endif