Coverage Report

Created: 2025-11-16 07:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibELF/Image.h
Line
Count
Source
1
/*
2
 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3
 * Copyright (c) 2022, the SerenityOS developers.
4
 *
5
 * SPDX-License-Identifier: BSD-2-Clause
6
 */
7
8
#pragma once
9
10
#include <AK/Concepts.h>
11
#include <AK/Vector.h>
12
#include <Kernel/Memory/VirtualAddress.h>
13
#include <LibELF/ELFABI.h>
14
15
#ifndef KERNEL
16
#    include <AK/ByteString.h>
17
#endif
18
19
namespace ELF {
20
21
class Image {
22
public:
23
    explicit Image(ReadonlyBytes, bool verbose_logging = true);
24
    explicit Image(u8 const*, size_t, bool verbose_logging = true);
25
26
1.92k
    ~Image() = default;
27
    void dump() const;
28
0
    bool is_valid() const { return m_valid; }
29
    bool parse();
30
31
    bool is_within_image(void const* address, size_t size) const
32
0
    {
33
0
        if (address < m_buffer)
34
0
            return false;
35
0
        if (((u8 const*)address + size) > m_buffer + m_size)
36
0
            return false;
37
0
        return true;
38
0
    }
39
40
    class Section;
41
    class RelocationSection;
42
    class Symbol;
43
    class Relocation;
44
45
    class Symbol {
46
    public:
47
        Symbol(Image const& image, unsigned index, Elf_Sym const& sym)
48
0
            : m_image(image)
49
0
            , m_sym(sym)
50
0
            , m_index(index)
51
0
        {
52
0
        }
53
54
        ~Symbol() = default;
55
56
0
        StringView name() const { return m_image.table_string(m_sym.st_name); }
57
0
        unsigned section_index() const { return m_sym.st_shndx; }
58
0
        FlatPtr value() const { return m_sym.st_value; }
59
0
        size_t size() const { return m_sym.st_size; }
60
0
        unsigned index() const { return m_index; }
61
        unsigned type() const
62
0
        {
63
0
            return ELF64_ST_TYPE(m_sym.st_info);
64
0
        }
65
0
        unsigned bind() const { return ELF64_ST_BIND(m_sym.st_info); }
66
        Section section() const
67
0
        {
68
0
            return m_image.section(section_index());
69
0
        }
70
0
        bool is_undefined() const { return section_index() == 0; }
71
        StringView raw_data() const;
72
73
    private:
74
        Image const& m_image;
75
        Elf_Sym const& m_sym;
76
        unsigned const m_index;
77
    };
78
79
    class ProgramHeader {
80
    public:
81
        ProgramHeader(Image const& image, unsigned program_header_index)
82
0
            : m_image(image)
83
0
            , m_program_header(image.program_header_internal(program_header_index))
84
0
            , m_program_header_index(program_header_index)
85
0
        {
86
0
        }
87
        ~ProgramHeader() = default;
88
89
0
        unsigned index() const { return m_program_header_index; }
90
0
        u32 type() const { return m_program_header.p_type; }
91
0
        u32 flags() const { return m_program_header.p_flags; }
92
0
        size_t offset() const { return m_program_header.p_offset; }
93
0
        VirtualAddress vaddr() const { return VirtualAddress(m_program_header.p_vaddr); }
94
0
        size_t size_in_memory() const { return m_program_header.p_memsz; }
95
0
        size_t size_in_image() const { return m_program_header.p_filesz; }
96
0
        size_t alignment() const { return m_program_header.p_align; }
97
0
        bool is_readable() const { return flags() & PF_R; }
98
0
        bool is_writable() const { return flags() & PF_W; }
99
0
        bool is_executable() const { return flags() & PF_X; }
100
0
        char const* raw_data() const { return m_image.raw_data(m_program_header.p_offset); }
101
0
        Elf_Phdr raw_header() const { return m_program_header; }
102
103
    private:
104
        Image const& m_image;
105
        Elf_Phdr const& m_program_header;
106
        unsigned m_program_header_index { 0 };
107
    };
108
109
    class Section {
110
    public:
111
        Section(Image const& image, unsigned sectionIndex)
112
0
            : m_image(image)
113
0
            , m_section_header(image.section_header(sectionIndex))
114
0
            , m_section_index(sectionIndex)
115
0
        {
116
0
        }
117
        ~Section() = default;
118
119
0
        StringView name() const { return m_image.section_header_table_string(m_section_header.sh_name); }
120
0
        u32 type() const { return m_section_header.sh_type; }
121
0
        size_t offset() const { return m_section_header.sh_offset; }
122
0
        size_t size() const { return m_section_header.sh_size; }
123
0
        size_t entry_size() const { return m_section_header.sh_entsize; }
124
0
        size_t entry_count() const { return !entry_size() ? 0 : size() / entry_size(); }
125
0
        FlatPtr address() const { return m_section_header.sh_addr; }
126
0
        char const* raw_data() const { return m_image.raw_data(m_section_header.sh_offset); }
127
0
        ReadonlyBytes bytes() const { return { raw_data(), size() }; }
128
0
        auto flags() const { return m_section_header.sh_flags; }
129
0
        bool is_writable() const { return flags() & SHF_WRITE; }
130
0
        bool is_executable() const { return flags() & PF_X; }
131
132
    protected:
133
        friend class RelocationSection;
134
        Image const& m_image;
135
        Elf_Shdr const& m_section_header;
136
        unsigned m_section_index;
137
    };
138
139
    class RelocationSection : public Section {
140
    public:
141
        explicit RelocationSection(Section const& section)
142
            : Section(section.m_image, section.m_section_index)
143
0
        {
144
0
        }
145
0
        size_t relocation_count() const { return entry_count(); }
146
        Relocation relocation(unsigned index) const;
147
148
        template<VoidFunction<Image::Relocation&> F>
149
        void for_each_relocation(F) const;
150
151
0
        bool addend_used() const { return type() == SHT_RELA; }
152
    };
153
154
    class Relocation {
155
    public:
156
        Relocation(Image const& image, Elf_Rela const& rel, bool addend_used)
157
0
            : m_image(image)
158
0
            , m_rel(rel)
159
0
            , m_addend_used(addend_used)
160
0
        {
161
0
        }
162
163
        ~Relocation() = default;
164
165
0
        size_t offset() const { return m_rel.r_offset; }
166
        unsigned type() const
167
0
        {
168
0
            return ELF64_R_TYPE(m_rel.r_info);
169
0
        }
170
0
        unsigned symbol_index() const { return ELF64_R_SYM(m_rel.r_info); }
171
        Symbol symbol() const
172
0
        {
173
0
            return m_image.symbol(symbol_index());
174
0
        }
175
176
0
        bool addend_used() const { return m_addend_used; }
177
        unsigned addend() const
178
0
        {
179
0
            VERIFY(m_addend_used);
180
0
            return m_rel.r_addend;
181
0
        }
182
183
    private:
184
        Image const& m_image;
185
        Elf_Rela const& m_rel;
186
        bool m_addend_used;
187
    };
188
189
    unsigned symbol_count() const;
190
    unsigned section_count() const;
191
    unsigned program_header_count() const;
192
193
    Symbol symbol(unsigned) const;
194
    Section section(unsigned) const;
195
    ProgramHeader program_header(unsigned) const;
196
197
    template<IteratorFunction<Image::Section> F>
198
    void for_each_section(F) const;
199
    template<VoidFunction<Section> F>
200
    void for_each_section(F) const;
201
202
    template<IteratorFunction<Section&> F>
203
    void for_each_section_of_type(unsigned, F) const;
204
    template<VoidFunction<Section&> F>
205
    void for_each_section_of_type(unsigned, F) const;
206
207
    template<IteratorFunction<Symbol> F>
208
    void for_each_symbol(F) const;
209
    template<VoidFunction<Symbol> F>
210
    void for_each_symbol(F) const;
211
212
    template<IteratorFunction<ProgramHeader> F>
213
    void for_each_program_header(F func) const;
214
    template<VoidFunction<ProgramHeader> F>
215
    void for_each_program_header(F) const;
216
217
    Optional<Section> lookup_section(StringView name) const;
218
219
0
    bool is_executable() const { return header().e_type == ET_EXEC; }
220
0
    bool is_relocatable() const { return header().e_type == ET_REL; }
221
0
    bool is_dynamic() const { return header().e_type == ET_DYN; }
222
223
0
    VirtualAddress entry() const { return VirtualAddress(header().e_entry); }
224
0
    Elf64_Quarter machine() const { return header().e_machine; }
225
0
    FlatPtr base_address() const { return (FlatPtr)m_buffer; }
226
0
    size_t size() const { return m_size; }
227
228
0
    unsigned char elf_class() const { return header().e_ident[EI_CLASS]; }
229
0
    unsigned char byte_order() const { return header().e_ident[EI_DATA]; }
230
231
    static Optional<StringView> object_file_type_to_string(Elf_Half type);
232
    static Optional<StringView> object_machine_type_to_string(Elf_Half type);
233
    static Optional<StringView> object_abi_type_to_string(Elf_Byte type);
234
235
0
    bool has_symbols() const { return symbol_count(); }
236
#ifndef KERNEL
237
    Optional<Symbol> find_demangled_function(StringView name) const;
238
    ByteString symbolicate(FlatPtr address, u32* offset = nullptr) const;
239
#endif
240
    Optional<Image::Symbol> find_symbol(FlatPtr address, u32* offset = nullptr) const;
241
242
private:
243
    char const* raw_data(unsigned offset) const;
244
    Elf_Ehdr const& header() const;
245
    Elf_Shdr const& section_header(unsigned) const;
246
    Elf_Phdr const& program_header_internal(unsigned) const;
247
    StringView table_string(unsigned offset) const;
248
    StringView section_header_table_string(unsigned offset) const;
249
    StringView section_index_to_string(unsigned index) const;
250
    StringView table_string(unsigned table_index, unsigned offset) const;
251
252
    u8 const* m_buffer { nullptr };
253
    size_t m_size { 0 };
254
    bool m_verbose_logging { true };
255
    bool m_valid { false };
256
    unsigned m_symbol_table_section_index { 0 };
257
    unsigned m_string_table_section_index { 0 };
258
259
#ifndef KERNEL
260
    struct SortedSymbol {
261
        FlatPtr address;
262
        StringView name;
263
        ByteString demangled_name;
264
        Optional<Image::Symbol> symbol;
265
    };
266
267
    void sort_symbols() const;
268
    SortedSymbol* find_sorted_symbol(FlatPtr) const;
269
270
    mutable Vector<SortedSymbol> m_sorted_symbols;
271
#endif
272
};
273
274
template<IteratorFunction<Image::Section> F>
275
inline void Image::for_each_section(F func) const
276
{
277
    auto section_count = this->section_count();
278
    for (unsigned i = 0; i < section_count; ++i) {
279
        if (func(section(i)) == IterationDecision::Break)
280
            break;
281
    }
282
}
283
284
template<VoidFunction<Image::Section> F>
285
inline void Image::for_each_section(F func) const
286
{
287
    for_each_section([&](auto section) {
288
        func(move(section));
289
        return IterationDecision::Continue;
290
    });
291
}
292
293
template<IteratorFunction<Image::Section&> F>
294
inline void Image::for_each_section_of_type(unsigned type, F func) const
295
{
296
    auto section_count = this->section_count();
297
    for (unsigned i = 0; i < section_count; ++i) {
298
        auto section = this->section(i);
299
        if (section.type() == type) {
300
            if (func(section) == IterationDecision::Break)
301
                break;
302
        }
303
    }
304
}
305
306
template<VoidFunction<Image::Section&> F>
307
inline void Image::for_each_section_of_type(unsigned type, F func) const
308
{
309
    for_each_section_of_type(type, [&](auto& section) {
310
        func(section);
311
        return IterationDecision::Continue;
312
    });
313
}
314
315
template<VoidFunction<Image::Relocation&> F>
316
inline void Image::RelocationSection::for_each_relocation(F func) const
317
{
318
    auto relocation_count = this->relocation_count();
319
    for (unsigned i = 0; i < relocation_count; ++i) {
320
        func(relocation(i));
321
    }
322
}
323
324
template<IteratorFunction<Image::Symbol> F>
325
inline void Image::for_each_symbol(F func) const
326
0
{
327
0
    auto symbol_count = this->symbol_count();
328
0
    for (unsigned i = 0; i < symbol_count; ++i) {
329
0
        if (func(symbol(i)) == IterationDecision::Break)
330
0
            break;
331
0
    }
332
0
}
Unexecuted instantiation: Image.cpp:_ZNK3ELF5Image15for_each_symbolITkN2AK8Concepts16IteratorFunctionINS0_6SymbolEEEZNKS0_23find_demangled_functionENS2_10StringViewEE3$_0EEvT_
Unexecuted instantiation: Image.cpp:_ZNK3ELF5Image15for_each_symbolITkN2AK8Concepts16IteratorFunctionINS0_6SymbolEEEZNKS0_15for_each_symbolITkNS3_12VoidFunctionIS5_EEZNKS0_12sort_symbolsEvE3$_0EEvT_EUlS9_E_EEvS9_
333
334
template<VoidFunction<Image::Symbol> F>
335
inline void Image::for_each_symbol(F func) const
336
0
{
337
0
    for_each_symbol([&](auto symbol) {
338
0
        func(move(symbol));
339
0
        return IterationDecision::Continue;
340
0
    });
341
0
}
342
343
template<IteratorFunction<Image::ProgramHeader> F>
344
inline void Image::for_each_program_header(F func) const
345
{
346
    auto program_header_count = this->program_header_count();
347
    for (unsigned i = 0; i < program_header_count; ++i) {
348
        if (func(program_header(i)) == IterationDecision::Break)
349
            break;
350
    }
351
}
352
353
template<VoidFunction<Image::ProgramHeader> F>
354
inline void Image::for_each_program_header(F func) const
355
{
356
    for_each_program_header([&](auto header) {
357
        func(move(header));
358
        return IterationDecision::Continue;
359
    });
360
}
361
362
} // end namespace ELF