Setup a lookup table for line info

This commit is contained in:
Jeremy 2023-11-06 22:38:21 -05:00
parent f4a71c2d23
commit fef039ba26
No known key found for this signature in database
GPG Key ID: BE03111EB7ED6E2E

View File

@ -51,11 +51,6 @@ namespace libdwarf {
constexpr bool dump_dwarf = false; constexpr bool dump_dwarf = false;
constexpr bool trace_dwarf = false; constexpr bool trace_dwarf = false;
struct line_context {
Dwarf_Unsigned version;
Dwarf_Line_Context line_context;
};
struct subprogram_entry { struct subprogram_entry {
die_object die; die_object die;
Dwarf_Addr low; Dwarf_Addr low;
@ -69,6 +64,22 @@ namespace libdwarf {
Dwarf_Addr high; Dwarf_Addr high;
}; };
struct line_entry {
Dwarf_Addr low;
// Dwarf_Addr high;
// int i;
Dwarf_Line line;
optional<std::string> path;
optional<unsigned> line_number;
};
struct line_table_info {
Dwarf_Unsigned version;
Dwarf_Line_Context line_context;
// sorted by low_addr
std::vector<line_entry> line_entries;
};
struct dwarf_resolver { struct dwarf_resolver {
std::string obj_path; std::string obj_path;
Dwarf_Debug dbg = nullptr; Dwarf_Debug dbg = nullptr;
@ -77,7 +88,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_context> line_contexts; std::unordered_map<Dwarf_Off, line_table_info> line_contexts;
// 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
@ -449,13 +460,13 @@ namespace libdwarf {
) { ) {
auto off = die.get_global_offset(); auto off = die.get_global_offset();
auto it = line_contexts.find(off); auto it = line_contexts.find(off);
Dwarf_Line_Context line_context;
if(it != line_contexts.end()) { if(it != line_contexts.end()) {
auto& entry = it->second; // auto& entry = it->second;
line_context = entry.line_context; // 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;
int ret = wrap( int ret = wrap(
dwarf_srclines_b, dwarf_srclines_b,
die.get(), die.get(),
@ -470,66 +481,102 @@ namespace libdwarf {
return; return;
} }
VERIFY(ret == DW_DLV_OK); VERIFY(ret == DW_DLV_OK);
line_contexts.insert({off, {version, line_context}});
} // build lookup table
Dwarf_Line* line_buffer = nullptr; Dwarf_Line* line_buffer = nullptr;
Dwarf_Signed line_count = 0; Dwarf_Signed line_count = 0;
Dwarf_Line* linebuf_actuals = nullptr; Dwarf_Line* linebuf_actuals = nullptr;
Dwarf_Signed linecount_actuals = 0; Dwarf_Signed linecount_actuals = 0;
VERIFY( VERIFY(
wrap( wrap(
dwarf_srclines_two_level_from_linecontext, dwarf_srclines_two_level_from_linecontext,
line_context, line_context,
&line_buffer, &line_buffer,
&line_count, &line_count,
&linebuf_actuals, &linebuf_actuals,
&linecount_actuals &linecount_actuals
) == DW_DLV_OK ) == DW_DLV_OK
); );
Dwarf_Addr last_lineaddr = 0;
Dwarf_Line last_line = nullptr; std::vector<line_entry> line_entries;
for(int i = 0; i < line_count; i++) { Dwarf_Addr last_pc = 0;
Dwarf_Line line = line_buffer[i]; // TODO: Make any attempt to note PC ranges? Handle line end sequence?
Dwarf_Addr lineaddr = 0; for(int i = 0; i < line_count; i++) {
VERIFY(wrap(dwarf_lineaddr, line, &lineaddr) == DW_DLV_OK); Dwarf_Line line = line_buffer[i];
Dwarf_Line found_line = nullptr; Dwarf_Addr low_addr = 0;
if(pc == lineaddr) { VERIFY(wrap(dwarf_lineaddr, line, &low_addr) == DW_DLV_OK);
// Multiple PCs may correspond to a line, find the last one // scan ahead for the last line entry matching this pc
found_line = line; int j;
for(int j = i + 1; j < line_count; j++) { for(j = i + 1; j < line_count; j++) {
Dwarf_Line line = line_buffer[j]; Dwarf_Addr addr = 0;
Dwarf_Addr lineaddr = 0; VERIFY(wrap(dwarf_lineaddr, line_buffer[j], &addr) == DW_DLV_OK);
VERIFY(wrap(dwarf_lineaddr, line, &lineaddr) == DW_DLV_OK); if(addr != low_addr) {
if(pc == lineaddr) { break;
found_line = line;
} }
} }
} else if(last_line && pc > last_lineaddr && pc < lineaddr) { line = line_buffer[j - 1];
// Guess that the last line had it // {
found_line = last_line; // Dwarf_Unsigned line_number = 0;
// VERIFY(wrap(dwarf_lineno, line, &line_number) == DW_DLV_OK);
// frame.line = static_cast<std::uint_least32_t>(line_number);
// char* filename = nullptr;
// VERIFY(wrap(dwarf_linesrc, line, &filename) == DW_DLV_OK);
// auto wrapper = raii_wrap(
// filename,
// [this] (char* str) { if(str) dwarf_dealloc(dbg, str, DW_DLA_STRING); }
// );
// frame.filename = filename;
// printf("%s : %d\n", filename, line_number);
// Dwarf_Bool is_line_end;
// VERIFY(wrap(dwarf_lineendsequence, line, &is_line_end) == DW_DLV_OK);
// if(is_line_end) {
// puts("Line end");
// }
// }
line_entries.push_back({
low_addr,
line // j - 1
});
i = j - 1;
} }
if(found_line) { // sort lines
Dwarf_Unsigned line_number = 0; std::sort(line_entries.begin(), line_entries.end(), [] (const line_entry& a, const line_entry& b) {
VERIFY(wrap(dwarf_lineno, found_line, &line_number) == DW_DLV_OK); return a.low < b.low;
frame.line = static_cast<std::uint_least32_t>(line_number); });
char* filename = nullptr;
VERIFY(wrap(dwarf_linesrc, found_line, &filename) == DW_DLV_OK); it = line_contexts.insert({off, {version, line_context, std::move(line_entries)}}).first;
auto wrapper = raii_wrap( }
filename,
[this] (char* str) { if(str) dwarf_dealloc(dbg, str, DW_DLA_STRING); } auto& table_info = it->second;
); auto& line_entries = table_info.line_entries;
frame.filename = filename; Dwarf_Line_Context line_context = table_info.line_context;
} else {
Dwarf_Bool is_line_end; auto table_it = std::lower_bound(
VERIFY(wrap(dwarf_lineendsequence, line, &is_line_end) == DW_DLV_OK); line_entries.begin(),
if(is_line_end) { line_entries.end(),
last_lineaddr = 0; pc,
last_line = nullptr; [] (const line_entry& entry, Dwarf_Addr pc) {
} else { return entry.low < pc;
last_lineaddr = lineaddr;
last_line = line;
}
} }
);
// vec_it is first >= pc
// we want first <= pc
if(table_it != line_entries.begin()) {
table_it--;
}
// If the vector has been empty this can happen
if(table_it != line_entries.end()) {
Dwarf_Line line = table_it->line;
Dwarf_Unsigned line_number = 0;
VERIFY(wrap(dwarf_lineno, line, &line_number) == DW_DLV_OK);
frame.line = static_cast<std::uint_least32_t>(line_number);
char* filename = nullptr;
VERIFY(wrap(dwarf_linesrc, line, &filename) == DW_DLV_OK);
auto wrapper = raii_wrap(
filename,
[this] (char* str) { if(str) dwarf_dealloc(dbg, str, DW_DLA_STRING); }
);
frame.filename = filename;
} }
} }
@ -596,12 +643,12 @@ namespace libdwarf {
} else { } else {
// look up the cu // look up the cu
auto vec_it = std::lower_bound( auto vec_it = std::lower_bound(
cu_cache.begin(), cu_cache.begin(),
cu_cache.end(), cu_cache.end(),
pc, pc,
[] (const cu_entry& entry, Dwarf_Addr pc) { [] (const cu_entry& entry, Dwarf_Addr pc) {
return entry.low < pc; return entry.low < pc;
} }
); );
// vec_it is first >= pc // vec_it is first >= pc
// we want first <= pc // we want first <= pc