Some CI and cmake changes (#9)
This commit is contained in:
parent
f28c2cac3a
commit
04f8b88efd
6
.clang-tidy
Normal file
6
.clang-tidy
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
Checks: '-*,clang-diagnostic-*,clang-analyzer-*,bugprone-*,cert-*,clang-analyzer-*,concurrency-*,cppcoreguidelines-*,misc-*,modernize-*,performance-*,portability-*,readability-*,-cppcoreguidelines-macro-usage,-modernize-use-trailing-return-type,-misc-non-private-member-variables-in-classes,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-avoid-c-arrays,-modernize-avoid-c-arrays,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-readability-else-after-return,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cert-dcl50-cpp,-cppcoreguidelines-init-variables,-readability-implicit-bool-conversion,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-owning-memory,-cppcoreguidelines-pro-type-member-init,-readability-isolate-declaration,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-pro-type-cstyle-cast,-readability-named-parameter,-cppcoreguidelines-avoid-goto,-readability-uppercase-literal-suffix,-performance-avoid-endl,-bugprone-easily-swappable-parameters'
|
||||
WarningsAsErrors: '*'
|
||||
HeaderFilterRegex: ''
|
||||
AnalyzeTemporaryDtors: false
|
||||
FormatStyle: none
|
||||
8
.github/workflows/build.yml
vendored
8
.github/workflows/build.yml
vendored
@ -43,7 +43,7 @@ jobs:
|
||||
-D${{matrix.symbols}}=On \
|
||||
-D${{matrix.demangle}}=On \
|
||||
-DCPPTRACE_BACKTRACE_PATH=/usr/lib/gcc/x86_64-linux-gnu/10/include/backtrace.h
|
||||
make
|
||||
make -j
|
||||
build-macos:
|
||||
runs-on: macos-13
|
||||
strategy:
|
||||
@ -79,7 +79,7 @@ jobs:
|
||||
-D${{matrix.unwind}}=On \
|
||||
-D${{matrix.symbols}}=On \
|
||||
-D${{matrix.demangle}}=On
|
||||
make
|
||||
make -j
|
||||
build-windows:
|
||||
runs-on: windows-2019
|
||||
strategy:
|
||||
@ -143,7 +143,7 @@ jobs:
|
||||
-DCMAKE_CXX_STANDARD=${{matrix.std}} \
|
||||
-DCPPTRACE_BACKTRACE_PATH=/usr/lib/gcc/x86_64-linux-gnu/10/include/backtrace.h \
|
||||
${{matrix.config}}
|
||||
make
|
||||
make -j
|
||||
build-macos-full-or-auto:
|
||||
runs-on: macos-13
|
||||
strategy:
|
||||
@ -164,7 +164,7 @@ jobs:
|
||||
-DCMAKE_CXX_COMPILER=${{matrix.compiler}} \
|
||||
-DCMAKE_CXX_STANDARD=${{matrix.std}} \
|
||||
${{matrix.config}}
|
||||
make
|
||||
make -j
|
||||
# TODO: -DCMAKE_CXX_STANDARD isn't being honored?
|
||||
# build-linux-full-or-auto-23:
|
||||
# runs-on: ubuntu-22.04
|
||||
|
||||
18
.github/workflows/lint.yml
vendored
Normal file
18
.github/workflows/lint.yml
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
name: lint
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: dependencies
|
||||
run: |
|
||||
sudo apt install clang-tidy
|
||||
- name: clang-tidy
|
||||
run: |
|
||||
chmod +x lint.sh
|
||||
./lint.sh -DCPPTRACE_BACKTRACE_PATH=\"/usr/lib/gcc/x86_64-linux-gnu/10/include/backtrace.h\"
|
||||
2
.github/workflows/performance-tests.yml
vendored
2
.github/workflows/performance-tests.yml
vendored
@ -37,7 +37,7 @@ jobs:
|
||||
-DCPPTRACE_BACKTRACE_PATH=/usr/lib/gcc/x86_64-linux-gnu/11/include/backtrace.h \
|
||||
-DCPPTRACE_BUILD_SPEEDTEST=On \
|
||||
-DBUILD_SHARED_LIBS=On
|
||||
make
|
||||
make -j
|
||||
- name: test
|
||||
working-directory: build
|
||||
run: |
|
||||
|
||||
8
.github/workflows/test.yml
vendored
8
.github/workflows/test.yml
vendored
@ -48,7 +48,7 @@ jobs:
|
||||
-DCPPTRACE_BUILD_TEST=On \
|
||||
$(if [ "${{matrix.symbols}}" = "CPPTRACE_GET_SYMBOLS_WITH_LIBDL" ]; then echo "-DCPPTRACE_BUILD_TEST_RDYNAMIC=On"; else echo ""; fi) \
|
||||
-DBUILD_SHARED_LIBS=On
|
||||
make
|
||||
make -j
|
||||
- name: test
|
||||
working-directory: build
|
||||
run: |
|
||||
@ -91,7 +91,7 @@ jobs:
|
||||
-DCPPTRACE_BUILD_TEST=On \
|
||||
$(if [ "${{matrix.symbols}}" = "CPPTRACE_GET_SYMBOLS_WITH_LIBDL" ]; then echo "-DCPPTRACE_BUILD_TEST_RDYNAMIC=On"; else echo ""; fi) \
|
||||
-DBUILD_SHARED_LIBS=On
|
||||
make
|
||||
make -j
|
||||
- name: test
|
||||
working-directory: build
|
||||
run: |
|
||||
@ -168,7 +168,7 @@ jobs:
|
||||
${{matrix.config}} \
|
||||
-DCPPTRACE_BUILD_TEST=On \
|
||||
-DBUILD_SHARED_LIBS=On
|
||||
make
|
||||
make -j
|
||||
- name: test
|
||||
working-directory: build
|
||||
run: |
|
||||
@ -195,7 +195,7 @@ jobs:
|
||||
${{matrix.config}} \
|
||||
-DCPPTRACE_BUILD_TEST=On \
|
||||
-DBUILD_SHARED_LIBS=On
|
||||
make
|
||||
make -j
|
||||
- name: test
|
||||
working-directory: build
|
||||
run: |
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,6 +1,4 @@
|
||||
.vscode
|
||||
build
|
||||
build2
|
||||
a.out
|
||||
test/build
|
||||
repro*/
|
||||
build*
|
||||
repro*
|
||||
|
||||
@ -6,7 +6,7 @@ endif()
|
||||
|
||||
project(
|
||||
cpptrace
|
||||
VERSION 1.0.0
|
||||
VERSION 0.0.1
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
@ -28,6 +28,7 @@ target_include_directories(
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cpptrace/cpptrace>
|
||||
)
|
||||
|
||||
# TODO
|
||||
target_compile_features(
|
||||
cpptrace
|
||||
PUBLIC
|
||||
@ -44,7 +45,8 @@ set_target_properties(
|
||||
target_compile_options(
|
||||
cpptrace
|
||||
PRIVATE
|
||||
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -Werror=return-type -Wshadow>
|
||||
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -Werror=return-type -Wshadow -Wundef>
|
||||
$<$<CXX_COMPILER_ID:GNU>:-Wuseless-cast -Wnonnull-compare>
|
||||
$<$<CXX_COMPILER_ID:MSVC>:/W4 /WX /permissive->
|
||||
)
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#ifndef CPPTRACE_HPP
|
||||
#define CPPTRACE_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
14
lint.sh
Normal file
14
lint.sh
Normal file
@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
status=0
|
||||
while read f
|
||||
do
|
||||
echo checking $f
|
||||
flags="-DCPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE -DCPPTRACE_FULL_TRACE_WITH_STACKTRACE -DCPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE -DCPPTRACE_GET_SYMBOLS_WITH_LIBDL -DCPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE -DCPPTRACE_GET_SYMBOLS_WITH_NOTHING -DCPPTRACE_UNWIND_WITH_EXECINFO -DCPPTRACE_UNWIND_WITH_NOTHING -DCPPTRACE_DEMANGLE_WITH_CXXABI -DCPPTRACE_DEMANGLE_WITH_NOTHING"
|
||||
clang-tidy $f -- -std=c++11 -Iinclude $@ $flags
|
||||
ret=$?
|
||||
if [ $ret -ne 0 ]; then
|
||||
status=1
|
||||
fi
|
||||
done <<< $(find include src -name "*.hpp" -o -name "*.cpp" -not -path "test/speedtest.cpp" -not -path "src/full/full_trace_with_stacktrace.cpp")
|
||||
exit $status
|
||||
@ -1,6 +1,7 @@
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
@ -48,13 +49,13 @@ namespace cpptrace {
|
||||
namespace cpptrace {
|
||||
void print_trace(std::uint32_t skip) {
|
||||
std::cerr<<"Stack trace (most recent call first):"<<std::endl;
|
||||
std::size_t i = 0;
|
||||
std::size_t counter = 0;
|
||||
const auto trace = generate_trace(skip + 1);
|
||||
// +1 to skip one frame
|
||||
for(auto it = trace.begin() + 1; it != trace.end(); it++) {
|
||||
const auto& frame = *it;
|
||||
std::cerr
|
||||
<< i++
|
||||
<< counter++
|
||||
<< " "
|
||||
<< frame.filename
|
||||
<< ":"
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
#ifndef CPPTRACE_DEMANGLE_HPP
|
||||
#define CPPTRACE_DEMANGLE_HPP
|
||||
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace cpptrace {
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#ifdef CPPTRACE_DEMANGLE_WITH_CXXABI
|
||||
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
#include "cpptrace_demangle.hpp"
|
||||
|
||||
#include <cxxabi.h>
|
||||
@ -14,9 +13,10 @@ namespace cpptrace {
|
||||
int status;
|
||||
char* demangled = abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status);
|
||||
if(demangled) {
|
||||
std::string s = demangled;
|
||||
std::string str = demangled;
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
|
||||
free(demangled);
|
||||
return s;
|
||||
return str;
|
||||
} else {
|
||||
return name;
|
||||
}
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
#ifdef CPPTRACE_DEMANGLE_WITH_NOTHING
|
||||
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
#include "cpptrace_demangle.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
namespace cpptrace {
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
#ifdef CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE
|
||||
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
#include "cpptrace_full_trace.hpp"
|
||||
#include "../platform/cpptrace_program_name.hpp"
|
||||
#include "../platform/cpptrace_common.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#ifdef CPPTRACE_BACKTRACE_PATH
|
||||
@ -16,7 +17,9 @@
|
||||
namespace cpptrace {
|
||||
namespace detail {
|
||||
struct trace_data {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
std::vector<stacktrace_frame>& frames;
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
size_t& skip;
|
||||
};
|
||||
|
||||
@ -47,6 +50,7 @@ namespace cpptrace {
|
||||
|
||||
backtrace_state* get_backtrace_state() {
|
||||
// backtrace_create_state must be called only one time per program
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
static backtrace_state* state = nullptr;
|
||||
static bool called = false;
|
||||
if(!called) {
|
||||
@ -67,7 +71,7 @@ namespace cpptrace {
|
||||
// fallback, try to at least recover the symbol name with backtrace_syminfo
|
||||
backtrace_syminfo(
|
||||
get_backtrace_state(),
|
||||
reinterpret_cast<uintptr_t>(frame.address),
|
||||
frame.address,
|
||||
syminfo_callback,
|
||||
error_callback,
|
||||
&frame
|
||||
|
||||
@ -13,16 +13,21 @@
|
||||
#define CPPTRACE_MAYBE_UNUSED __attribute__((unused))
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <ios>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// Lightweight std::source_location.
|
||||
struct source_location {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
const char* const file;
|
||||
//const char* const function; // disabled for now due to static constexpr restrictions
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
const int line;
|
||||
constexpr source_location(
|
||||
//const char* _function /*= __builtin_FUNCTION()*/,
|
||||
@ -44,14 +49,20 @@ static void primitive_assert_impl(
|
||||
const char* action = verify ? "verification" : "assertion";
|
||||
const char* name = verify ? "verify" : "assert";
|
||||
if(message == nullptr) {
|
||||
fprintf(stderr, "Cpptrace %s failed at %s:%d: %s\n",
|
||||
action, location.file, location.line, signature);
|
||||
(void) fprintf(
|
||||
stderr,
|
||||
"Cpptrace %s failed at %s:%d: %s\n",
|
||||
action, location.file, location.line, signature
|
||||
);
|
||||
} else {
|
||||
fprintf(stderr, "Cpptrace %s failed at %s:%d: %s: %s\n",
|
||||
action, location.file, location.line, signature, message);
|
||||
(void) fprintf(
|
||||
stderr,
|
||||
"Cpptrace %s failed at %s:%d: %s: %s\n",
|
||||
action, location.file, location.line, signature, message
|
||||
);
|
||||
}
|
||||
fprintf(stderr, " primitive_%s(%s);\n", name, expression);
|
||||
abort();
|
||||
(void) fprintf(stderr, " primitive_%s(%s);\n", name, expression);
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,15 +81,15 @@ void nothing() {}
|
||||
#endif
|
||||
|
||||
CPPTRACE_MAYBE_UNUSED
|
||||
static std::vector<std::string> split(const std::string& s, const std::string& delims) {
|
||||
static std::vector<std::string> split(const std::string& str, const std::string& delims) {
|
||||
std::vector<std::string> vec;
|
||||
size_t old_pos = 0;
|
||||
size_t pos = 0;
|
||||
while((pos = s.find_first_of(delims, old_pos)) != std::string::npos) {
|
||||
vec.emplace_back(s.substr(old_pos, pos - old_pos));
|
||||
while((pos = str.find_first_of(delims, old_pos)) != std::string::npos) {
|
||||
vec.emplace_back(str.substr(old_pos, pos - old_pos));
|
||||
old_pos = pos + 1;
|
||||
}
|
||||
vec.emplace_back(std::string(s.substr(old_pos)));
|
||||
vec.emplace_back(str.substr(old_pos));
|
||||
return vec;
|
||||
}
|
||||
|
||||
@ -98,22 +109,22 @@ static std::string join(const C& container, const std::string& delim) {
|
||||
return str;
|
||||
}
|
||||
|
||||
constexpr const char* const ws = " \t\n\r\f\v";
|
||||
constexpr const char* const whitespace = " \t\n\r\f\v";
|
||||
|
||||
CPPTRACE_MAYBE_UNUSED
|
||||
static std::string trim(const std::string& s) {
|
||||
if(s == "") {
|
||||
static std::string trim(const std::string& str) {
|
||||
if(str.empty()) {
|
||||
return "";
|
||||
}
|
||||
size_t l = s.find_first_not_of(ws);
|
||||
size_t r = s.find_last_not_of(ws) + 1;
|
||||
return s.substr(l, r - l);
|
||||
const size_t left = str.find_first_not_of(whitespace);
|
||||
const size_t right = str.find_last_not_of(whitespace) + 1;
|
||||
return str.substr(left, right - left);
|
||||
}
|
||||
|
||||
CPPTRACE_MAYBE_UNUSED
|
||||
static std::string to_hex(uintptr_t addr) {
|
||||
std::stringstream sstream;
|
||||
sstream<<std::hex<<uintptr_t(addr);
|
||||
sstream<<std::hex<<addr;
|
||||
return std::move(sstream).str();
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
|
||||
namespace cpptrace {
|
||||
@ -20,7 +20,7 @@ namespace cpptrace {
|
||||
}
|
||||
}
|
||||
|
||||
#elif __APPLE__
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
#include <cstdint>
|
||||
#include <mach-o/dyld.h>
|
||||
@ -42,8 +42,9 @@ namespace cpptrace {
|
||||
}
|
||||
}
|
||||
|
||||
#elif __linux__
|
||||
#elif defined(__linux__)
|
||||
#include <linux/limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace cpptrace {
|
||||
@ -55,11 +56,11 @@ namespace cpptrace {
|
||||
if(!did_init) {
|
||||
did_init = true;
|
||||
char buffer[PATH_MAX + 1];
|
||||
ssize_t s = readlink("/proc/self/exe", buffer, PATH_MAX);
|
||||
if(s == -1) {
|
||||
const ssize_t size = readlink("/proc/self/exe", buffer, PATH_MAX);
|
||||
if(size == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
buffer[s] = 0;
|
||||
buffer[size] = 0;
|
||||
name = buffer;
|
||||
valid = true;
|
||||
}
|
||||
|
||||
@ -8,13 +8,13 @@
|
||||
|
||||
namespace cpptrace {
|
||||
namespace detail {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
|
||||
class symbolizer {
|
||||
struct impl;
|
||||
std::unique_ptr<impl> pimpl;
|
||||
public:
|
||||
symbolizer();
|
||||
~symbolizer();
|
||||
//stacktrace_frame resolve_frame(void* addr);
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames);
|
||||
};
|
||||
}
|
||||
|
||||
@ -4,13 +4,17 @@
|
||||
#include "cpptrace_symbols.hpp"
|
||||
#include "../platform/cpptrace_common.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
// NOLINTNEXTLINE(misc-include-cleaner)
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
@ -28,7 +32,7 @@ namespace cpptrace {
|
||||
// reference: https://github.com/bminor/glibc/blob/master/debug/backtracesyms.c
|
||||
std::vector<dlframe> frames;
|
||||
frames.reserve(addrs.size());
|
||||
for(const auto addr : addrs) {
|
||||
for(const void* addr : addrs) {
|
||||
Dl_info info;
|
||||
dlframe frame;
|
||||
frame.raw_address = reinterpret_cast<uintptr_t>(addr);
|
||||
@ -47,16 +51,18 @@ namespace cpptrace {
|
||||
bool has_addr2line() {
|
||||
// Detects if addr2line exists by trying to invoke addr2line --help
|
||||
constexpr int magic = 42;
|
||||
pid_t pid = fork();
|
||||
// NOLINTNEXTLINE(misc-include-cleaner)
|
||||
const pid_t pid = fork();
|
||||
if(pid == -1) { return false; }
|
||||
if(pid == 0) { // child
|
||||
close(STDOUT_FILENO);
|
||||
// TODO: path
|
||||
execlp("addr2line", "addr2line", "--help", nullptr);
|
||||
exit(magic);
|
||||
_exit(magic);
|
||||
}
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
// NOLINTNEXTLINE(misc-include-cleaner)
|
||||
return WEXITSTATUS(status) == 0;
|
||||
}
|
||||
|
||||
@ -71,12 +77,13 @@ namespace cpptrace {
|
||||
};
|
||||
static_assert(sizeof(pipe_t) == 2 * sizeof(int), "Unexpected struct packing");
|
||||
|
||||
static std::string resolve_addresses(const std::string& addresses, const std::string& executable) {
|
||||
std::string resolve_addresses(const std::string& addresses, const std::string& executable) {
|
||||
pipe_t output_pipe;
|
||||
pipe_t input_pipe;
|
||||
internal_verify(pipe(output_pipe.data) == 0);
|
||||
internal_verify(pipe(input_pipe.data) == 0);
|
||||
pid_t pid = fork();
|
||||
// NOLINTNEXTLINE(misc-include-cleaner)
|
||||
const pid_t pid = fork();
|
||||
if(pid == -1) { return ""; } // error? TODO: Diagnostic
|
||||
if(pid == 0) { // child
|
||||
dup2(output_pipe.write_end, STDOUT_FILENO);
|
||||
@ -107,24 +114,68 @@ namespace cpptrace {
|
||||
}
|
||||
|
||||
struct symbolizer::impl {
|
||||
using target_vec = std::vector<std::pair<std::string, std::reference_wrapper<stacktrace_frame>>>;
|
||||
|
||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||
std::unordered_map<std::string, target_vec> get_addr2line_targets(
|
||||
const std::vector<dlframe>& dlframes,
|
||||
std::vector<stacktrace_frame>& trace
|
||||
) {
|
||||
std::unordered_map<std::string, target_vec> entries;
|
||||
for(std::size_t i = 0; i < dlframes.size(); i++) {
|
||||
const auto& entry = dlframes[i];
|
||||
entries[entry.obj_path].emplace_back(
|
||||
to_hex(entry.raw_address - entry.obj_base),
|
||||
trace[i]
|
||||
);
|
||||
// Set what is known for now, and resolutions from addr2line should overwrite
|
||||
trace[i].filename = entry.obj_path;
|
||||
trace[i].symbol = entry.symbol;
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||
void update_trace(const std::string& line, size_t entry_index, const target_vec& entries_vec) {
|
||||
// Result will be of the form <identifier> " at " path:line
|
||||
// The path may be ?? if addr2line cannot resolve, line may be ?
|
||||
// Edge cases:
|
||||
// ?? ??:0
|
||||
const std::size_t at_location = line.find(" at ");
|
||||
std::size_t symbol_end;
|
||||
std::size_t filename_start;
|
||||
if(at_location != std::string::npos) {
|
||||
symbol_end = at_location;
|
||||
filename_start = at_location + 4;
|
||||
} else {
|
||||
internal_verify(line.find("?? ") == 0, "Unexpected edge case while processing addr2line output");
|
||||
symbol_end = 2;
|
||||
filename_start = 3;
|
||||
}
|
||||
auto symbol = line.substr(0, symbol_end);
|
||||
auto colon = line.rfind(':');
|
||||
internal_verify(colon != std::string::npos);
|
||||
internal_verify(colon > filename_start);
|
||||
auto filename = line.substr(filename_start, colon - filename_start);
|
||||
auto line_number = line.substr(colon + 1);
|
||||
if(line_number != "?") {
|
||||
entries_vec[entry_index].second.get().line = std::stoi(line_number);
|
||||
}
|
||||
if(filename != "??") {
|
||||
entries_vec[entry_index].second.get().filename = filename;
|
||||
}
|
||||
if(!symbol.empty()) {
|
||||
entries_vec[entry_index].second.get().symbol = symbol;
|
||||
}
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames) {
|
||||
// TODO: Refactor better
|
||||
std::vector<stacktrace_frame> trace(frames.size(), stacktrace_frame { 0, 0, 0, "", "" });
|
||||
if(has_addr2line()) {
|
||||
std::vector<dlframe> dlframes = backtrace_frames(frames);
|
||||
std::unordered_map<
|
||||
std::string,
|
||||
std::vector<std::pair<std::string, std::reference_wrapper<stacktrace_frame>>>
|
||||
> entries;
|
||||
for(size_t i = 0; i < dlframes.size(); i++) {
|
||||
const auto& entry = dlframes[i];
|
||||
entries[entry.obj_path].push_back({
|
||||
to_hex(entry.raw_address - entry.obj_base),
|
||||
trace[i]
|
||||
});
|
||||
// Set what is known for now, and resolutions from addr2line should overwrite
|
||||
trace[i].filename = entry.obj_path;
|
||||
trace[i].symbol = entry.symbol;
|
||||
}
|
||||
const std::vector<dlframe> dlframes = backtrace_frames(frames);
|
||||
const auto entries = get_addr2line_targets(dlframes, trace);
|
||||
for(const auto& entry : entries) {
|
||||
const auto& object_name = entry.first;
|
||||
const auto& entries_vec = entry.second;
|
||||
@ -136,37 +187,7 @@ namespace cpptrace {
|
||||
auto output = split(trim(resolve_addresses(address_input, object_name)), "\n");
|
||||
internal_verify(output.size() == entries_vec.size());
|
||||
for(size_t i = 0; i < output.size(); i++) {
|
||||
// Result will be of the form <identifier> " at " path:line
|
||||
// The path may be ?? if addr2line cannot resolve, line may be ?
|
||||
// Edge cases:
|
||||
// ?? ??:0
|
||||
const auto& line = output[i];
|
||||
std::size_t at_location = line.find(" at ");
|
||||
std::size_t symbol_end;
|
||||
std::size_t filename_start;
|
||||
if(at_location != std::string::npos) {
|
||||
symbol_end = at_location;
|
||||
filename_start = at_location + 4;
|
||||
} else {
|
||||
internal_verify(line.find("?? ") == 0, "Unexpected edge case while processing addr2line output");
|
||||
symbol_end = 2;
|
||||
filename_start = 3;
|
||||
}
|
||||
auto symbol = line.substr(0, symbol_end);
|
||||
auto colon = line.rfind(":");
|
||||
internal_verify(colon != std::string::npos);
|
||||
internal_verify(colon > filename_start);
|
||||
auto filename = line.substr(filename_start, colon - filename_start);
|
||||
auto line_number = line.substr(colon + 1);
|
||||
if(line_number != "?") {
|
||||
entries_vec[i].second.get().line = std::stoi(line_number);
|
||||
}
|
||||
if(filename != "??") {
|
||||
entries_vec[i].second.get().filename = filename;
|
||||
}
|
||||
if(symbol != "") {
|
||||
entries_vec[i].second.get().symbol = symbol;
|
||||
}
|
||||
update_trace(output[i], i, entries_vec);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -174,6 +195,7 @@ namespace cpptrace {
|
||||
}
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-unhandled-exception-at-new)
|
||||
symbolizer::symbolizer() : pimpl{new impl} {}
|
||||
symbolizer::~symbolizer() = default;
|
||||
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
#include "cpptrace_symbols.hpp"
|
||||
#include "../platform/cpptrace_program_name.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
@ -12,7 +12,8 @@
|
||||
namespace cpptrace {
|
||||
namespace detail {
|
||||
struct symbolizer::impl {
|
||||
stacktrace_frame resolve_frame(void* addr) {
|
||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||
stacktrace_frame resolve_frame(const void* addr) {
|
||||
Dl_info info;
|
||||
if(dladdr(addr, &info)) {
|
||||
return {
|
||||
@ -34,6 +35,7 @@ namespace cpptrace {
|
||||
}
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-unhandled-exception-at-new)
|
||||
symbolizer::symbolizer() : pimpl{new impl} {}
|
||||
symbolizer::~symbolizer() = default;
|
||||
|
||||
@ -44,7 +46,7 @@ namespace cpptrace {
|
||||
std::vector<stacktrace_frame> symbolizer::resolve_frames(const std::vector<void*>& frames) {
|
||||
std::vector<stacktrace_frame> trace;
|
||||
trace.reserve(frames.size());
|
||||
for(const auto frame : frames) {
|
||||
for(const void* frame : frames) {
|
||||
trace.push_back(pimpl->resolve_frame(frame));
|
||||
}
|
||||
return trace;
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "cpptrace_symbols.hpp"
|
||||
#include "../platform/cpptrace_program_name.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
@ -42,6 +43,7 @@ namespace cpptrace {
|
||||
|
||||
backtrace_state* get_backtrace_state() {
|
||||
// backtrace_create_state must be called only one time per program
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
static backtrace_state* state = nullptr;
|
||||
static bool called = false;
|
||||
if(!called) {
|
||||
@ -53,7 +55,8 @@ namespace cpptrace {
|
||||
|
||||
// TODO: Handle backtrace_pcinfo calling the callback multiple times on inlined functions
|
||||
struct symbolizer::impl {
|
||||
stacktrace_frame resolve_frame(void* addr) {
|
||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||
stacktrace_frame resolve_frame(const void* addr) {
|
||||
stacktrace_frame frame;
|
||||
frame.col = 0;
|
||||
backtrace_pcinfo(
|
||||
@ -77,6 +80,7 @@ namespace cpptrace {
|
||||
}
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-unhandled-exception-at-new)
|
||||
symbolizer::symbolizer() : pimpl{new impl} {}
|
||||
symbolizer::~symbolizer() = default;
|
||||
|
||||
@ -87,7 +91,7 @@ namespace cpptrace {
|
||||
std::vector<stacktrace_frame> symbolizer::resolve_frames(const std::vector<void*>& frames) {
|
||||
std::vector<stacktrace_frame> trace;
|
||||
trace.reserve(frames.size());
|
||||
for(const auto frame : frames) {
|
||||
for(const void* frame : frames) {
|
||||
trace.push_back(pimpl->resolve_frame(frame));
|
||||
}
|
||||
return trace;
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
#include "cpptrace_symbols.hpp"
|
||||
#include "../platform/cpptrace_program_name.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
@ -21,6 +20,7 @@ namespace cpptrace {
|
||||
// };
|
||||
// }
|
||||
|
||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||
std::vector<stacktrace_frame> symbolizer::resolve_frames(const std::vector<void*>& frames) {
|
||||
return std::vector<stacktrace_frame>(frames.size(), {
|
||||
0,
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
#ifndef CPPTRACE_UNWIND_HPP
|
||||
#define CPPTRACE_UNWIND_HPP
|
||||
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
#include "../platform/cpptrace_common.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
namespace cpptrace {
|
||||
namespace detail {
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
#ifdef CPPTRACE_UNWIND_WITH_EXECINFO
|
||||
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
#include "cpptrace_unwind.hpp"
|
||||
#include "../platform/cpptrace_common.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include <execinfo.h>
|
||||
@ -14,9 +14,9 @@ namespace cpptrace {
|
||||
CPPTRACE_FORCE_NO_INLINE
|
||||
std::vector<void*> capture_frames(size_t skip) {
|
||||
std::vector<void*> frames(hard_max_frames + skip, nullptr);
|
||||
int n_frames = backtrace(frames.data(), hard_max_frames + skip);
|
||||
const int n_frames = backtrace(frames.data(), int(hard_max_frames + skip));
|
||||
frames.resize(n_frames);
|
||||
frames.erase(frames.begin(), frames.begin() + std::min(skip + 1, frames.size()));
|
||||
frames.erase(frames.begin(), frames.begin() + ptrdiff_t(std::min(skip + 1, frames.size())));
|
||||
frames.shrink_to_fit();
|
||||
return frames;
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
#ifdef CPPTRACE_UNWIND_WITH_NOTHING
|
||||
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
#include "cpptrace_unwind.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
namespace cpptrace {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user