Update how stacktraces are printed, add color, add a demo program, add a screenshot to the readme, and two small fixes to backends
This commit is contained in:
parent
927f5ea21e
commit
00d6f1c9d1
@ -68,6 +68,7 @@ option(CPPTRACE_DEMANGLE_WITH_CXXABI "" OFF)
|
|||||||
option(CPPTRACE_DEMANGLE_WITH_NOTHING "" OFF)
|
option(CPPTRACE_DEMANGLE_WITH_NOTHING "" OFF)
|
||||||
|
|
||||||
option(CPPTRACE_BUILD_TEST "" OFF)
|
option(CPPTRACE_BUILD_TEST "" OFF)
|
||||||
|
option(CPPTRACE_BUILD_DEMO "" OFF)
|
||||||
option(CPPTRACE_BUILD_TEST_RDYNAMIC "" OFF)
|
option(CPPTRACE_BUILD_TEST_RDYNAMIC "" OFF)
|
||||||
|
|
||||||
option(CPPTRACE_BUILD_SPEEDTEST "" OFF)
|
option(CPPTRACE_BUILD_SPEEDTEST "" OFF)
|
||||||
@ -408,6 +409,19 @@ if(CPPTRACE_BUILD_TEST)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(CPPTRACE_BUILD_DEMO)
|
||||||
|
add_executable(demo test/demo.cpp)
|
||||||
|
target_link_libraries(demo PRIVATE cpptrace)
|
||||||
|
# Clang has been fast to adopt dwarf 5, other tools (e.g. addr2line from binutils) have not
|
||||||
|
check_cxx_compiler_flag("-gdwarf-4" HAS_DWARF4)
|
||||||
|
if(HAS_DWARF4)
|
||||||
|
target_compile_options(demo PRIVATE "$<$<CONFIG:Debug>:-gdwarf-4>")
|
||||||
|
endif()
|
||||||
|
if(CPPTRACE_BUILD_TEST_RDYNAMIC)
|
||||||
|
set_property(TARGET demo PROPERTY ENABLE_EXPORTS ON)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
if(CPPTRACE_BUILD_SPEEDTEST)
|
if(CPPTRACE_BUILD_SPEEDTEST)
|
||||||
if(CPPTRACE_BUILD_SPEEDTEST_DWARF4)
|
if(CPPTRACE_BUILD_SPEEDTEST_DWARF4)
|
||||||
check_cxx_compiler_flag("-gdwarf-4" HAS_DWARF4)
|
check_cxx_compiler_flag("-gdwarf-4" HAS_DWARF4)
|
||||||
|
|||||||
@ -14,6 +14,8 @@ Some day C++23's `<stacktrace>` will be ubiquitous. And maybe one day the msvc i
|
|||||||
|
|
||||||
🚧 WIP: This library is in beta. 🏗️
|
🚧 WIP: This library is in beta. 🏗️
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Table of contents
|
## Table of contents
|
||||||
|
|
||||||
- [Cpptrace](#cpptrace)
|
- [Cpptrace](#cpptrace)
|
||||||
@ -187,9 +189,10 @@ General:
|
|||||||
`100`.
|
`100`.
|
||||||
|
|
||||||
Testing:
|
Testing:
|
||||||
- `CPPTRACE_BUILD_TEST`
|
- `CPPTRACE_BUILD_TEST` Build a small test program
|
||||||
- `CPPTRACE_BUILD_TEST_RDYNAMIC`
|
- `CPPTRACE_BUILD_DEMO` Build a small demo program
|
||||||
- `CPPTRACE_BUILD_SPEEDTEST`
|
- `CPPTRACE_BUILD_TEST_RDYNAMIC` Use `-rdynamic` when compiling the test program
|
||||||
|
- `CPPTRACE_BUILD_SPEEDTEST` Build a small speed test program
|
||||||
- `CPPTRACE_BUILD_SPEEDTEST_DWARF4`
|
- `CPPTRACE_BUILD_SPEEDTEST_DWARF4`
|
||||||
- `CPPTRACE_BUILD_SPEEDTEST_DWARF5`
|
- `CPPTRACE_BUILD_SPEEDTEST_DWARF5`
|
||||||
|
|
||||||
|
|||||||
BIN
res/screenshot.png
Normal file
BIN
res/screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
@ -4,6 +4,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#if !(defined(CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE) || defined(CPPTRACE_FULL_TRACE_WITH_STACKTRACE))
|
#if !(defined(CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE) || defined(CPPTRACE_FULL_TRACE_WITH_STACKTRACE))
|
||||||
@ -46,23 +47,55 @@ namespace cpptrace {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define ESC "\033["
|
||||||
|
#define RESET ESC "0m"
|
||||||
|
#define RED ESC "31m"
|
||||||
|
#define GREEN ESC "32m"
|
||||||
|
#define YELLOW ESC "33m"
|
||||||
|
#define BLUE ESC "34m"
|
||||||
|
#define MAGENTA ESC "35m"
|
||||||
|
#define CYAN ESC "36m"
|
||||||
|
|
||||||
namespace cpptrace {
|
namespace cpptrace {
|
||||||
void print_trace(std::uint32_t skip) {
|
void print_trace(std::uint32_t skip) {
|
||||||
|
enable_virtual_terminal_processing_if_needed();
|
||||||
std::cerr<<"Stack trace (most recent call first):"<<std::endl;
|
std::cerr<<"Stack trace (most recent call first):"<<std::endl;
|
||||||
std::size_t counter = 0;
|
std::size_t counter = 0;
|
||||||
const auto trace = generate_trace(skip + 1);
|
const auto trace = generate_trace(skip + 1);
|
||||||
// +1 to skip one frame
|
if(trace.empty()) {
|
||||||
for(auto it = trace.begin() + 1; it != trace.end(); it++) {
|
std::cerr<<"<empty trace>"<<std::endl;
|
||||||
const auto& frame = *it;
|
return;
|
||||||
|
}
|
||||||
|
const auto frame_number_width = n_digits(static_cast<int>(trace.size()) - 1);
|
||||||
|
for(const auto& frame : trace) {
|
||||||
std::cerr
|
std::cerr
|
||||||
|
<< '#'
|
||||||
|
<< std::setw(static_cast<int>(frame_number_width))
|
||||||
|
<< std::left
|
||||||
<< counter++
|
<< counter++
|
||||||
<< " "
|
<< " "
|
||||||
<< frame.filename
|
<< std::hex
|
||||||
<< ":"
|
<< BLUE
|
||||||
<< frame.line
|
<< "0x"
|
||||||
<< (frame.col > 0 ? ":" + std::to_string(frame.col) : "")
|
<< std::setw(2 * sizeof(uintptr_t))
|
||||||
<< " "
|
<< std::setfill('0')
|
||||||
|
<< frame.address
|
||||||
|
<< std::dec
|
||||||
|
<< std::setfill(' ')
|
||||||
|
<< RESET
|
||||||
|
<< " in "
|
||||||
|
<< YELLOW
|
||||||
<< frame.symbol
|
<< frame.symbol
|
||||||
|
<< RESET
|
||||||
|
<< " at "
|
||||||
|
<< GREEN
|
||||||
|
<< frame.filename
|
||||||
|
<< RESET
|
||||||
|
<< ":"
|
||||||
|
<< BLUE
|
||||||
|
<< frame.line
|
||||||
|
<< RESET
|
||||||
|
<< (frame.col > 0 ? ":" BLUE + std::to_string(frame.col) + RESET : "")
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,6 +28,9 @@ namespace cpptrace {
|
|||||||
trace_data& data = *reinterpret_cast<trace_data*>(data_pointer);
|
trace_data& data = *reinterpret_cast<trace_data*>(data_pointer);
|
||||||
if(data.skip > 0) {
|
if(data.skip > 0) {
|
||||||
data.skip--;
|
data.skip--;
|
||||||
|
} else if(address == uintptr_t(-1)) {
|
||||||
|
// sentinel for libbacktrace, stop tracing
|
||||||
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
data.frames.push_back({
|
data.frames.push_back({
|
||||||
address,
|
address,
|
||||||
|
|||||||
@ -57,6 +57,10 @@
|
|||||||
#error "Unsupported compiler"
|
#error "Unsupported compiler"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if IS_WINDOWS
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
// Lightweight std::source_location.
|
// Lightweight std::source_location.
|
||||||
struct source_location {
|
struct source_location {
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||||
@ -218,6 +222,34 @@ T byteswap(T value) {
|
|||||||
return byte_swapper<T, sizeof(T)>{}(value);
|
return byte_swapper<T, sizeof(T)>{}(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CPPTRACE_MAYBE_UNUSED
|
||||||
|
inline void enable_virtual_terminal_processing_if_needed() {
|
||||||
|
// enable colors / ansi processing if necessary
|
||||||
|
#if IS_WINDOWS
|
||||||
|
// https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#example-of-enabling-virtual-terminal-processing
|
||||||
|
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||||
|
constexpr DWORD ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4;
|
||||||
|
#endif
|
||||||
|
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
DWORD dwMode = 0;
|
||||||
|
if(hOut == INVALID_HANDLE_VALUE) return;
|
||||||
|
if(!GetConsoleMode(hOut, &dwMode)) return;
|
||||||
|
if(dwMode != (dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING))
|
||||||
|
if(!SetConsoleMode(hOut, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
CPPTRACE_MAYBE_UNUSED
|
||||||
|
// NOLINTNEXTLINE(misc-no-recursion)
|
||||||
|
inline constexpr unsigned n_digits(unsigned value) {
|
||||||
|
return value < 10 ? 1 : 1 + n_digits(value / 10);
|
||||||
|
}
|
||||||
|
static_assert(n_digits(1) == 1, "n_digits utility producing the wrong result");
|
||||||
|
static_assert(n_digits(9) == 1, "n_digits utility producing the wrong result");
|
||||||
|
static_assert(n_digits(10) == 2, "n_digits utility producing the wrong result");
|
||||||
|
static_assert(n_digits(11) == 2, "n_digits utility producing the wrong result");
|
||||||
|
static_assert(n_digits(1024) == 4, "n_digits utility producing the wrong result");
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -291,6 +291,9 @@ namespace cpptrace {
|
|||||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames) {
|
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames) {
|
||||||
// TODO: Refactor better
|
// TODO: Refactor better
|
||||||
std::vector<stacktrace_frame> trace(frames.size(), stacktrace_frame { 0, 0, 0, "", "" });
|
std::vector<stacktrace_frame> trace(frames.size(), stacktrace_frame { 0, 0, 0, "", "" });
|
||||||
|
for(size_t i = 0; i < frames.size(); i++) {
|
||||||
|
trace[i].address = reinterpret_cast<uintptr_t>(frames[i]);
|
||||||
|
}
|
||||||
if(has_addr2line()) {
|
if(has_addr2line()) {
|
||||||
const std::vector<dlframe> dlframes = backtrace_frames(frames);
|
const std::vector<dlframe> dlframes = backtrace_frames(frames);
|
||||||
const auto entries = get_addr2line_targets(dlframes, trace);
|
const auto entries = get_addr2line_targets(dlframes, trace);
|
||||||
|
|||||||
50
test/demo.cpp
Normal file
50
test/demo.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include <cpptrace/cpptrace.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
void trace() {
|
||||||
|
cpptrace::print_trace();
|
||||||
|
}
|
||||||
|
|
||||||
|
int x;
|
||||||
|
|
||||||
|
void foo(int n) {
|
||||||
|
if(n == 0) {
|
||||||
|
x = 0;
|
||||||
|
trace();
|
||||||
|
x = 0;
|
||||||
|
} else {
|
||||||
|
x = 0;
|
||||||
|
foo(n - 1);
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void foo(int x, Args... args) {
|
||||||
|
x = 0;
|
||||||
|
foo(args...);
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void function_two(int, float) {
|
||||||
|
x = 0;
|
||||||
|
foo(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void function_one(int) {
|
||||||
|
x = 0;
|
||||||
|
function_two(0, 0);
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
x = 0;
|
||||||
|
function_one(0);
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user