Refactor cu lookup out of pc resolution

This commit is contained in:
Jeremy 2024-05-25 16:18:57 -05:00
parent 8bff5dc9fe
commit 5556aedddb
No known key found for this signature in database
GPG Key ID: BE03111EB7ED6E2E
2 changed files with 62 additions and 18 deletions

View File

@ -809,16 +809,17 @@ namespace libdwarf {
}
}
struct cu_info {
maybe_owned_die_object cu_die;
Dwarf_Half dwversion;
};
// CU resolution has three paths:
// - If aranges are present, the pc is looked up in aranges (falls through to next cases if not in aranges)
// - If cache mode is prioritize memory, the CUs are walked for a match
// - Otherwise a CU cache is built up and CUs are looked up in the map
CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING
void lookup_pc(
Dwarf_Addr pc,
stacktrace_frame& frame,
std::vector<stacktrace_frame>& inlines
) {
if(dump_dwarf) {
std::fprintf(stderr, "%s\n", object_path.c_str());
std::fprintf(stderr, "%llx\n", to_ull(pc));
}
optional<cu_info> lookup_cu(Dwarf_Addr pc) {
// Check for .debug_aranges for fast lookup
if(aranges) {
// Try to find pc in aranges
@ -838,9 +839,8 @@ namespace libdwarf {
std::fprintf(stderr, "Found CU in aranges\n");
cu_die.print();
}
retrieve_line_info(cu_die, pc, frame); // no offset for line info
retrieve_symbol(cu_die, pc, dwversion, frame, inlines);
return;
// resolve_pc(cu_die, dwversion, pc, frame, inlines);
return cu_info{maybe_owned_die_object::owned(std::move(cu_die)), dwversion};
}
}
// otherwise, or if not in aranges
@ -849,7 +849,8 @@ namespace libdwarf {
// compiler while the C compiler defaults to an older gcc)
if(get_cache_mode() == cache_mode::prioritize_memory) {
// walk for the cu and go from there
walk_compilation_units([this, pc, &frame, &inlines] (const die_object& cu_die) {
optional<cu_info> info;
walk_compilation_units([pc, &info] (const die_object& cu_die) {
Dwarf_Half offset_size = 0;
Dwarf_Half dwversion = 0;
dwarf_get_version_of_die(cu_die.get(), &dwversion, &offset_size);
@ -869,12 +870,13 @@ namespace libdwarf {
to_ull(pc)
);
}
retrieve_line_info(cu_die, pc, frame); // no offset for line info
retrieve_symbol(cu_die, pc, dwversion, frame, inlines);
// resolve_pc(cu_die, dwversion, pc, frame, inlines);
info = cu_info{maybe_owned_die_object::owned(cu_die.clone()), dwversion};
return false;
}
return true;
});
return info;
} else {
lazy_generate_cu_cache();
// look up the cu
@ -890,14 +892,33 @@ namespace libdwarf {
if(vec_it != cu_cache.end()) {
//vec_it->die.print();
if(vec_it->die.pc_in_die(vec_it->dwversion, pc)) {
retrieve_line_info(vec_it->die, pc, frame); // no offset for line info
retrieve_symbol(vec_it->die, pc, vec_it->dwversion, frame, inlines);
// resolve_pc(vec_it->die, vec_it->dwversion, pc, frame, inlines);
return cu_info{maybe_owned_die_object::ref(vec_it->die), vec_it->dwversion};
}
} else {
// I've had this happen for _start, where there is a cached CU for the object but _start is outside
// of the CU's PC range
// ASSERT(cu_cache.size() == 0, "Vec should be empty?");
}
return nullopt;
}
}
CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING
void resolve_pc(
Dwarf_Addr pc,
stacktrace_frame& frame,
std::vector<stacktrace_frame>& inlines
) {
if(dump_dwarf) {
std::fprintf(stderr, "%s\n", object_path.c_str());
std::fprintf(stderr, "%llx\n", to_ull(pc));
}
optional<cu_info> cu = lookup_cu(pc);
if(cu) {
const auto& cu_die = cu.unwrap().cu_die.get();
retrieve_line_info(cu_die, pc, frame);
retrieve_symbol(cu_die, pc, cu.unwrap().dwversion, frame, inlines);
}
}
@ -931,7 +952,7 @@ namespace libdwarf {
);
}
std::vector<stacktrace_frame> inlines;
lookup_pc(
resolve_pc(
frame_info.object_address,
frame,
inlines

View File

@ -491,6 +491,29 @@ namespace libdwarf {
}
);
}
class maybe_owned_die_object {
// Hacky... I wish std::variant existed.
optional<die_object> owned_die;
optional<const die_object*> ref_die;
maybe_owned_die_object(die_object&& die) : owned_die(std::move(die)) {}
maybe_owned_die_object(const die_object& die) : ref_die(&die) {}
public:
static maybe_owned_die_object owned(die_object&& die) {
return maybe_owned_die_object{std::move(die)};
}
static maybe_owned_die_object ref(const die_object& die) {
return maybe_owned_die_object{die};
}
const die_object& get() {
ASSERT(owned_die || ref_die, "Mal-formed maybe_owned_die_object");
if(owned_die) {
return owned_die.unwrap();
} else {
return *ref_die.unwrap();
}
}
};
}
}
}