summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibDebug/DebugInfo.h
blob: 43493c33132bb4b3d56c6de966f0bbbaec2c29ef (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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
 * Copyright (c) 2020-2021, Itamar S. <itamar8910@gmail.com>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <AK/NonnullOwnPtrVector.h>
#include <AK/NonnullRefPtr.h>
#include <AK/Optional.h>
#include <AK/OwnPtr.h>
#include <AK/Vector.h>
#include <LibDebug/Dwarf/DIE.h>
#include <LibDebug/Dwarf/DwarfInfo.h>
#include <LibDebug/Dwarf/LineProgram.h>
#include <LibELF/Image.h>
#include <sys/arch/i386/regs.h>

namespace Debug {

class DebugInfo {
    AK_MAKE_NONCOPYABLE(DebugInfo);
    AK_MAKE_NONMOVABLE(DebugInfo);

public:
    explicit DebugInfo(ELF::Image const&, String source_root = {}, FlatPtr base_address = 0);

    ELF::Image const& elf() const { return m_elf; }

    struct SourcePosition {
        FlyString file_path;
        size_t line_number { 0 };
        Optional<FlatPtr> address_of_first_statement;

        SourcePosition()
            : SourcePosition(String::empty(), 0)
        {
        }
        SourcePosition(String file_path, size_t line_number)
            : file_path(file_path)
            , line_number(line_number)
        {
        }
        SourcePosition(String file_path, size_t line_number, FlatPtr address_of_first_statement)
            : file_path(file_path)
            , line_number(line_number)
            , address_of_first_statement(address_of_first_statement)
        {
        }

        bool operator==(SourcePosition const& other) const { return file_path == other.file_path && line_number == other.line_number; }
        bool operator!=(SourcePosition const& other) const { return !(*this == other); }

        static SourcePosition from_line_info(Dwarf::LineProgram::LineInfo const&);
    };

    struct VariableInfo {
        enum class LocationType {
            None,
            Address,
            Register,
        };
        String name;
        String type_name;
        LocationType location_type { LocationType::None };
        union {
            FlatPtr address;
        } location_data { 0 };

        union {
            u32 as_u32;
            u32 as_i32;
            char const* as_string;
        } constant_data { 0 };

        Dwarf::EntryTag type_tag;
        OwnPtr<VariableInfo> type;
        NonnullOwnPtrVector<VariableInfo> members;
        VariableInfo* parent { nullptr };
        Vector<u32> dimension_sizes;

        bool is_enum_type() const { return type && type->type_tag == Dwarf::EntryTag::EnumerationType; }
    };

    struct VariablesScope {
        bool is_function { false };
        String name;
        FlatPtr address_low { 0 };
        FlatPtr address_high { 0 }; // Non-inclusive - the lowest address after address_low that's not in this scope
        Vector<Dwarf::DIE> dies_of_variables;
    };

    NonnullOwnPtrVector<VariableInfo> get_variables_in_current_scope(PtraceRegisters const&) const;

    Optional<SourcePosition> get_source_position(FlatPtr address) const;

    struct SourcePositionWithInlines {
        Optional<SourcePosition> source_position;
        Vector<SourcePosition> inline_chain;
    };
    SourcePositionWithInlines get_source_position_with_inlines(FlatPtr address) const;

    struct SourcePositionAndAddress {
        String file;
        size_t line;
        FlatPtr address;
    };

    Optional<SourcePositionAndAddress> get_address_from_source_position(String const& file, size_t line) const;

    String name_of_containing_function(FlatPtr address) const;
    Vector<SourcePosition> source_lines_in_scope(VariablesScope const&) const;
    Optional<VariablesScope> get_containing_function(FlatPtr address) const;

private:
    void prepare_variable_scopes();
    void prepare_lines();
    void parse_scopes_impl(Dwarf::DIE const& die);
    OwnPtr<VariableInfo> create_variable_info(Dwarf::DIE const& variable_die, PtraceRegisters const&, u32 address_offset = 0) const;
    static bool is_variable_tag_supported(Dwarf::EntryTag const& tag);
    void add_type_info_to_variable(Dwarf::DIE const& type_die, PtraceRegisters const& regs, DebugInfo::VariableInfo* parent_variable) const;

    Optional<Dwarf::LineProgram::DirectoryAndFile> get_source_path_of_inline(Dwarf::DIE const&) const;
    Optional<uint32_t> get_line_of_inline(Dwarf::DIE const&) const;

    ELF::Image const& m_elf;
    String m_source_root;
    FlatPtr m_base_address { 0 };
    Dwarf::DwarfInfo m_dwarf_info;

    Vector<VariablesScope> m_scopes;
    Vector<Dwarf::LineProgram::LineInfo> m_sorted_lines;
};

}