Skip library frames when unwinding
This commit is contained in:
parent
bdc8410f82
commit
6c950e0817
@ -12,7 +12,7 @@ project(
|
|||||||
|
|
||||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||||
|
|
||||||
#set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
include(CheckCXXSourceCompiles)
|
include(CheckCXXSourceCompiles)
|
||||||
@ -63,6 +63,7 @@ option(LIBCPPTRACE_DEMANGLE_WITH_CXXABI "" OFF)
|
|||||||
option(LIBCPPTRACE_DEMANGLE_WITH_NOTHING "" OFF)
|
option(LIBCPPTRACE_DEMANGLE_WITH_NOTHING "" OFF)
|
||||||
|
|
||||||
set(LIBCPP_BACKTRACE_PATH "" CACHE STRING "Path to backtrace.h, if the compiler doesn't already know it. Check /usr/lib/gcc/x86_64-linux-gnu/*/include.")
|
set(LIBCPP_BACKTRACE_PATH "" CACHE STRING "Path to backtrace.h, if the compiler doesn't already know it. Check /usr/lib/gcc/x86_64-linux-gnu/*/include.")
|
||||||
|
set(LIBCPPTRACE_HARD_MAX_FRAMES "" CACHE STRING "Hard limit on unwinding depth. Default is 100.")
|
||||||
|
|
||||||
if(NOT "${LIBCPP_BACKTRACE_PATH}" STREQUAL "")
|
if(NOT "${LIBCPP_BACKTRACE_PATH}" STREQUAL "")
|
||||||
# quotes used over <> because of a macro substitution issue where
|
# quotes used over <> because of a macro substitution issue where
|
||||||
@ -254,6 +255,10 @@ if(NOT "${LIBCPP_BACKTRACE_PATH}" STREQUAL "")
|
|||||||
target_compile_definitions(cpptrace PUBLIC LIBCPP_BACKTRACE_PATH=${LIBCPP_BACKTRACE_PATH})
|
target_compile_definitions(cpptrace PUBLIC LIBCPP_BACKTRACE_PATH=${LIBCPP_BACKTRACE_PATH})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(NOT "${LIBCPPTRACE_HARD_MAX_FRAMES}" STREQUAL "")
|
||||||
|
target_compile_definitions(cpptrace PUBLIC LIBCPPTRACE_HARD_MAX_FRAMES=${LIBCPPTRACE_HARD_MAX_FRAMES})
|
||||||
|
endif()
|
||||||
|
|
||||||
# ======================================================================================================================
|
# ======================================================================================================================
|
||||||
|
|
||||||
#target_link_libraries(
|
#target_link_libraries(
|
||||||
|
|||||||
@ -57,6 +57,9 @@ also manually set which back-end you want used.
|
|||||||
| winapi | `LIBCPPTRACE_UNWIND_WITH_WINAPI` | ✔️ | ❌ | Frames are captured with `CaptureStackBackTrace`. |
|
| winapi | `LIBCPPTRACE_UNWIND_WITH_WINAPI` | ✔️ | ❌ | Frames are captured with `CaptureStackBackTrace`. |
|
||||||
| N/A | `LIBCPPTRACE_UNWIND_WITH_NOTHING` | ✔️ | ✔️ | Unwinding is not done, stack traces will be empty. |
|
| N/A | `LIBCPPTRACE_UNWIND_WITH_NOTHING` | ✔️ | ✔️ | Unwinding is not done, stack traces will be empty. |
|
||||||
|
|
||||||
|
Some back-ends require a fixed buffer has to be created to read addresses into while unwinding. By default the buffer
|
||||||
|
can hold addresses for 100 frames. This is configurable with `LIBCPPTRACE_HARD_MAX_FRAMES`.
|
||||||
|
|
||||||
**Symbol resolution**
|
**Symbol resolution**
|
||||||
|
|
||||||
| Library | CMake config | Windows | Linux | Info |
|
| Library | CMake config | Windows | Linux | Info |
|
||||||
@ -80,7 +83,8 @@ 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
|
||||||
`LIBCPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE`. This is also the first configuration the auto config attempts to use.
|
`LIBCPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE`. This is also the first configuration the auto config attempts to use. Full
|
||||||
|
tracing with libbacktrace ignores `LIBCPPTRACE_HARD_MAX_FRAMES`.
|
||||||
|
|
||||||
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.
|
||||||
|
|||||||
@ -10,10 +10,12 @@
|
|||||||
#include "symbols/libcpp_symbols.hpp"
|
#include "symbols/libcpp_symbols.hpp"
|
||||||
#include "unwind/libcpp_unwind.hpp"
|
#include "unwind/libcpp_unwind.hpp"
|
||||||
#include "demangle/libcpp_demangle.hpp"
|
#include "demangle/libcpp_demangle.hpp"
|
||||||
|
#include "platform/libcpp_common.hpp"
|
||||||
|
|
||||||
namespace cpptrace {
|
namespace cpptrace {
|
||||||
|
LIBCPPTRACE_FORCE_NO_INLINE
|
||||||
std::vector<stacktrace_frame> generate_trace() {
|
std::vector<stacktrace_frame> generate_trace() {
|
||||||
std::vector<void*> frames = detail::capture_frames();
|
std::vector<void*> frames = detail::capture_frames(1);
|
||||||
std::vector<stacktrace_frame> trace;
|
std::vector<stacktrace_frame> trace;
|
||||||
detail::symbolizer symbolizer;
|
detail::symbolizer symbolizer;
|
||||||
for(const auto frame : frames) {
|
for(const auto frame : frames) {
|
||||||
@ -33,8 +35,9 @@ namespace cpptrace {
|
|||||||
#include "demangle/libcpp_demangle.hpp"
|
#include "demangle/libcpp_demangle.hpp"
|
||||||
|
|
||||||
namespace cpptrace {
|
namespace cpptrace {
|
||||||
|
LIBCPPTRACE_FORCE_NO_INLINE
|
||||||
std::vector<stacktrace_frame> generate_trace() {
|
std::vector<stacktrace_frame> generate_trace() {
|
||||||
auto trace = detail::generate_trace();
|
auto trace = detail::generate_trace(1);
|
||||||
for(auto& entry : trace) {
|
for(auto& entry : trace) {
|
||||||
entry.symbol = detail::demangle(entry.symbol);
|
entry.symbol = detail::demangle(entry.symbol);
|
||||||
}
|
}
|
||||||
@ -48,12 +51,15 @@ namespace cpptrace {
|
|||||||
void print_trace() {
|
void print_trace() {
|
||||||
std::cerr<<"Stack trace (most recent call first):"<<std::endl;
|
std::cerr<<"Stack trace (most recent call first):"<<std::endl;
|
||||||
std::size_t i = 0;
|
std::size_t i = 0;
|
||||||
for(const auto& frame : generate_trace()) {
|
const auto trace = generate_trace();
|
||||||
|
// +1 to skip one frame
|
||||||
|
for(auto it = trace.begin() + 1; it != trace.end(); it++) {
|
||||||
|
const auto& frame = *it;
|
||||||
std::cerr
|
std::cerr
|
||||||
<< i++
|
<< i++
|
||||||
<< " "
|
<< " "
|
||||||
<< frame.filename
|
<< frame.filename
|
||||||
<< " at "
|
<< ":"
|
||||||
<< frame.line
|
<< frame.line
|
||||||
<< (frame.col > 0 ? ":" + std::to_string(frame.col) : "")
|
<< (frame.col > 0 ? ":" + std::to_string(frame.col) : "")
|
||||||
<< " "
|
<< " "
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include <cpptrace/cpptrace.hpp>
|
#include <cpptrace/cpptrace.hpp>
|
||||||
#include "libcpp_full_trace.hpp"
|
#include "libcpp_full_trace.hpp"
|
||||||
#include "../platform/libcpp_program_name.hpp"
|
#include "../platform/libcpp_program_name.hpp"
|
||||||
|
#include "../platform/libcpp_common.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -14,14 +15,24 @@
|
|||||||
|
|
||||||
namespace cpptrace {
|
namespace cpptrace {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
int full_callback(void* data, uintptr_t address, const char* file, int line, const char* symbol) {
|
struct trace_data {
|
||||||
reinterpret_cast<std::vector<stacktrace_frame>*>(data)->push_back({
|
std::vector<stacktrace_frame>& frames;
|
||||||
address,
|
size_t& skip;
|
||||||
line,
|
};
|
||||||
-1,
|
|
||||||
file ? file : "",
|
int full_callback(void* data_pointer, uintptr_t address, const char* file, int line, const char* symbol) {
|
||||||
symbol ? symbol : ""
|
trace_data& data = *reinterpret_cast<trace_data*>(data_pointer);
|
||||||
});
|
if(data.skip > 0) {
|
||||||
|
data.skip--;
|
||||||
|
} else {
|
||||||
|
data.frames.push_back({
|
||||||
|
address,
|
||||||
|
line,
|
||||||
|
-1,
|
||||||
|
file ? file : "",
|
||||||
|
symbol ? symbol : ""
|
||||||
|
});
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,9 +51,12 @@ namespace cpptrace {
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<stacktrace_frame> generate_trace() {
|
LIBCPPTRACE_FORCE_NO_INLINE
|
||||||
|
std::vector<stacktrace_frame> generate_trace(size_t skip) {
|
||||||
std::vector<stacktrace_frame> frames;
|
std::vector<stacktrace_frame> frames;
|
||||||
backtrace_full(get_backtrace_state(), 0, full_callback, error_callback, &frames);
|
skip++; // add one for this call
|
||||||
|
trace_data data { frames, skip };
|
||||||
|
backtrace_full(get_backtrace_state(), 0, full_callback, error_callback, &data);
|
||||||
return frames;
|
return frames;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,12 +2,15 @@
|
|||||||
#define LIBCPP_FULL_TRACE_HPP
|
#define LIBCPP_FULL_TRACE_HPP
|
||||||
|
|
||||||
#include <cpptrace/cpptrace.hpp>
|
#include <cpptrace/cpptrace.hpp>
|
||||||
|
#include "../platform/libcpp_common.hpp"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace cpptrace {
|
namespace cpptrace {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
std::vector<stacktrace_frame> generate_trace();
|
LIBCPPTRACE_FORCE_NO_INLINE
|
||||||
|
std::vector<stacktrace_frame> generate_trace(size_t skip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
10
src/platform/libcpp_common.hpp
Normal file
10
src/platform/libcpp_common.hpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef LIBCPP_COMMON_HPP
|
||||||
|
#define LIBCPP_COMMON_HPP
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define LIBCPPTRACE_FORCE_NO_INLINE __declspec(noinline)
|
||||||
|
#else
|
||||||
|
#define LIBCPPTRACE_FORCE_NO_INLINE __attribute__((noinline))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -2,6 +2,7 @@
|
|||||||
#define LIBCPP_UNWIND_HPP
|
#define LIBCPP_UNWIND_HPP
|
||||||
|
|
||||||
#include <cpptrace/cpptrace.hpp>
|
#include <cpptrace/cpptrace.hpp>
|
||||||
|
#include "../platform/libcpp_common.hpp"
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
@ -12,7 +13,8 @@ namespace cpptrace {
|
|||||||
#else
|
#else
|
||||||
constexpr size_t hard_max_frames = 100;
|
constexpr size_t hard_max_frames = 100;
|
||||||
#endif
|
#endif
|
||||||
std::vector<void*> capture_frames();
|
LIBCPPTRACE_FORCE_NO_INLINE
|
||||||
|
std::vector<void*> capture_frames(size_t skip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,17 +2,21 @@
|
|||||||
|
|
||||||
#include <cpptrace/cpptrace.hpp>
|
#include <cpptrace/cpptrace.hpp>
|
||||||
#include "libcpp_unwind.hpp"
|
#include "libcpp_unwind.hpp"
|
||||||
|
#include "../platform/libcpp_common.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <execinfo.h>
|
#include <execinfo.h>
|
||||||
|
|
||||||
namespace cpptrace {
|
namespace cpptrace {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
std::vector<void*> capture_frames() {
|
LIBCPPTRACE_FORCE_NO_INLINE
|
||||||
std::vector<void*> frames(hard_max_frames, nullptr);
|
std::vector<void*> capture_frames(size_t skip) {
|
||||||
int n_frames = backtrace(frames.data(), hard_max_frames);
|
std::vector<void*> frames(hard_max_frames + skip, nullptr);
|
||||||
|
int n_frames = backtrace(frames.data(), hard_max_frames + skip);
|
||||||
frames.resize(n_frames);
|
frames.resize(n_frames);
|
||||||
|
frames.erase(frames.begin(), frames.begin() + std::min(skip + 1, frames.size()));
|
||||||
frames.shrink_to_fit();
|
frames.shrink_to_fit();
|
||||||
return frames;
|
return frames;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace cpptrace {
|
namespace cpptrace {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
std::vector<void*> capture_frames() {
|
std::vector<void*> capture_frames(size_t) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <cpptrace/cpptrace.hpp>
|
#include <cpptrace/cpptrace.hpp>
|
||||||
#include "libcpp_unwind.hpp"
|
#include "libcpp_unwind.hpp"
|
||||||
|
#include "../platform/libcpp_common.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -9,9 +10,10 @@
|
|||||||
|
|
||||||
namespace cpptrace {
|
namespace cpptrace {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
std::vector<void*> capture_frames() {
|
LIBCPPTRACE_FORCE_NO_INLINE
|
||||||
|
std::vector<void*> capture_frames(size_t skip) {
|
||||||
std::vector<PVOID> addrs(hard_max_frames, nullptr);
|
std::vector<PVOID> addrs(hard_max_frames, nullptr);
|
||||||
int frames = CaptureStackBackTrace(0, hard_max_frames, addrs.data(), NULL);
|
int frames = CaptureStackBackTrace(static_cast<DWORD>(skip + 1), hard_max_frames, addrs.data(), NULL);
|
||||||
addrs.resize(frames);
|
addrs.resize(frames);
|
||||||
addrs.shrink_to_fit();
|
addrs.shrink_to_fit();
|
||||||
return addrs;
|
return addrs;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user