From 26a96d315ddc7f1753e7d3cb5246c7817fedfb8f Mon Sep 17 00:00:00 2001 From: Itamar Date: Tue, 28 Sep 2021 13:19:32 +0300 Subject: [PATCH] LibDebug: Support parsing non-contiguous DWARF address ranges This adds support for parsing DWARF "range lists", which are identified by the DW_AT_ranges form. They contain code addresses for DIEs whose location is not contiguous. --- Userland/Libraries/LibDebug/CMakeLists.txt | 1 + .../LibDebug/Dwarf/AddressRanges.cpp | 67 +++++++++++++++++++ .../Libraries/LibDebug/Dwarf/AddressRanges.h | 35 ++++++++++ .../Libraries/LibDebug/Dwarf/DwarfTypes.h | 12 ++++ 4 files changed, 115 insertions(+) create mode 100644 Userland/Libraries/LibDebug/Dwarf/AddressRanges.cpp create mode 100644 Userland/Libraries/LibDebug/Dwarf/AddressRanges.h diff --git a/Userland/Libraries/LibDebug/CMakeLists.txt b/Userland/Libraries/LibDebug/CMakeLists.txt index a2fa57a9a5..e03bc1f625 100644 --- a/Userland/Libraries/LibDebug/CMakeLists.txt +++ b/Userland/Libraries/LibDebug/CMakeLists.txt @@ -2,6 +2,7 @@ set(SOURCES DebugInfo.cpp DebugSession.cpp Dwarf/AbbreviationsMap.cpp + Dwarf/AddressRanges.cpp Dwarf/CompilationUnit.cpp Dwarf/DIE.cpp Dwarf/DwarfInfo.cpp diff --git a/Userland/Libraries/LibDebug/Dwarf/AddressRanges.cpp b/Userland/Libraries/LibDebug/Dwarf/AddressRanges.cpp new file mode 100644 index 0000000000..fe6eb1c04a --- /dev/null +++ b/Userland/Libraries/LibDebug/Dwarf/AddressRanges.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020-2021, Itamar S. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "AddressRanges.h" +#include "DwarfTypes.h" + +namespace Debug::Dwarf { + +AddressRanges::AddressRanges(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) +{ + // Dwarf version 5, section 2.17.3 "Non-Contiguous Address Ranges" + + Optional current_base_address; + while (!m_range_lists_stream.eof() && !m_range_lists_stream.has_any_error()) { + u8 entry_type; + m_range_lists_stream >> entry_type; + switch (static_cast(entry_type)) { + case RangeListEntryType::BaseAddress: { + FlatPtr base; + m_range_lists_stream >> base; + current_base_address = base; + break; + } + case RangeListEntryType::OffsetPair: { + Optional base_address = current_base_address; + if (!base_address.has_value()) { + base_address = m_compilation_unit.base_address(); + } + + if (!base_address.has_value()) { + dbgln("expected base_address for rangelist"); + return; + } + + size_t start_offset, end_offset; + m_range_lists_stream.read_LEB128_unsigned(start_offset); + m_range_lists_stream.read_LEB128_unsigned(end_offset); + callback(Range { start_offset + *base_address, end_offset + *base_address }); + break; + } + case RangeListEntryType::StartLength: { + FlatPtr start; + m_range_lists_stream >> start; + size_t length; + m_range_lists_stream.read_LEB128_unsigned(length); + callback(Range { start, start + length }); + } + case RangeListEntryType::EndOfList: + return; + default: + dbgln("unsupported range list entry type: 0x{:x}", (int)entry_type); + return; + } + } +} + +} diff --git a/Userland/Libraries/LibDebug/Dwarf/AddressRanges.h b/Userland/Libraries/LibDebug/Dwarf/AddressRanges.h new file mode 100644 index 0000000000..cd16b10558 --- /dev/null +++ b/Userland/Libraries/LibDebug/Dwarf/AddressRanges.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020-2021, Itamar S. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include "CompilationUnit.h" +#include +#include +#include +#include + +namespace Debug::Dwarf { + +class AddressRanges { + AK_MAKE_NONCOPYABLE(AddressRanges); + AK_MAKE_NONMOVABLE(AddressRanges); + +public: + AddressRanges(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: + InputMemoryStream m_range_lists_stream; + CompilationUnit const& m_compilation_unit; +}; + +} diff --git a/Userland/Libraries/LibDebug/Dwarf/DwarfTypes.h b/Userland/Libraries/LibDebug/Dwarf/DwarfTypes.h index 8a66ca71ea..aa8e2c0e08 100644 --- a/Userland/Libraries/LibDebug/Dwarf/DwarfTypes.h +++ b/Userland/Libraries/LibDebug/Dwarf/DwarfTypes.h @@ -317,4 +317,16 @@ struct [[gnu::packed]] AttributeSpecification { ssize_t value; }; +// Dwarf version 5, section 7.25 +enum class RangeListEntryType : u8 { + EndOfList = 0, + BaseAddressX = 0x1, + StartXEndX = 0x2, + StartXLength = 0x3, + OffsetPair = 0x4, + BaseAddress = 0x5, + StartEnd = 0x6, + StartLength = 0x7 +}; + }