summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h
blob: 24a72e9f750c601bc2816a6af10ddeaeff85c59a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/*
 * Copyright (c) 2020-2021, Itamar S. <itamar8910@gmail.com>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include "AttributeValue.h"
#include "DwarfTypes.h"
#include <AK/ByteBuffer.h>
#include <AK/DeprecatedString.h>
#include <AK/NonnullOwnPtrVector.h>
#include <AK/NonnullRefPtr.h>
#include <AK/RedBlackTree.h>
#include <AK/RefCounted.h>
#include <LibDebug/Dwarf/DIE.h>
#include <LibELF/Image.h>

namespace Debug::Dwarf {

class CompilationUnit;

class DwarfInfo {
    AK_MAKE_NONCOPYABLE(DwarfInfo);
    AK_MAKE_NONMOVABLE(DwarfInfo);

public:
    explicit DwarfInfo(ELF::Image const&);
    ~DwarfInfo();

    ReadonlyBytes debug_info_data() const { return m_debug_info_data; }
    ReadonlyBytes abbreviation_data() const { return m_abbreviation_data; }
    ReadonlyBytes debug_strings_data() const { return m_debug_strings_data; }
    ReadonlyBytes debug_line_strings_data() const { return m_debug_line_strings_data; }
    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<typename Callback>
    ErrorOr<void> for_each_compilation_unit(Callback) const;

    ErrorOr<AttributeValue> get_attribute_value(AttributeDataForm form, ssize_t implicit_const_value,
        SeekableStream& debug_info_stream, CompilationUnit const* unit = nullptr) const;

    ErrorOr<Optional<DIE>> get_die_at_address(FlatPtr) const;

    // Note that even if there is a DIE at the given offset,
    // but it does not exist in the DIE cache (because for example
    // it does not contain an address range), then this function will not return it.
    // To get any DIE object at a given offset in a compilation unit,
    // use CompilationUnit::get_die_at_offset.
    ErrorOr<Optional<DIE>> get_cached_die_at_offset(FlatPtr) const;

private:
    ErrorOr<void> populate_compilation_units();
    ErrorOr<void> build_cached_dies() const;

    ReadonlyBytes section_data(StringView section_name) const;

    ELF::Image const& m_elf;
    ReadonlyBytes m_debug_info_data;
    ReadonlyBytes m_abbreviation_data;
    ReadonlyBytes m_debug_strings_data;
    ReadonlyBytes m_debug_line_data;
    ReadonlyBytes m_debug_line_strings_data;
    ReadonlyBytes m_debug_range_lists_data;
    ReadonlyBytes m_debug_str_offsets_data;
    ReadonlyBytes m_debug_addr_data;
    ReadonlyBytes m_debug_ranges_data;

    NonnullOwnPtrVector<Dwarf::CompilationUnit> m_compilation_units;

    struct DIERange {
        FlatPtr start_address { 0 };
        FlatPtr end_address { 0 };
    };

    struct DIEAndRange {
        DIE die;
        DIERange range;
    };

    using DIEStartAddress = FlatPtr;

    mutable RedBlackTree<DIEStartAddress, DIEAndRange> m_cached_dies_by_range;
    mutable RedBlackTree<FlatPtr, DIE> m_cached_dies_by_offset;
    mutable bool m_built_cached_dies { false };
};

template<typename Callback>
ErrorOr<void> DwarfInfo::for_each_compilation_unit(Callback callback) const
{
    for (auto const& unit : m_compilation_units) {
        TRY(callback(unit));
    }
    return {};
}

}