From 79bc580519b01edf8fdffbe6f314ddccd930a683 Mon Sep 17 00:00:00 2001 From: Jeremy <51220084+jeremy-rifkin@users.noreply.github.com> Date: Wed, 15 Nov 2023 15:09:08 -0500 Subject: [PATCH] Handle multiple symbol back-ends better --- README.md | 3 + src/symbols/symbols_core.cpp | 144 ++++++++++++++------------ src/symbols/symbols_with_dbghelp.cpp | 4 +- src/symbols/symbols_with_libdwarf.cpp | 9 +- 4 files changed, 94 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index c29d2a7..b184852 100644 --- a/README.md +++ b/README.md @@ -604,6 +604,9 @@ configurable with `CPPTRACE_HARD_MAX_FRAMES`. *: Requires installation +One back-end should be used. For MinGW `CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF` and `CPPTRACE_GET_SYMBOLS_WITH_DBGHELP` can +be used in conjunction. + Note for addr2line: By default cmake will resolve an absolute path to addr2line to bake into the library. This path can be configured with `CPPTRACE_ADDR2LINE_PATH`, or `CPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH` can be used to have the library search the system path for `addr2line` at runtime. This is not the default to prevent against path injection attacks. diff --git a/src/symbols/symbols_core.cpp b/src/symbols/symbols_core.cpp index 0ec9c45..bed16fa 100644 --- a/src/symbols/symbols_core.cpp +++ b/src/symbols/symbols_core.cpp @@ -55,59 +55,71 @@ namespace detail { * */ - void apply_trace( - std::vector& result, - std::vector&& trace + // Resolver must not support walking inlines + void fill_blanks( + std::vector& vec, + std::vector (*resolver)(const std::vector&) ) { - for(std::size_t i = 0; i < result.size(); i++) { - if(result[i].address == 0) { - result[i].address = trace[i].address; + std::vector addresses; + for(const auto& frame : vec) { + if(frame.symbol.empty() || frame.filename.empty()) { + addresses.push_back(frame.address); } - if(!result[i].line.has_value()) { - result[i].line = trace[i].line; - } - if(!result[i].column.has_value()) { - result[i].column = trace[i].column; - } - if(result[i].filename.empty()) { - result[i].filename = std::move(trace[i].filename); - } - if(result[i].symbol.empty()) { - result[i].symbol = std::move(trace[i].symbol); + } + std::vector new_frames = resolver(addresses); + std::size_t i = 0; + for(auto& frame : vec) { + if(frame.symbol.empty() || frame.filename.empty()) { + // three cases to handle, either partially overwrite or fully overwrite + if(frame.symbol.empty() && frame.filename.empty()) { + frame = new_frames[i]; + } else if(frame.symbol.empty() && !frame.filename.empty()) { + frame.symbol = new_frames[i].symbol; + } else { + ASSERT(!frame.symbol.empty() && frame.filename.empty()); + frame.filename = new_frames[i].filename; + frame.line = new_frames[i].line; + frame.column = new_frames[i].column; + } + i++; } } } std::vector resolve_frames(const std::vector& frames) { - std::vector trace(frames.size(), null_frame); - #if defined(CPPTRACE_GET_SYMBOLS_WITH_LIBDL) \ - || defined(CPPTRACE_GET_SYMBOLS_WITH_DBGHELP) \ - || defined(CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE) - // actually need to go backwards to a void* - std::vector raw_frames(frames.size()); - for(std::size_t i = 0; i < frames.size(); i++) { - raw_frames[i] = frames[i].raw_address; - } + #if defined(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF) && defined(CPPTRACE_GET_SYMBOLS_WITH_DBGHELP) + std::vector trace = libdwarf::resolve_frames(frames); + fill_blanks(trace, dbghelp::resolve_frames); + return trace; + #else + #if defined(CPPTRACE_GET_SYMBOLS_WITH_LIBDL) \ + || defined(CPPTRACE_GET_SYMBOLS_WITH_DBGHELP) \ + || defined(CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE) + // actually need to go backwards to a void* + std::vector raw_frames(frames.size()); + for(std::size_t i = 0; i < frames.size(); i++) { + raw_frames[i] = frames[i].raw_address; + } + #endif + #ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDL + return libdl::resolve_frames(raw_frames); + #endif + #ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF + return libdwarf::resolve_frames(frames); + #endif + #ifdef CPPTRACE_GET_SYMBOLS_WITH_DBGHELP + return dbghelp::resolve_frames(raw_frames); + #endif + #ifdef CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE + return addr2line::resolve_frames(frames); + #endif + #ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE + return libbacktrace::resolve_frames(raw_frames); + #endif + #ifdef CPPTRACE_GET_SYMBOLS_WITH_NOTHING + return nothing::resolve_frames(frames); + #endif #endif - #ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDL - apply_trace(trace, libdl::resolve_frames(raw_frames)); - #endif - #ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF - apply_trace(trace, libdwarf::resolve_frames(frames)); - #endif - #ifdef CPPTRACE_GET_SYMBOLS_WITH_DBGHELP - apply_trace(trace, dbghelp::resolve_frames(raw_frames)); - #endif - #ifdef CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE - apply_trace(trace, addr2line::resolve_frames(frames)); - #endif - #ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE - apply_trace(trace, libbacktrace::resolve_frames(raw_frames)); - #endif - #ifdef CPPTRACE_GET_SYMBOLS_WITH_NOTHING - apply_trace(trace, nothing::resolve_frames(frames)); - #endif - return trace; } std::vector resolve_frames(const std::vector& frames) { @@ -115,26 +127,30 @@ namespace detail { || defined(CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE) auto dlframes = get_frames_object_info(frames); #endif - std::vector trace(frames.size(), null_frame); - #ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDL - apply_trace(trace, libdl::resolve_frames(frames)); + #if defined(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF) && defined(CPPTRACE_GET_SYMBOLS_WITH_DBGHELP) + std::vector trace = libdwarf::resolve_frames(dlframes); + fill_blanks(trace, dbghelp::resolve_frames); + return trace; + #else + #ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDL + return libdl::resolve_frames(frames); + #endif + #ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF + return libdwarf::resolve_frames(dlframes); + #endif + #ifdef CPPTRACE_GET_SYMBOLS_WITH_DBGHELP + return dbghelp::resolve_frames(frames); + #endif + #ifdef CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE + return addr2line::resolve_frames(dlframes); + #endif + #ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE + return libbacktrace::resolve_frames(frames); + #endif + #ifdef CPPTRACE_GET_SYMBOLS_WITH_NOTHING + return nothing::resolve_frames(frames); + #endif #endif - #ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF - apply_trace(trace, libdwarf::resolve_frames(dlframes)); - #endif - #ifdef CPPTRACE_GET_SYMBOLS_WITH_DBGHELP - apply_trace(trace, dbghelp::resolve_frames(frames)); - #endif - #ifdef CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE - apply_trace(trace, addr2line::resolve_frames(dlframes)); - #endif - #ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE - apply_trace(trace, libbacktrace::resolve_frames(frames)); - #endif - #ifdef CPPTRACE_GET_SYMBOLS_WITH_NOTHING - apply_trace(trace, nothing::resolve_frames(frames)); - #endif - return trace; } } } diff --git a/src/symbols/symbols_with_dbghelp.cpp b/src/symbols/symbols_with_dbghelp.cpp index ca739ad..5f63851 100644 --- a/src/symbols/symbols_with_dbghelp.cpp +++ b/src/symbols/symbols_with_dbghelp.cpp @@ -421,7 +421,9 @@ namespace dbghelp { if(!detail::should_absorb_trace_exceptions()) { throw; } - trace.push_back(null_frame); + auto entry = null_frame; + entry.address = frame; + trace.push_back(entry); } } if(get_cache_mode() != cache_mode::prioritize_speed) { diff --git a/src/symbols/symbols_with_libdwarf.cpp b/src/symbols/symbols_with_libdwarf.cpp index cfd9573..d63ed58 100644 --- a/src/symbols/symbols_with_libdwarf.cpp +++ b/src/symbols/symbols_with_libdwarf.cpp @@ -881,12 +881,19 @@ namespace libdwarf { const auto& dlframe = entry.first.get(); auto& frame = entry.second.get(); frame = resolver->resolve_frame(dlframe); - } catch(...) { // NOSONAR + } catch(...) { if(!should_absorb_trace_exceptions()) { throw; } } } + } else { + // at least copy the addresses + for(const auto& entry : obj_entry.second) { + const auto& dlframe = entry.first.get(); + auto& frame = entry.second.get(); + frame.frame.address = dlframe.raw_address; + } } if(resolver_object.has_value() && get_cache_mode() == cache_mode::prioritize_speed) { // .emplace needed, for some reason .insert tries to copy <= gcc 7.2