Implement better logic for handling scrfile indices, related to #86

This commit is contained in:
Jeremy 2024-02-11 21:02:48 -06:00
parent cb92c9fdfa
commit e6627b760d
No known key found for this signature in database
GPG Key ID: 19AA8270105E8EB4

View File

@ -75,6 +75,7 @@ namespace libdwarf {
Dwarf_Unsigned version; Dwarf_Unsigned version;
Dwarf_Line_Context line_context; Dwarf_Line_Context line_context;
// sorted by low_addr // sorted by low_addr
// TODO: Make this optional at some point, it may not be generated if cache mode switches during program exec...
std::vector<line_entry> line_entries; std::vector<line_entry> line_entries;
}; };
@ -93,7 +94,7 @@ namespace libdwarf {
Dwarf_Arange* aranges = nullptr; Dwarf_Arange* aranges = nullptr;
Dwarf_Signed arange_count = 0; Dwarf_Signed arange_count = 0;
// Map from CU -> Line context // Map from CU -> Line context
std::unordered_map<Dwarf_Off, line_table_info> line_contexts; std::unordered_map<Dwarf_Off, line_table_info> line_tables;
// Map from CU -> Sorted subprograms vector // Map from CU -> Sorted subprograms vector
std::unordered_map<Dwarf_Off, std::vector<subprogram_entry>> subprograms_cache; std::unordered_map<Dwarf_Off, std::vector<subprogram_entry>> subprograms_cache;
// Vector of ranges and their corresponding CU offsets // Vector of ranges and their corresponding CU offsets
@ -190,7 +191,7 @@ namespace libdwarf {
~dwarf_resolver() { ~dwarf_resolver() {
// TODO: Maybe redundant since dwarf_finish(dbg); will clean up the line stuff anyway but may as well just // TODO: Maybe redundant since dwarf_finish(dbg); will clean up the line stuff anyway but may as well just
// for thoroughness // for thoroughness
for(auto& entry : line_contexts) { for(auto& entry : line_tables) {
dwarf_srclines_dealloc_b(entry.second.line_context); dwarf_srclines_dealloc_b(entry.second.line_context);
} }
for(auto& entry : srcfiles_cache) { for(auto& entry : srcfiles_cache) {
@ -214,7 +215,7 @@ namespace libdwarf {
ok(other.ok), ok(other.ok),
aranges(other.aranges), aranges(other.aranges),
arange_count(other.arange_count), arange_count(other.arange_count),
line_contexts(std::move(other.line_contexts)), line_tables(std::move(other.line_tables)),
subprograms_cache(std::move(other.subprograms_cache)), subprograms_cache(std::move(other.subprograms_cache)),
cu_cache(std::move(other.cu_cache)), cu_cache(std::move(other.cu_cache)),
generated_cu_cache(other.generated_cu_cache), generated_cu_cache(other.generated_cu_cache),
@ -230,7 +231,7 @@ namespace libdwarf {
ok = other.ok; ok = other.ok;
aranges = other.aranges; aranges = other.aranges;
arange_count = other.arange_count; arange_count = other.arange_count;
line_contexts = std::move(other.line_contexts); line_tables = std::move(other.line_tables);
subprograms_cache = std::move(other.subprograms_cache); subprograms_cache = std::move(other.subprograms_cache);
cu_cache = std::move(other.cu_cache); cu_cache = std::move(other.cu_cache);
generated_cu_cache = other.generated_cu_cache; generated_cu_cache = other.generated_cu_cache;
@ -335,6 +336,7 @@ namespace libdwarf {
return ""; return "";
} }
// despite (some) dwarf using 1-indexing, file_i should be the 0-based index
std::string resolve_filename(const die_object& cu_die, Dwarf_Unsigned file_i) { std::string resolve_filename(const die_object& cu_die, Dwarf_Unsigned file_i) {
std::string filename; std::string filename;
if(get_cache_mode() == cache_mode::prioritize_memory) { if(get_cache_mode() == cache_mode::prioritize_memory) {
@ -343,7 +345,7 @@ namespace libdwarf {
VERIFY(wrap(dwarf_srcfiles, cu_die.get(), &dw_srcfiles, &dw_filecount) == DW_DLV_OK); VERIFY(wrap(dwarf_srcfiles, cu_die.get(), &dw_srcfiles, &dw_filecount) == DW_DLV_OK);
if(Dwarf_Signed(file_i) < dw_filecount) { if(Dwarf_Signed(file_i) < dw_filecount) {
// dwarf is using 1-indexing // dwarf is using 1-indexing
filename = dw_srcfiles[file_i - 1]; filename = dw_srcfiles[file_i];
} }
dwarf_dealloc(cu_die.dbg, dw_srcfiles, DW_DLA_LIST); dwarf_dealloc(cu_die.dbg, dw_srcfiles, DW_DLA_LIST);
} else { } else {
@ -359,7 +361,7 @@ namespace libdwarf {
Dwarf_Signed dw_filecount = it->second.second; Dwarf_Signed dw_filecount = it->second.second;
if(Dwarf_Signed(file_i) < dw_filecount) { if(Dwarf_Signed(file_i) < dw_filecount) {
// dwarf is using 1-indexing // dwarf is using 1-indexing
filename = dw_srcfiles[file_i - 1]; filename = dw_srcfiles[file_i];
} }
} }
return filename; return filename;
@ -380,14 +382,26 @@ namespace libdwarf {
[this, &cu_die, pc, dwversion, &inlines] (const die_object& die) { [this, &cu_die, pc, dwversion, &inlines] (const die_object& die) {
if(die.get_tag() == DW_TAG_inlined_subroutine && die.pc_in_die(dwversion, pc)) { if(die.get_tag() == DW_TAG_inlined_subroutine && die.pc_in_die(dwversion, pc)) {
const auto name = subprogram_symbol(die, dwversion); const auto name = subprogram_symbol(die, dwversion);
const auto file_i = die.get_unsigned_attribute(DW_AT_call_file); auto file_i = die.get_unsigned_attribute(DW_AT_call_file);
// TODO: Somehow file_i can end up being 0 here, in a way I don't understand. The string if(file_i) {
// table is 1-indexed and the first string isn't the correct string. Somehow dwarfdump // for dwarf 2, 3, 4, and experimental line table version 0xfe06 1-indexing is used
// resolves this correctly. And also somehow in testing a file name ends up getting used // for dwarf 5 0-indexing is used
// here but I have no idea where it's coming from. auto line_table_opt = get_line_table(cu_die);
std::string file = file_i && file_i.unwrap() > 0 if(line_table_opt) {
? resolve_filename(cu_die, file_i.unwrap()) auto& line_table = line_table_opt.unwrap().get();
: ""; if(line_table.version != 5) {
if(file_i.unwrap() == 0) {
file_i.reset(); // 0 means no name to be found
} else {
// decrement to 0-based index
file_i.unwrap()--;
}
}
} else {
// silently continue
}
}
std::string file = file_i ? resolve_filename(cu_die, file_i.unwrap()) : "";
const auto line = die.get_unsigned_attribute(DW_AT_call_line); const auto line = die.get_unsigned_attribute(DW_AT_call_line);
const auto col = die.get_unsigned_attribute(DW_AT_call_column); const auto col = die.get_unsigned_attribute(DW_AT_call_column);
inlines.push_back(stacktrace_frame{ inlines.push_back(stacktrace_frame{
@ -578,24 +592,20 @@ namespace libdwarf {
} }
} }
// returns a reference to a CU's line table, may be invalidated if the line_tables map is modified
CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING
void retrieve_line_info( optional<std::reference_wrapper<line_table_info>> get_line_table(const die_object& cu_die) {
const die_object& die, auto off = cu_die.get_global_offset();
Dwarf_Addr pc, auto it = line_tables.find(off);
stacktrace_frame& frame if(it != line_tables.end()) {
) { return it->second;
auto off = die.get_global_offset();
auto it = line_contexts.find(off);
if(it != line_contexts.end()) {
// auto& entry = it->second;
// line_context = entry.line_context;
} else { } else {
Dwarf_Unsigned version; Dwarf_Unsigned version;
Dwarf_Small table_count; Dwarf_Small table_count;
Dwarf_Line_Context line_context; Dwarf_Line_Context line_context;
int ret = wrap( int ret = wrap(
dwarf_srclines_b, dwarf_srclines_b,
die.get(), cu_die.get(),
&version, &version,
&table_count, &table_count,
&line_context &line_context
@ -604,7 +614,7 @@ namespace libdwarf {
VERIFY(/*table_count >= 0 &&*/ table_count <= 2, "Unknown dwarf line table count"); VERIFY(/*table_count >= 0 &&*/ table_count <= 2, "Unknown dwarf line table count");
if(ret == DW_DLV_NO_ENTRY) { if(ret == DW_DLV_NO_ENTRY) {
// TODO: Failing silently for now // TODO: Failing silently for now
return; return nullopt;
} }
VERIFY(ret == DW_DLV_OK); VERIFY(ret == DW_DLV_OK);
@ -672,11 +682,22 @@ namespace libdwarf {
}); });
} }
it = line_contexts.insert({off, {version, line_context, std::move(line_entries)}}).first; it = line_tables.insert({off, {version, line_context, std::move(line_entries)}}).first;
return it->second;
}
} }
auto& table_info = it->second; CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING
void retrieve_line_info(
const die_object& cu_die,
Dwarf_Addr pc,
stacktrace_frame& frame
) {
auto table_info_opt = get_line_table(cu_die);
if(!table_info_opt) {
return; // failing silently for now
}
auto& table_info = table_info_opt.unwrap().get();
if(get_cache_mode() == cache_mode::prioritize_speed) { if(get_cache_mode() == cache_mode::prioritize_speed) {
// Lookup in the table // Lookup in the table
auto& line_entries = table_info.line_entries; auto& line_entries = table_info.line_entries;