Optimize dwarf handling by caching line contexts so the line info table only has to be computed once per TU per object per trace

This commit is contained in:
Jeremy 2023-09-17 00:54:11 -04:00
parent e47cb7147d
commit e4eab1d426
No known key found for this signature in database
GPG Key ID: 19AA8270105E8EB4

View File

@ -558,7 +558,55 @@ namespace libdwarf {
frame.symbol = name + "(" + join(params, ", ") + ")";*/ frame.symbol = name + "(" + join(params, ", ") + ")";*/
} }
struct line_context {
Dwarf_Unsigned version;
Dwarf_Small table_count;
Dwarf_Line_Context ctx;
};
struct dwarf_resolver {
std::string obj_path;
Dwarf_Debug dbg;
std::unordered_map<Dwarf_Off, line_context> line_contexts;
CPPTRACE_FORCE_NO_INLINE
dwarf_resolver(const std::string& object_path) {
obj_path = object_path;
#if IS_APPLE
if(directory_exists(obj_path + ".dSYM")) {
obj_path += ".dSYM/Contents/Resources/DWARF/" + basename(object_path);
}
#endif
Dwarf_Ptr errarg = 0;
auto ret = dwarf_init_path(
obj_path.c_str(),
nullptr,
0,
DW_GROUPNUMBER_ANY,
err_handler,
errarg,
&dbg,
nullptr
);
if(ret == DW_DLV_NO_ENTRY) {
// fail, no debug info
} else if(ret != DW_DLV_OK) {
fprintf(stderr, "Error\n");
} else {
}
}
CPPTRACE_FORCE_NO_INLINE
~dwarf_resolver() {
dwarf_finish(dbg);
for(auto& entry : line_contexts) {
dwarf_srclines_dealloc_b(entry.second.ctx);
}
}
// returns true if this call found the symbol // returns true if this call found the symbol
CPPTRACE_FORCE_NO_INLINE
bool retrieve_symbol( bool retrieve_symbol(
Dwarf_Debug dbg, Dwarf_Debug dbg,
const die_object& die, const die_object& die,
@ -570,7 +618,7 @@ namespace libdwarf {
walk_die_list( walk_die_list(
dbg, dbg,
die, die,
[pc, dwversion, &frame, &found] (Dwarf_Debug dbg, const die_object& die) { [this, pc, dwversion, &frame, &found] (Dwarf_Debug dbg, const die_object& die) {
if(dump_dwarf) { if(dump_dwarf) {
fprintf( fprintf(
stderr, stderr,
@ -618,6 +666,7 @@ namespace libdwarf {
return found; return found;
} }
CPPTRACE_FORCE_NO_INLINE
void retrieve_line_info( void retrieve_line_info(
Dwarf_Debug dbg, Dwarf_Debug dbg,
const die_object& die, const die_object& die,
@ -630,6 +679,14 @@ namespace libdwarf {
Dwarf_Line_Context ctxt; Dwarf_Line_Context ctxt;
Dwarf_Bool is_found = false; Dwarf_Bool is_found = false;
(void)dwversion; (void)dwversion;
auto off = die.get_global_offset();
auto it = line_contexts.find(off);
if(it != line_contexts.end()) {
auto& entry = it->second;
version = entry.version;
table_count = entry.table_count;
ctxt = entry.ctx;
} else {
int ret = dwarf_srclines_b( int ret = dwarf_srclines_b(
die.get(), die.get(),
&version, &version,
@ -637,10 +694,13 @@ namespace libdwarf {
&ctxt, &ctxt,
nullptr nullptr
); );
line_contexts.insert({off, {version, table_count, ctxt}});
if(ret == DW_DLV_NO_ENTRY) { if(ret == DW_DLV_NO_ENTRY) {
fprintf(stderr, "dwarf_srclines_b error\n"); fprintf(stderr, "dwarf_srclines_b error\n");
return; return;
} }
}
if(table_count == 1) { if(table_count == 1) {
Dwarf_Line *linebuf = 0; Dwarf_Line *linebuf = 0;
Dwarf_Signed linecount = 0; Dwarf_Signed linecount = 0;
@ -685,9 +745,9 @@ namespace libdwarf {
} }
} }
} }
dwarf_srclines_dealloc_b(ctxt);
} }
CPPTRACE_FORCE_NO_INLINE
void walk_compilation_units(Dwarf_Debug dbg, Dwarf_Addr pc, stacktrace_frame& frame) { void walk_compilation_units(Dwarf_Debug dbg, Dwarf_Addr pc, stacktrace_frame& frame) {
// 0 passed as the die to the first call of dwarf_siblingof_b immediately after dwarf_next_cu_header_d // 0 passed as the die to the first call of dwarf_siblingof_b immediately after dwarf_next_cu_header_d
// to fetch the cu die // to fetch the cu die
@ -702,7 +762,7 @@ namespace libdwarf {
walk_die_list( walk_die_list(
dbg, dbg,
cu_die, cu_die,
[&frame, pc] (Dwarf_Debug dbg, const die_object& cu_die) { [this, &frame, pc] (Dwarf_Debug dbg, const die_object& cu_die) {
Dwarf_Half offset_size = 0; Dwarf_Half offset_size = 0;
Dwarf_Half dwversion = 0; Dwarf_Half dwversion = 0;
dwarf_get_version_of_die(cu_die.get(), &dwversion, &offset_size); dwarf_get_version_of_die(cu_die.get(), &dwversion, &offset_size);
@ -742,6 +802,7 @@ namespace libdwarf {
); );
} }
CPPTRACE_FORCE_NO_INLINE
void walk_dbg(Dwarf_Debug dbg, Dwarf_Addr pc, stacktrace_frame& frame) { void walk_dbg(Dwarf_Debug dbg, Dwarf_Addr pc, stacktrace_frame& frame) {
// libdwarf keeps track of where it is in the file, dwarf_next_cu_header_d is statefull // libdwarf keeps track of where it is in the file, dwarf_next_cu_header_d is statefull
Dwarf_Unsigned next_cu_header; Dwarf_Unsigned next_cu_header;
@ -776,6 +837,7 @@ namespace libdwarf {
} }
} }
CPPTRACE_FORCE_NO_INLINE
void lookup_pc( void lookup_pc(
const char* object, const char* object,
Dwarf_Addr pc, Dwarf_Addr pc,
@ -785,39 +847,15 @@ namespace libdwarf {
fprintf(stderr, "%s\n", object); fprintf(stderr, "%s\n", object);
fprintf(stderr, "%llx\n", pc); fprintf(stderr, "%llx\n", pc);
} }
Dwarf_Debug dbg;
Dwarf_Ptr errarg = 0;
auto ret = dwarf_init_path(
object,
nullptr,
0,
DW_GROUPNUMBER_ANY,
err_handler,
errarg,
&dbg,
nullptr
);
if(ret == DW_DLV_NO_ENTRY) {
// fail, no debug info
} else if(ret != DW_DLV_OK) {
fprintf(stderr, "Error\n");
} else {
walk_dbg(dbg, pc, frame); walk_dbg(dbg, pc, frame);
} }
dwarf_finish(dbg);
}
CPPTRACE_FORCE_NO_INLINE
stacktrace_frame resolve_frame(const dlframe& frame_info) { stacktrace_frame resolve_frame(const dlframe& frame_info) {
stacktrace_frame frame{}; stacktrace_frame frame{};
frame.filename = frame_info.obj_path; frame.filename = frame_info.obj_path;
frame.symbol = frame_info.symbol; frame.symbol = frame_info.symbol;
frame.address = frame_info.raw_address; frame.address = frame_info.raw_address;
std::string obj_path = frame_info.obj_path;
#if IS_APPLE
if(directory_exists(obj_path + ".dSYM")) {
obj_path += ".dSYM/Contents/Resources/DWARF/" + basename(frame_info.obj_path);
}
#endif
if(trace_dwarf) { if(trace_dwarf) {
fprintf( fprintf(
stderr, stderr,
@ -834,12 +872,20 @@ namespace libdwarf {
); );
return frame; return frame;
} }
};
CPPTRACE_FORCE_NO_INLINE
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames) { std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames) {
std::vector<stacktrace_frame> trace; std::vector<stacktrace_frame> trace(frames.size(), stacktrace_frame { 0, 0, 0, "", "" });
trace.reserve(frames.size()); const auto dlframes = get_frames_object_info(frames);
for(const auto& frame : get_frames_object_info(frames)) { for(const auto& obj_entry : collate_frames(dlframes, trace)) {
trace.push_back(resolve_frame(frame)); const auto& obj_name = obj_entry.first;
dwarf_resolver resolver(obj_name);
for(const auto& entry : obj_entry.second) {
const auto& dlframe = entry.first.get();
auto& frame = entry.second.get();
frame = resolver.resolve_frame(dlframe);
}
} }
return trace; return trace;
} }