mirror of
https://github.com/pocoproject/poco.git
synced 2025-03-13 08:14:20 +01:00

* chore(Trace): add dev env settings * add(Trace): init add Poco::trace and libbacktrace files * feat(Exception): generate stack trace if enabled at compile time * chore(DNSSD): remove binaries from git * fix(Trace): build * chore(ci): exclude exception text tests for trace build; add debug test script params * chore(build): mac (dl) * chore(cmake): Changes to build Trace with CMake. * chore(cmake): Changes to build Trace on Windows * chore(cmake): Improvements to include trace sample. * chore(cmake): Fixes to properly build/link Trace on Linux * chore(cmake): add_definitions --> add_compile_definitions * chore(cmake): Build Trace as static and don't export it. * chore(make): Link Trace with built-in libbacktrace on Linux * chore(Trace): remove unnecessary sources for libbacktrace. * chore(github): enable trace on a few github checks * chore(cmake): Build Trace with clang++ on Linux. * chore(cmake): Properly set POCO_ENABLE_TRACE globally when needed. * fix(cmake): Trace: corrected include for clang on Linux --------- Co-authored-by: Matej Kenda <matejken@gmail.com>
146 lines
5.6 KiB
C++
146 lines
5.6 KiB
C++
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF
|
|
|
|
#include "symbols/symbols.hpp"
|
|
|
|
#include <cpptrace/cpptrace.hpp>
|
|
#include "dwarf/resolver.hpp"
|
|
#include "utils/common.hpp"
|
|
#include "utils/error.hpp"
|
|
#include "utils/utils.hpp"
|
|
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
|
|
namespace cpptrace {
|
|
namespace detail {
|
|
namespace libdwarf {
|
|
std::unique_ptr<symbol_resolver> get_resolver_for_object(const std::string& object_path) {
|
|
#if IS_APPLE
|
|
// Check if dSYM exist, if not fallback to debug map
|
|
if(!directory_exists(object_path + ".dSYM")) {
|
|
return make_debug_map_resolver(object_path);
|
|
}
|
|
#endif
|
|
return make_dwarf_resolver(object_path);
|
|
}
|
|
|
|
// not thread-safe, replies on caller to lock
|
|
maybe_owned<symbol_resolver> get_resolver(const std::string& object_name) {
|
|
// cache resolvers since objects are likely to be traced more than once
|
|
static std::unordered_map<std::string, std::unique_ptr<symbol_resolver>> resolver_map;
|
|
auto it = resolver_map.find(object_name);
|
|
if(it != resolver_map.end()) {
|
|
return it->second.get();
|
|
} else {
|
|
std::unique_ptr<symbol_resolver> resolver_object = get_resolver_for_object(object_name);
|
|
if(get_cache_mode() == cache_mode::prioritize_speed) {
|
|
// .emplace needed, for some reason .insert tries to copy <= gcc 7.2
|
|
return resolver_map.emplace(object_name, std::move(resolver_object)).first->second.get();
|
|
} else {
|
|
// gcc 4 has trouble with automatic moves of locals here https://godbolt.org/z/9oWdWjbf8
|
|
return maybe_owned<symbol_resolver>{std::move(resolver_object)};
|
|
}
|
|
}
|
|
}
|
|
|
|
// flatten trace with inlines
|
|
std::vector<stacktrace_frame> flatten_inlines(std::vector<frame_with_inlines>& trace) {
|
|
std::vector<stacktrace_frame> final_trace;
|
|
for(auto& entry : trace) {
|
|
// most recent call first
|
|
if(!entry.inlines.empty()) {
|
|
// insert in reverse order
|
|
final_trace.insert(
|
|
final_trace.end(),
|
|
std::make_move_iterator(entry.inlines.rbegin()),
|
|
std::make_move_iterator(entry.inlines.rend())
|
|
);
|
|
}
|
|
final_trace.push_back(std::move(entry.frame));
|
|
if(!entry.inlines.empty()) {
|
|
// rotate line info due to quirk of how dwarf stores this stuff
|
|
// inclusive range
|
|
auto begin = final_trace.end() - (1 + entry.inlines.size());
|
|
auto end = final_trace.end() - 1;
|
|
auto carry_line = end->line;
|
|
auto carry_column = end->column;
|
|
std::string carry_filename = std::move(end->filename);
|
|
for(auto it = end; it != begin; it--) {
|
|
it->line = (it - 1)->line;
|
|
it->column = (it - 1)->column;
|
|
it->filename = std::move((it - 1)->filename);
|
|
}
|
|
begin->line = carry_line;
|
|
begin->column = carry_column;
|
|
begin->filename = std::move(carry_filename);
|
|
}
|
|
}
|
|
return final_trace;
|
|
}
|
|
|
|
CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING
|
|
std::vector<stacktrace_frame> resolve_frames(const std::vector<object_frame>& frames) {
|
|
std::vector<frame_with_inlines> trace(frames.size(), {null_frame, {}});
|
|
// Locking around all libdwarf interaction per https://github.com/davea42/libdwarf-code/discussions/184
|
|
// And also locking for interactions with get_resolver
|
|
static std::mutex mutex;
|
|
const std::lock_guard<std::mutex> lock(mutex);
|
|
for(const auto& group : collate_frames(frames, trace)) {
|
|
try {
|
|
const auto& object_name = group.first;
|
|
auto resolver = get_resolver(object_name);
|
|
for(const auto& entry : group.second) {
|
|
const auto& dlframe = entry.first.get();
|
|
auto& frame = entry.second.get();
|
|
try {
|
|
frame = resolver->resolve_frame(dlframe);
|
|
} catch(...) {
|
|
frame.frame.raw_address = dlframe.raw_address;
|
|
frame.frame.object_address = dlframe.object_address;
|
|
frame.frame.filename = dlframe.object_path;
|
|
if(!should_absorb_trace_exceptions()) {
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
} catch(...) { // NOSONAR
|
|
if(!should_absorb_trace_exceptions()) {
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
// fill in basic info for any frames where there were resolution issues
|
|
for(std::size_t i = 0; i < frames.size(); i++) {
|
|
const auto& dlframe = frames[i];
|
|
auto& frame = trace[i];
|
|
if(frame.frame == null_frame) {
|
|
frame = {
|
|
{
|
|
dlframe.raw_address,
|
|
dlframe.object_address,
|
|
nullable<std::uint32_t>::null(),
|
|
nullable<std::uint32_t>::null(),
|
|
dlframe.object_path,
|
|
"",
|
|
false
|
|
},
|
|
{}
|
|
};
|
|
}
|
|
}
|
|
// flatten and finish
|
|
return flatten_inlines(trace);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|