From 815f15f82c0a35fb4470301204588b405e668a26 Mon Sep 17 00:00:00 2001 From: Daniel Bertalan Date: Sun, 5 Dec 2021 08:45:05 +0100 Subject: [PATCH] LibDebug: Handle DWARF 4 address ranges The format of the address range section is different between DWARF version 4 and version 5. This meant that we parsed programs compiled with `-gdwarf-4` incorrectly. --- .../LibDebug/Dwarf/AddressRanges.cpp | 32 +++++++++++++++++-- .../Libraries/LibDebug/Dwarf/AddressRanges.h | 31 +++++++++++++----- .../LibDebug/Dwarf/CompilationUnit.h | 2 ++ .../Libraries/LibDebug/Dwarf/DwarfInfo.cpp | 17 +++++++--- Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h | 2 ++ 5 files changed, 70 insertions(+), 14 deletions(-) diff --git a/Userland/Libraries/LibDebug/Dwarf/AddressRanges.cpp b/Userland/Libraries/LibDebug/Dwarf/AddressRanges.cpp index cb77e95c65..fb0abf055c 100644 --- a/Userland/Libraries/LibDebug/Dwarf/AddressRanges.cpp +++ b/Userland/Libraries/LibDebug/Dwarf/AddressRanges.cpp @@ -9,14 +9,14 @@ namespace Debug::Dwarf { -AddressRanges::AddressRanges(ReadonlyBytes range_lists_data, size_t offset, CompilationUnit const& compilation_unit) +AddressRangesV5::AddressRangesV5(ReadonlyBytes range_lists_data, size_t offset, CompilationUnit const& compilation_unit) : m_range_lists_stream(range_lists_data) , m_compilation_unit(compilation_unit) { m_range_lists_stream.seek(offset); } -void AddressRanges::for_each_range(Function callback) +void AddressRangesV5::for_each_range(Function callback) { // Dwarf version 5, section 2.17.3 "Non-Contiguous Address Ranges" @@ -86,4 +86,32 @@ void AddressRanges::for_each_range(Function callback) } } +AddressRangesV4::AddressRangesV4(ReadonlyBytes ranges_data, size_t offset, CompilationUnit const& compilation_unit) + : m_ranges_stream(ranges_data) + , m_compilation_unit(compilation_unit) +{ + m_ranges_stream.seek(offset); +} + +void AddressRangesV4::for_each_range(Function callback) +{ + // Dwarf version 4, section 2.17.3 "Non-Contiguous Address Ranges" + + Optional current_base_address; + while (!m_ranges_stream.eof() && !m_ranges_stream.has_any_error()) { + FlatPtr begin, end; + m_ranges_stream >> begin >> end; + + if (begin == 0 && end == 0) { + // end of list entry + return; + } else if (begin == explode_byte(0xff)) { + current_base_address = end; + } else { + FlatPtr base = current_base_address.value_or(m_compilation_unit.base_address().value_or(0)); + callback({ base + begin, base + end }); + } + } +} + } diff --git a/Userland/Libraries/LibDebug/Dwarf/AddressRanges.h b/Userland/Libraries/LibDebug/Dwarf/AddressRanges.h index cd16b10558..f14451d4ea 100644 --- a/Userland/Libraries/LibDebug/Dwarf/AddressRanges.h +++ b/Userland/Libraries/LibDebug/Dwarf/AddressRanges.h @@ -14,17 +14,18 @@ namespace Debug::Dwarf { -class AddressRanges { - AK_MAKE_NONCOPYABLE(AddressRanges); - AK_MAKE_NONMOVABLE(AddressRanges); +struct Range { + FlatPtr start { 0 }; + FlatPtr end { 0 }; +}; + +class AddressRangesV5 { + AK_MAKE_NONCOPYABLE(AddressRangesV5); + AK_MAKE_NONMOVABLE(AddressRangesV5); public: - AddressRanges(ReadonlyBytes range_lists_data, size_t offset, CompilationUnit const& compilation_unit); + AddressRangesV5(ReadonlyBytes range_lists_data, size_t offset, CompilationUnit const& compilation_unit); - struct Range { - FlatPtr start { 0 }; - FlatPtr end { 0 }; - }; void for_each_range(Function); private: @@ -32,4 +33,18 @@ private: CompilationUnit const& m_compilation_unit; }; +class AddressRangesV4 { + AK_MAKE_NONCOPYABLE(AddressRangesV4); + AK_MAKE_NONMOVABLE(AddressRangesV4); + +public: + AddressRangesV4(ReadonlyBytes ranges_data, size_t offset, CompilationUnit const&); + + void for_each_range(Function); + +private: + InputMemoryStream m_ranges_stream; + CompilationUnit const& m_compilation_unit; +}; + } diff --git a/Userland/Libraries/LibDebug/Dwarf/CompilationUnit.h b/Userland/Libraries/LibDebug/Dwarf/CompilationUnit.h index 483148e061..c67aeb014e 100644 --- a/Userland/Libraries/LibDebug/Dwarf/CompilationUnit.h +++ b/Userland/Libraries/LibDebug/Dwarf/CompilationUnit.h @@ -34,6 +34,8 @@ public: FlatPtr get_address(size_t index) const; char const* get_string(size_t index) const; + u8 dwarf_version() const { return m_header.version(); } + DwarfInfo const& dwarf_info() const { return m_dwarf_info; } AbbreviationsMap const& abbreviations_map() const { return m_abbreviations; } LineProgram const& line_program() const { return *m_line_program; } diff --git a/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.cpp b/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.cpp index 08d1689bc5..da94efe54b 100644 --- a/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.cpp +++ b/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.cpp @@ -25,6 +25,7 @@ DwarfInfo::DwarfInfo(ELF::Image const& elf) m_debug_range_lists_data = section_data(".debug_rnglists"sv); m_debug_str_offsets_data = section_data(".debug_str_offsets"sv); m_debug_addr_data = section_data(".debug_addr"sv); + m_debug_ranges_data = section_data(".debug_ranges"sv); populate_compilation_units(); } @@ -346,11 +347,19 @@ void DwarfInfo::build_cached_dies() const auto offsets = reinterpret_cast(debug_range_lists_data().offset(base)); offset = offsets[index] + base; } - AddressRanges address_ranges(debug_range_lists_data(), offset, die.compilation_unit()); + Vector entries; - address_ranges.for_each_range([&entries](auto range) { - entries.empend(range.start, range.end); - }); + if (die.compilation_unit().dwarf_version() == 5) { + AddressRangesV5 address_ranges(debug_range_lists_data(), offset, die.compilation_unit()); + address_ranges.for_each_range([&entries](auto range) { + entries.empend(range.start, range.end); + }); + } else { + AddressRangesV4 address_ranges(debug_ranges_data(), offset, die.compilation_unit()); + address_ranges.for_each_range([&entries](auto range) { + entries.empend(range.start, range.end); + }); + } return entries; } diff --git a/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h b/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h index bcb4253710..3e9375801b 100644 --- a/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h +++ b/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h @@ -33,6 +33,7 @@ public: ReadonlyBytes debug_range_lists_data() const { return m_debug_range_lists_data; } ReadonlyBytes debug_str_offsets_data() const { return m_debug_str_offsets_data; } ReadonlyBytes debug_addr_data() const { return m_debug_addr_data; } + ReadonlyBytes debug_ranges_data() const { return m_debug_ranges_data; } template void for_each_compilation_unit(Callback) const; @@ -64,6 +65,7 @@ private: ReadonlyBytes m_debug_range_lists_data; ReadonlyBytes m_debug_str_offsets_data; ReadonlyBytes m_debug_addr_data; + ReadonlyBytes m_debug_ranges_data; NonnullOwnPtrVector m_compilation_units;