Baseline for middle-end system

This commit is contained in:
Jeremy 2023-09-11 11:57:01 -04:00
parent 09ccc95814
commit 5dc819186e
No known key found for this signature in database
GPG Key ID: 3E11861CB34E158C
9 changed files with 1548 additions and 1366 deletions

View File

@ -224,6 +224,7 @@ set(
src/symbols/symbols_with_libbacktrace.cpp src/symbols/symbols_with_libbacktrace.cpp
src/symbols/symbols_with_libdwarf.cpp src/symbols/symbols_with_libdwarf.cpp
src/symbols/symbols_with_nothing.cpp src/symbols/symbols_with_nothing.cpp
src/symbols/symbols_core.cpp
src/unwind/unwind_with_execinfo.cpp src/unwind/unwind_with_execinfo.cpp
src/unwind/unwind_with_nothing.cpp src/unwind/unwind_with_nothing.cpp
src/unwind/unwind_with_unwind.cpp src/unwind/unwind_with_unwind.cpp

View File

@ -8,6 +8,36 @@
namespace cpptrace { namespace cpptrace {
namespace detail { namespace detail {
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE
namespace libbacktrace {
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames);
}
#endif
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF
namespace libdwarf {
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames);
}
#endif
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDL
namespace libdl {
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames);
}
#endif
#ifdef CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE
namespace addr2line {
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames);
}
#endif
#ifdef CPPTRACE_GET_SYMBOLS_WITH_DBGHELP
namespace dbghelp {
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames);
}
#endif
#ifdef CPPTRACE_GET_SYMBOLS_WITH_NOTHING
namespace nothing {
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames);
}
#endif
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames); std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames);
} }
} }

View File

@ -0,0 +1,84 @@
#include "symbols.hpp"
#include <vector>
namespace cpptrace {
namespace detail {
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE
namespace libbacktrace {
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames);
}
#endif
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF
namespace libdwarf {
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames);
}
#endif
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDL
namespace libdl {
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames);
}
#endif
#ifdef CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE
namespace addr2line {
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames);
}
#endif
#ifdef CPPTRACE_GET_SYMBOLS_WITH_DBGHELP
namespace dbghelp {
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames);
}
#endif
#ifdef CPPTRACE_GET_SYMBOLS_WITH_NOTHING
namespace nothing {
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames);
}
#endif
void apply_trace(
std::vector<stacktrace_frame>& result,
const std::vector<stacktrace_frame>& trace
) {
for(std::size_t i = 0; i < result.size(); i++) {
if(result[i].address == 0) {
result[i].address = trace[i].address;
}
if(result[i].line == 0) {
result[i].line = trace[i].line;
}
if(result[i].col == 0) {
result[i].col = trace[i].col;
}
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<stacktrace_frame> resolve_frames(const std::vector<void*>& frames) {
std::vector<stacktrace_frame> trace(frames.size());
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE
apply_trace(trace, libbacktrace::resolve_frames(frames));
#endif
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF
apply_trace(trace, libdwarf::resolve_frames(frames));
#endif
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDL
apply_trace(trace, libdl::resolve_frames(frames));
#endif
#ifdef CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE
apply_trace(trace, addr2line::resolve_frames(frames));
#endif
#ifdef CPPTRACE_GET_SYMBOLS_WITH_DBGHELP
apply_trace(trace, dbghelp::resolve_frames(frames));
#endif
#ifdef CPPTRACE_GET_SYMBOLS_WITH_NOTHING
apply_trace(trace, nothing::resolve_frames(frames));
#endif
return trace;
}
}
}

View File

@ -24,6 +24,7 @@
namespace cpptrace { namespace cpptrace {
namespace detail { namespace detail {
namespace addr2line {
#if IS_LINUX || IS_APPLE #if IS_LINUX || IS_APPLE
bool has_addr2line() { bool has_addr2line() {
static std::mutex mutex; static std::mutex mutex;
@ -195,7 +196,12 @@ namespace cpptrace {
// If libdl fails to find the shared object for a frame, the path will be empty. I've observed this // 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`. // on macos when looking up the shared object containing `start`.
if(!entry.obj_path.empty()) { if(!entry.obj_path.empty()) {
///fprintf(stderr, "%s %s\n", to_hex(entry.raw_address).c_str(), to_hex(entry.raw_address - entry.obj_base + base).c_str()); ///fprintf(
/// stderr,
/// "%s %s\n",
/// to_hex(entry.raw_address).c_str(),
/// to_hex(entry.raw_address - entry.obj_base + base).c_str()
///);
try { try {
entries[entry.obj_path].emplace_back( entries[entry.obj_path].emplace_back(
to_hex(entry.obj_address), to_hex(entry.obj_address),
@ -280,7 +286,10 @@ namespace cpptrace {
filename_end != std::string::npos, filename_end != std::string::npos,
"Unexpected edge case while processing addr2line/atos output" "Unexpected edge case while processing addr2line/atos output"
); );
entries_vec[entry_index].second.get().filename = line.substr(filename_start + 3, filename_end - filename_start - 3); entries_vec[entry_index].second.get().filename = line.substr(
filename_start + 3,
filename_end - filename_start - 3
);
const std::size_t line_start = filename_end + 1; const std::size_t line_start = filename_end + 1;
const std::size_t line_end = line.find(")", filename_end); const std::size_t line_end = line.find(")", filename_end);
internal_verify( internal_verify(
@ -331,5 +340,6 @@ namespace cpptrace {
} }
} }
} }
}
#endif #endif

View File

@ -15,6 +15,8 @@
namespace cpptrace { namespace cpptrace {
namespace detail { namespace detail {
namespace dbghelp {
// SymFromAddr only returns the function's name. In order to get information about parameters, // SymFromAddr only returns the function's name. In order to get information about parameters,
// important for C++ stack traces where functions may be overloaded, we have to manually use // important for C++ stack traces where functions may be overloaded, we have to manually use
// Windows DIA to walk debug info structures. Resources: // Windows DIA to walk debug info structures. Resources:
@ -57,7 +59,15 @@ namespace cpptrace {
template<typename T, IMAGEHLP_SYMBOL_TYPE_INFO SymType, bool FAILABLE = false> template<typename T, IMAGEHLP_SYMBOL_TYPE_INFO SymType, bool FAILABLE = false>
T get_info(ULONG type_index, HANDLE proc, ULONG64 modbase) { T get_info(ULONG type_index, HANDLE proc, ULONG64 modbase) {
T info; T info;
if(!SymGetTypeInfo(proc, modbase, type_index, static_cast<::IMAGEHLP_SYMBOL_TYPE_INFO>(SymType), &info)) { if(
!SymGetTypeInfo(
proc,
modbase,
type_index,
static_cast<::IMAGEHLP_SYMBOL_TYPE_INFO>(SymType),
&info
)
) {
if(FAILABLE) { if(FAILABLE) {
return (T)-1; return (T)-1;
} else { } else {
@ -73,14 +83,20 @@ namespace cpptrace {
template<IMAGEHLP_SYMBOL_TYPE_INFO SymType, bool FAILABLE = false> template<IMAGEHLP_SYMBOL_TYPE_INFO SymType, bool FAILABLE = false>
std::string get_info_wchar(ULONG type_index, HANDLE proc, ULONG64 modbase) { std::string get_info_wchar(ULONG type_index, HANDLE proc, ULONG64 modbase) {
WCHAR* info; WCHAR* info;
if(!SymGetTypeInfo(proc, modbase, type_index, static_cast<::IMAGEHLP_SYMBOL_TYPE_INFO>(SymType), &info)) { if(
!SymGetTypeInfo(proc, modbase, type_index, static_cast<::IMAGEHLP_SYMBOL_TYPE_INFO>(SymType), &info)
) {
throw std::logic_error( throw std::logic_error(
std::string("SymGetTypeInfo failed: ") std::string("SymGetTypeInfo failed: ")
+ std::system_error(GetLastError(), std::system_category()).what() + std::system_error(GetLastError(), std::system_category()).what()
); );
} }
// special case to properly free a buffer and convert string to narrow chars, only used for TI_GET_SYMNAME // special case to properly free a buffer and convert string to narrow chars, only used for
static_assert(SymType == IMAGEHLP_SYMBOL_TYPE_INFO::TI_GET_SYMNAME, "get_info_wchar called with unexpected IMAGEHLP_SYMBOL_TYPE_INFO"); // TI_GET_SYMNAME
static_assert(
SymType == IMAGEHLP_SYMBOL_TYPE_INFO::TI_GET_SYMNAME,
"get_info_wchar called with unexpected IMAGEHLP_SYMBOL_TYPE_INFO"
);
std::wstring wstr(info); std::wstring wstr(info);
std::string str; std::string str;
str.reserve(wstr.size()); str.reserve(wstr.size());
@ -210,7 +226,8 @@ namespace cpptrace {
modbase modbase
); );
int n_ignore = class_parent_id != (DWORD)-1; // ignore this param int n_ignore = class_parent_id != (DWORD)-1; // ignore this param
n_children -= n_ignore; // this must be ignored before TI_FINDCHILDREN_PARAMS::Count is set, else error // this must be ignored before TI_FINDCHILDREN_PARAMS::Count is set, else error
n_children -= n_ignore;
// return type // return type
const auto return_type = lookup_type(return_type_id, proc, modbase); const auto return_type = lookup_type(return_type_id, proc, modbase);
if(n_children == 0) { if(n_children == 0) {
@ -225,7 +242,9 @@ namespace cpptrace {
if( if(
!SymGetTypeInfo( !SymGetTypeInfo(
proc, modbase, type_index, proc, modbase, type_index,
static_cast<::IMAGEHLP_SYMBOL_TYPE_INFO>(IMAGEHLP_SYMBOL_TYPE_INFO::TI_FINDCHILDREN), static_cast<::IMAGEHLP_SYMBOL_TYPE_INFO>(
IMAGEHLP_SYMBOL_TYPE_INFO::TI_FINDCHILDREN
),
children children
) )
) { ) {
@ -256,10 +275,14 @@ namespace cpptrace {
case SymTagEnum::SymTagEnum: case SymTagEnum::SymTagEnum:
case SymTagEnum::SymTagUDT: case SymTagEnum::SymTagUDT:
case SymTagEnum::SymTagBaseClass: case SymTagEnum::SymTagBaseClass:
return {get_info_wchar<IMAGEHLP_SYMBOL_TYPE_INFO::TI_GET_SYMNAME>(type_index, proc, modbase), ""}; return {
get_info_wchar<IMAGEHLP_SYMBOL_TYPE_INFO::TI_GET_SYMNAME>(type_index, proc, modbase), ""
};
default: default:
return { return {
"<unknown type " + std::to_string(static_cast<std::underlying_type<SymTagEnum>::type>(tag)) + ">", "<unknown type " +
std::to_string(static_cast<std::underlying_type<SymTagEnum>::type>(tag)) +
">",
"" ""
}; };
}; };
@ -339,7 +362,14 @@ namespace cpptrace {
proc, proc,
symbol->ModBase symbol->ModBase
); );
function_info fi { proc, symbol->ModBase, 0, int(n_children), class_parent_id != (DWORD)-1, "" }; function_info fi {
proc,
symbol->ModBase,
0,
int(n_children),
class_parent_id != (DWORD)-1,
""
};
SymEnumSymbols(proc, 0, nullptr, enumerator_callback, &fi); SymEnumSymbols(proc, 0, nullptr, enumerator_callback, &fi);
std::string signature = symbol->Name + std::string("(") + fi.str + ")"; std::string signature = symbol->Name + std::string("(") + fi.str + ")";
// There's a phenomina with DIA not inserting commas after template parameters. Fix them here. // There's a phenomina with DIA not inserting commas after template parameters. Fix them here.
@ -394,5 +424,6 @@ namespace cpptrace {
} }
} }
} }
}
#endif #endif

View File

@ -11,6 +11,7 @@
namespace cpptrace { namespace cpptrace {
namespace detail { namespace detail {
namespace libdl {
stacktrace_frame resolve_frame(const void* addr) { stacktrace_frame resolve_frame(const void* addr) {
Dl_info info; Dl_info info;
if(dladdr(addr, &info)) { // thread-safe if(dladdr(addr, &info)) { // thread-safe
@ -42,5 +43,6 @@ namespace cpptrace {
} }
} }
} }
}
#endif #endif

View File

@ -18,6 +18,7 @@
namespace cpptrace { namespace cpptrace {
namespace detail { namespace detail {
namespace libbacktrace {
int full_callback(void* data, uintptr_t address, const char* file, int line, const char* symbol) { int full_callback(void* data, uintptr_t address, const char* file, int line, const char* symbol) {
stacktrace_frame& frame = *static_cast<stacktrace_frame*>(data); stacktrace_frame& frame = *static_cast<stacktrace_frame*>(data);
if(line == 0) { if(line == 0) {
@ -90,5 +91,6 @@ namespace cpptrace {
} }
} }
} }
}
#endif #endif

View File

@ -182,6 +182,7 @@ static int dwarf4_ranges(
namespace cpptrace { namespace cpptrace {
namespace detail { namespace detail {
namespace libdwarf {
// printbugging as we go // printbugging as we go
constexpr bool dump_dwarf = false; constexpr bool dump_dwarf = false;
@ -614,7 +615,13 @@ namespace cpptrace {
return name.find("_Z") || name.find("?h@@"); return name.find("_Z") || name.find("?h@@");
} }
void retrieve_symbol_for_subprogram(Dwarf_Debug dbg, const die_object& die, Dwarf_Addr pc, Dwarf_Half dwversion, stacktrace_frame& frame) { void retrieve_symbol_for_subprogram(
Dwarf_Debug dbg,
const die_object& die,
Dwarf_Addr pc,
Dwarf_Half dwversion,
stacktrace_frame& frame
) {
assert(die.get_tag() == DW_TAG_subprogram); assert(die.get_tag() == DW_TAG_subprogram);
Dwarf_Attribute attr; Dwarf_Attribute attr;
int ret = dwarf_attr(die.get(), DW_AT_linkage_name, &attr, nullptr); int ret = dwarf_attr(die.get(), DW_AT_linkage_name, &attr, nullptr);
@ -676,7 +683,13 @@ namespace cpptrace {
frame.symbol = name + "(" + join(params, ", ") + ")";*/ frame.symbol = name + "(" + join(params, ", ") + ")";*/
} }
void retrieve_symbol(Dwarf_Debug dbg, const die_object& die, Dwarf_Addr pc, Dwarf_Half dwversion, stacktrace_frame& frame) { void retrieve_symbol(
Dwarf_Debug dbg,
const die_object& die,
Dwarf_Addr pc,
Dwarf_Half dwversion,
stacktrace_frame& frame
) {
walk_die_list( walk_die_list(
dbg, dbg,
die, die,
@ -718,7 +731,13 @@ namespace cpptrace {
); );
} }
void retrieve_line_info(Dwarf_Debug dbg, const die_object& die, Dwarf_Addr pc, Dwarf_Half dwversion, stacktrace_frame& frame) { void retrieve_line_info(
Dwarf_Debug dbg,
const die_object& die,
Dwarf_Addr pc,
Dwarf_Half dwversion,
stacktrace_frame& frame
) {
Dwarf_Unsigned version; Dwarf_Unsigned version;
Dwarf_Small table_count; Dwarf_Small table_count;
Dwarf_Line_Context ctxt; Dwarf_Line_Context ctxt;
@ -899,5 +918,6 @@ namespace cpptrace {
} }
} }
} }
}
#endif #endif

View File

@ -7,6 +7,7 @@
namespace cpptrace { namespace cpptrace {
namespace detail { namespace detail {
namespace nothing {
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames) { std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames) {
return std::vector<stacktrace_frame>(frames.size(), { return std::vector<stacktrace_frame>(frames.size(), {
0, 0,
@ -18,5 +19,6 @@ namespace cpptrace {
} }
} }
} }
}
#endif #endif