#include "symbols.hpp" #include #include #include "../utils/common.hpp" #include "../binary/object.hpp" namespace cpptrace { namespace detail { std::unordered_map collate_frames( const std::vector& frames, std::vector& trace ) { std::unordered_map entries; for(std::size_t i = 0; i < frames.size(); i++) { const auto& entry = frames[i]; // If libdl fails to find the shared object for a frame, the path will be empty. I've observed this // on macos when looking up the shared object containing `start`. if(!entry.object_path.empty()) { entries[entry.object_path].emplace_back( entry, trace[i] ); } } return entries; } // TODO: Refactor to eliminate the code duplication std::unordered_map collate_frames( const std::vector& frames, std::vector& trace ) { std::unordered_map entries; for(std::size_t i = 0; i < frames.size(); i++) { const auto& entry = frames[i]; // If libdl fails to find the shared object for a frame, the path will be empty. I've observed this // on macos when looking up the shared object containing `start`. if(!entry.object_path.empty()) { entries[entry.object_path].emplace_back( entry, trace[i] ); } } return entries; } /* * * * All the code here is awful and I'm not proud of it. * * * */ // Resolver must not support walking inlines void fill_blanks( std::vector& vec, std::vector (*resolver)(const std::vector&) ) { std::vector addresses; for(const auto& frame : vec) { if(frame.symbol.empty() || frame.filename.empty()) { addresses.push_back(frame.address); } } 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) { #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 } std::vector resolve_frames(const std::vector& frames) { #if defined(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF) \ || defined(CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE) auto dlframes = get_frames_object_info(frames); #endif #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 } } }