ソースを参照

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.
Itamar 3 年 前
コミット
26a96d315d

+ 1 - 0
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

+ 67 - 0
Userland/Libraries/LibDebug/Dwarf/AddressRanges.cpp

@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2020-2021, Itamar S. <itamar8910@gmail.com>
+ *
+ * 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<void(Range)> callback)
+{
+    // Dwarf version 5, section 2.17.3 "Non-Contiguous Address Ranges"
+
+    Optional<FlatPtr> 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<RangeListEntryType>(entry_type)) {
+        case RangeListEntryType::BaseAddress: {
+            FlatPtr base;
+            m_range_lists_stream >> base;
+            current_base_address = base;
+            break;
+        }
+        case RangeListEntryType::OffsetPair: {
+            Optional<FlatPtr> 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;
+        }
+    }
+}
+
+}

+ 35 - 0
Userland/Libraries/LibDebug/Dwarf/AddressRanges.h

@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020-2021, Itamar S. <itamar8910@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include "CompilationUnit.h"
+#include <AK/Forward.h>
+#include <AK/Function.h>
+#include <AK/MemoryStream.h>
+#include <AK/Noncopyable.h>
+
+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<void(Range)>);
+
+private:
+    InputMemoryStream m_range_lists_stream;
+    CompilationUnit const& m_compilation_unit;
+};
+
+}

+ 12 - 0
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
+};
+
 }