From fef039ba26995fde69e6b1061217c1e8e21521c1 Mon Sep 17 00:00:00 2001 From: Jeremy <51220084+jeremy-rifkin@users.noreply.github.com> Date: Mon, 6 Nov 2023 22:38:21 -0500 Subject: [PATCH] Setup a lookup table for line info --- src/symbols/symbols_with_libdwarf.cpp | 189 ++++++++++++++++---------- 1 file changed, 118 insertions(+), 71 deletions(-) diff --git a/src/symbols/symbols_with_libdwarf.cpp b/src/symbols/symbols_with_libdwarf.cpp index e3a1bb9..e5f34ea 100644 --- a/src/symbols/symbols_with_libdwarf.cpp +++ b/src/symbols/symbols_with_libdwarf.cpp @@ -51,11 +51,6 @@ namespace libdwarf { constexpr bool dump_dwarf = false; constexpr bool trace_dwarf = false; - struct line_context { - Dwarf_Unsigned version; - Dwarf_Line_Context line_context; - }; - struct subprogram_entry { die_object die; Dwarf_Addr low; @@ -69,6 +64,22 @@ namespace libdwarf { Dwarf_Addr high; }; + struct line_entry { + Dwarf_Addr low; + // Dwarf_Addr high; + // int i; + Dwarf_Line line; + optional path; + optional line_number; + }; + + struct line_table_info { + Dwarf_Unsigned version; + Dwarf_Line_Context line_context; + // sorted by low_addr + std::vector line_entries; + }; + struct dwarf_resolver { std::string obj_path; Dwarf_Debug dbg = nullptr; @@ -77,7 +88,7 @@ namespace libdwarf { Dwarf_Arange* aranges = nullptr; Dwarf_Signed arange_count = 0; // Map from CU -> Line context - std::unordered_map line_contexts; + std::unordered_map line_contexts; // Map from CU -> Sorted subprograms vector std::unordered_map> subprograms_cache; // Vector of ranges and their corresponding CU offsets @@ -449,13 +460,13 @@ namespace libdwarf { ) { auto off = die.get_global_offset(); auto it = line_contexts.find(off); - Dwarf_Line_Context line_context; if(it != line_contexts.end()) { - auto& entry = it->second; - line_context = entry.line_context; + // auto& entry = it->second; + // line_context = entry.line_context; } else { Dwarf_Unsigned version; Dwarf_Small table_count; + Dwarf_Line_Context line_context; int ret = wrap( dwarf_srclines_b, die.get(), @@ -470,66 +481,102 @@ namespace libdwarf { return; } VERIFY(ret == DW_DLV_OK); - line_contexts.insert({off, {version, line_context}}); - } - Dwarf_Line* line_buffer = nullptr; - Dwarf_Signed line_count = 0; - Dwarf_Line* linebuf_actuals = nullptr; - Dwarf_Signed linecount_actuals = 0; - VERIFY( - wrap( - dwarf_srclines_two_level_from_linecontext, - line_context, - &line_buffer, - &line_count, - &linebuf_actuals, - &linecount_actuals - ) == DW_DLV_OK - ); - Dwarf_Addr last_lineaddr = 0; - Dwarf_Line last_line = nullptr; - for(int i = 0; i < line_count; i++) { - Dwarf_Line line = line_buffer[i]; - Dwarf_Addr lineaddr = 0; - VERIFY(wrap(dwarf_lineaddr, line, &lineaddr) == DW_DLV_OK); - Dwarf_Line found_line = nullptr; - if(pc == lineaddr) { - // Multiple PCs may correspond to a line, find the last one - found_line = line; - for(int j = i + 1; j < line_count; j++) { - Dwarf_Line line = line_buffer[j]; - Dwarf_Addr lineaddr = 0; - VERIFY(wrap(dwarf_lineaddr, line, &lineaddr) == DW_DLV_OK); - if(pc == lineaddr) { - found_line = line; + + // build lookup table + Dwarf_Line* line_buffer = nullptr; + Dwarf_Signed line_count = 0; + Dwarf_Line* linebuf_actuals = nullptr; + Dwarf_Signed linecount_actuals = 0; + VERIFY( + wrap( + dwarf_srclines_two_level_from_linecontext, + line_context, + &line_buffer, + &line_count, + &linebuf_actuals, + &linecount_actuals + ) == DW_DLV_OK + ); + + std::vector line_entries; + Dwarf_Addr last_pc = 0; + // TODO: Make any attempt to note PC ranges? Handle line end sequence? + for(int i = 0; i < line_count; i++) { + Dwarf_Line line = line_buffer[i]; + Dwarf_Addr low_addr = 0; + VERIFY(wrap(dwarf_lineaddr, line, &low_addr) == DW_DLV_OK); + // scan ahead for the last line entry matching this pc + int j; + for(j = i + 1; j < line_count; j++) { + Dwarf_Addr addr = 0; + VERIFY(wrap(dwarf_lineaddr, line_buffer[j], &addr) == DW_DLV_OK); + if(addr != low_addr) { + break; } } - } else if(last_line && pc > last_lineaddr && pc < lineaddr) { - // Guess that the last line had it - found_line = last_line; + line = line_buffer[j - 1]; + // { + // Dwarf_Unsigned line_number = 0; + // VERIFY(wrap(dwarf_lineno, line, &line_number) == DW_DLV_OK); + // frame.line = static_cast(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) { - Dwarf_Unsigned line_number = 0; - VERIFY(wrap(dwarf_lineno, found_line, &line_number) == DW_DLV_OK); - frame.line = static_cast(line_number); - char* filename = nullptr; - VERIFY(wrap(dwarf_linesrc, found_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; - } else { - Dwarf_Bool is_line_end; - VERIFY(wrap(dwarf_lineendsequence, line, &is_line_end) == DW_DLV_OK); - if(is_line_end) { - last_lineaddr = 0; - last_line = nullptr; - } else { - last_lineaddr = lineaddr; - last_line = line; - } + // sort lines + std::sort(line_entries.begin(), line_entries.end(), [] (const line_entry& a, const line_entry& b) { + return a.low < b.low; + }); + + it = line_contexts.insert({off, {version, line_context, std::move(line_entries)}}).first; + } + + auto& table_info = it->second; + auto& line_entries = table_info.line_entries; + Dwarf_Line_Context line_context = table_info.line_context; + + auto table_it = std::lower_bound( + line_entries.begin(), + line_entries.end(), + pc, + [] (const line_entry& entry, Dwarf_Addr pc) { + return entry.low < pc; } + ); + // 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(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 { // look up the cu auto vec_it = std::lower_bound( - cu_cache.begin(), - cu_cache.end(), - pc, - [] (const cu_entry& entry, Dwarf_Addr pc) { - return entry.low < pc; - } + cu_cache.begin(), + cu_cache.end(), + pc, + [] (const cu_entry& entry, Dwarf_Addr pc) { + return entry.low < pc; + } ); // vec_it is first >= pc // we want first <= pc