Coverage Report

Created: 2025-09-05 06:52

/src/serenity/Userland/Libraries/LibELF/Image.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
3
 * Copyright (c) 2022, the SerenityOS developers.
4
 *
5
 * SPDX-License-Identifier: BSD-2-Clause
6
 */
7
8
#include <AK/BinarySearch.h>
9
#include <AK/Debug.h>
10
#include <AK/Demangle.h>
11
#include <AK/QuickSort.h>
12
#include <AK/StringBuilder.h>
13
#include <AK/StringView.h>
14
#include <Kernel/API/serenity_limits.h>
15
#include <LibELF/Image.h>
16
#include <LibELF/Validation.h>
17
18
#ifdef KERNEL
19
#    include <Kernel/Library/StdLib.h>
20
#else
21
#    include <string.h>
22
#endif
23
24
namespace ELF {
25
26
Image::Image(ReadonlyBytes bytes, bool verbose_logging)
27
1.91k
    : m_buffer(bytes.data())
28
1.91k
    , m_size(bytes.size())
29
1.91k
    , m_verbose_logging(verbose_logging)
30
1.91k
{
31
1.91k
    parse();
32
1.91k
}
33
34
Image::Image(u8 const* buffer, size_t size, bool verbose_logging)
35
1.91k
    : Image(ReadonlyBytes { buffer, size }, verbose_logging)
36
1.91k
{
37
1.91k
}
38
39
StringView Image::section_index_to_string(unsigned index) const
40
0
{
41
0
    VERIFY(m_valid);
42
0
    if (index == SHN_UNDEF)
43
0
        return "Undefined"sv;
44
0
    if (index >= SHN_LORESERVE)
45
0
        return "Reserved"sv;
46
0
    return section(index).name();
47
0
}
48
49
unsigned Image::symbol_count() const
50
0
{
51
0
    VERIFY(m_valid);
52
0
    if (!section_count())
53
0
        return 0;
54
0
    return section(m_symbol_table_section_index).entry_count();
55
0
}
56
57
void Image::dump() const
58
0
{
59
#if ELF_IMAGE_DEBUG
60
    dbgln("ELF::Image({:p}) {{", this);
61
    dbgln("    is_valid: {}", is_valid());
62
63
    if (!is_valid()) {
64
        dbgln("}}");
65
        return;
66
    }
67
68
    dbgln("    type:    {}", ELF::Image::object_file_type_to_string(header().e_type).value_or("(?)"sv));
69
    dbgln("    machine: {}", header().e_machine);
70
    dbgln("    entry:   {:x}", header().e_entry);
71
    dbgln("    shoff:   {}", header().e_shoff);
72
    dbgln("    shnum:   {}", header().e_shnum);
73
    dbgln("    phoff:   {}", header().e_phoff);
74
    dbgln("    phnum:   {}", header().e_phnum);
75
    dbgln(" shstrndx:   {}", header().e_shstrndx);
76
77
    for_each_program_header([&](ProgramHeader const& program_header) {
78
        dbgln("    Program Header {}: {{", program_header.index());
79
        dbgln("        type: {:x}", program_header.type());
80
        dbgln("      offset: {:x}", program_header.offset());
81
        dbgln("       flags: {:x}", program_header.flags());
82
        dbgln("    }}");
83
    });
84
85
    for (unsigned i = 0; i < header().e_shnum; ++i) {
86
        auto const& section = this->section(i);
87
        dbgln("    Section {}: {{", i);
88
        dbgln("        name: {}", section.name());
89
        dbgln("        type: {:x}", section.type());
90
        dbgln("      offset: {:x}", section.offset());
91
        dbgln("        size: {}", section.size());
92
        dbgln("        ");
93
        dbgln("    }}");
94
    }
95
96
    dbgln("Symbol count: {} (table is {})", symbol_count(), m_symbol_table_section_index);
97
    for (unsigned i = 1; i < symbol_count(); ++i) {
98
        auto const& sym = symbol(i);
99
        dbgln("Symbol @{}:", i);
100
        dbgln("    Name: {}", sym.name());
101
        dbgln("    In section: {}", section_index_to_string(sym.section_index()));
102
        dbgln("    Value: {}", sym.value());
103
        dbgln("    Size: {}", sym.size());
104
    }
105
106
    dbgln("}}");
107
#endif
108
0
}
109
110
unsigned Image::section_count() const
111
145k
{
112
145k
    VERIFY(m_valid);
113
145k
    return header().e_shnum;
114
145k
}
115
116
unsigned Image::program_header_count() const
117
0
{
118
0
    VERIFY(m_valid);
119
0
    return header().e_phnum;
120
0
}
121
122
bool Image::parse()
123
1.91k
{
124
1.91k
    if (m_size < sizeof(Elf_Ehdr) || !validate_elf_header(header(), m_size, m_verbose_logging)) {
125
668
        if (m_verbose_logging)
126
0
            dbgln("ELF::Image::parse(): ELF Header not valid");
127
668
        m_valid = false;
128
668
        return false;
129
668
    }
130
131
1.24k
    [[maybe_unused]] Optional<Elf_Phdr> interpreter_path_program_header {};
132
1.24k
    if (!validate_program_headers(header(), m_size, { m_buffer, m_size }, interpreter_path_program_header, nullptr, m_verbose_logging)) {
133
622
        if (m_verbose_logging)
134
0
            dbgln("ELF::Image::parse(): ELF Program Headers not valid");
135
622
        m_valid = false;
136
622
        return false;
137
622
    }
138
139
624
    m_valid = true;
140
141
    // First locate the string tables.
142
145k
    for (unsigned i = 0; i < section_count(); ++i) {
143
145k
        auto& sh = section_header(i);
144
145k
        if (sh.sh_type == SHT_SYMTAB) {
145
74
            if (m_symbol_table_section_index && m_symbol_table_section_index != i) {
146
22
                m_valid = false;
147
22
                return false;
148
22
            }
149
52
            m_symbol_table_section_index = i;
150
52
        }
151
145k
        if (sh.sh_type == SHT_STRTAB && i != header().e_shstrndx) {
152
5.43k
            if (section_header_table_string(sh.sh_name) == ELF_STRTAB)
153
194
                m_string_table_section_index = i;
154
5.43k
        }
155
145k
    }
156
157
602
    return m_valid;
158
624
}
159
160
StringView Image::table_string(unsigned table_index, unsigned offset) const
161
5.43k
{
162
5.43k
    VERIFY(m_valid);
163
5.43k
    auto& sh = section_header(table_index);
164
5.43k
    if (sh.sh_type != SHT_STRTAB)
165
854
        return {};
166
4.58k
    size_t computed_offset = sh.sh_offset + offset;
167
4.58k
    if (computed_offset >= m_size) {
168
622
        if (m_verbose_logging)
169
0
            dbgln("SHENANIGANS! Image::table_string() computed offset outside image.");
170
622
        return {};
171
622
    }
172
3.96k
    size_t max_length = min(m_size - computed_offset, (size_t)SERENITY_PAGE_SIZE);
173
3.96k
    size_t length = strnlen(raw_data(sh.sh_offset + offset), max_length);
174
3.96k
    return { raw_data(sh.sh_offset + offset), length };
175
4.58k
}
176
177
StringView Image::section_header_table_string(unsigned offset) const
178
5.43k
{
179
5.43k
    VERIFY(m_valid);
180
5.43k
    return table_string(header().e_shstrndx, offset);
181
5.43k
}
182
183
StringView Image::table_string(unsigned offset) const
184
0
{
185
0
    VERIFY(m_valid);
186
0
    return table_string(m_string_table_section_index, offset);
187
0
}
188
189
char const* Image::raw_data(unsigned offset) const
190
771k
{
191
771k
    VERIFY(offset < m_size); // Callers must check indices into raw_data()'s result are also in bounds.
192
771k
    return reinterpret_cast<char const*>(m_buffer) + offset;
193
771k
}
194
195
Elf_Ehdr const& Image::header() const
196
612k
{
197
612k
    VERIFY(m_size >= sizeof(Elf_Ehdr));
198
612k
    return *reinterpret_cast<Elf_Ehdr const*>(raw_data(0));
199
612k
}
200
201
Elf_Phdr const& Image::program_header_internal(unsigned index) const
202
0
{
203
0
    VERIFY(m_valid);
204
0
    VERIFY(index < header().e_phnum);
205
0
    return *reinterpret_cast<Elf_Phdr const*>(raw_data(header().e_phoff + (index * sizeof(Elf_Phdr))));
206
0
}
207
208
Elf_Shdr const& Image::section_header(unsigned index) const
209
150k
{
210
150k
    VERIFY(m_valid);
211
150k
    VERIFY(index < header().e_shnum);
212
150k
    return *reinterpret_cast<Elf_Shdr const*>(raw_data(header().e_shoff + (index * header().e_shentsize)));
213
150k
}
214
215
Image::Symbol Image::symbol(unsigned index) const
216
0
{
217
0
    VERIFY(m_valid);
218
0
    VERIFY(index < symbol_count());
219
0
    auto* raw_syms = reinterpret_cast<Elf_Sym const*>(raw_data(section(m_symbol_table_section_index).offset()));
220
0
    return Symbol(*this, index, raw_syms[index]);
221
0
}
222
223
Image::Section Image::section(unsigned index) const
224
0
{
225
0
    VERIFY(m_valid);
226
0
    VERIFY(index < section_count());
227
0
    return Section(*this, index);
228
0
}
229
230
Image::ProgramHeader Image::program_header(unsigned index) const
231
0
{
232
0
    VERIFY(m_valid);
233
0
    VERIFY(index < program_header_count());
234
0
    return ProgramHeader(*this, index);
235
0
}
236
237
Image::Relocation Image::RelocationSection::relocation(unsigned index) const
238
0
{
239
0
    VERIFY(index < relocation_count());
240
0
    unsigned offset_in_section = index * entry_size();
241
0
    auto relocation_address = bit_cast<Elf_Rela*>(m_image.raw_data(offset() + offset_in_section));
242
0
    return Relocation(m_image, *relocation_address, addend_used());
243
0
}
244
245
Optional<Image::Section> Image::lookup_section(StringView name) const
246
0
{
247
0
    VERIFY(m_valid);
248
0
    for (unsigned i = 0; i < section_count(); ++i) {
249
0
        auto section = this->section(i);
250
0
        if (section.name() == name)
251
0
            return section;
252
0
    }
253
0
    return {};
254
0
}
255
256
Optional<StringView> Image::object_file_type_to_string(Elf_Half type)
257
0
{
258
0
    switch (type) {
259
0
    case ET_NONE:
260
0
        return "None"sv;
261
0
    case ET_REL:
262
0
        return "Relocatable"sv;
263
0
    case ET_EXEC:
264
0
        return "Executable"sv;
265
0
    case ET_DYN:
266
0
        return "Shared object"sv;
267
0
    case ET_CORE:
268
0
        return "Core"sv;
269
0
    default:
270
0
        return {};
271
0
    }
272
0
}
273
274
Optional<StringView> Image::object_machine_type_to_string(Elf_Half type)
275
0
{
276
0
    switch (type) {
277
0
    case ET_NONE:
278
0
        return "None"sv;
279
0
    case EM_M32:
280
0
        return "AT&T WE 32100"sv;
281
0
    case EM_SPARC:
282
0
        return "SPARC"sv;
283
0
    case EM_386:
284
0
        return "Intel 80386"sv;
285
0
    case EM_68K:
286
0
        return "Motorola 68000"sv;
287
0
    case EM_88K:
288
0
        return "Motorola 88000"sv;
289
0
    case EM_486:
290
0
        return "Intel 80486"sv;
291
0
    case EM_860:
292
0
        return "Intel 80860"sv;
293
0
    case EM_MIPS:
294
0
        return "MIPS R3000 Big-Endian only"sv;
295
0
    case EM_X86_64:
296
0
        return "x86_64"sv;
297
0
    default:
298
0
        return {};
299
0
    }
300
0
}
301
302
Optional<StringView> Image::object_abi_type_to_string(Elf_Byte type)
303
0
{
304
0
    switch (type) {
305
0
    case ELFOSABI_SYSV:
306
0
        return "SYSV"sv;
307
0
    case ELFOSABI_HPUX:
308
0
        return "HP-UX"sv;
309
0
    case ELFOSABI_NETBSD:
310
0
        return "NetBSD"sv;
311
0
    case ELFOSABI_LINUX:
312
0
        return "Linux"sv;
313
0
    case ELFOSABI_HURD:
314
0
        return "GNU Hurd"sv;
315
0
    case ELFOSABI_86OPEN:
316
0
        return "86Open"sv;
317
0
    case ELFOSABI_SOLARIS:
318
0
        return "Solaris"sv;
319
0
    case ELFOSABI_MONTEREY:
320
0
        return "AIX"sv;
321
0
    case ELFOSABI_IRIX:
322
0
        return "IRIX"sv;
323
0
    case ELFOSABI_FREEBSD:
324
0
        return "FreeBSD"sv;
325
0
    case ELFOSABI_TRU64:
326
0
        return "Tru64"sv;
327
0
    case ELFOSABI_MODESTO:
328
0
        return "Novell Modesto"sv;
329
0
    case ELFOSABI_OPENBSD:
330
0
        return "OpenBSD"sv;
331
0
    case ELFOSABI_ARM:
332
0
        return "ARM"sv;
333
0
    case ELFOSABI_STANDALONE:
334
0
        return "Standalone"sv;
335
0
    default:
336
0
        return {};
337
0
    }
338
0
}
339
340
StringView Image::Symbol::raw_data() const
341
0
{
342
0
    auto section = this->section();
343
0
    return { section.raw_data() + (value() - section.address()), size() };
344
0
}
345
346
#ifndef KERNEL
347
Optional<Image::Symbol> Image::find_demangled_function(StringView name) const
348
0
{
349
0
    Optional<Image::Symbol> found;
350
0
    for_each_symbol([&](Image::Symbol const& symbol) {
351
0
        if (symbol.type() != STT_FUNC && symbol.type() != STT_GNU_IFUNC)
352
0
            return IterationDecision::Continue;
353
0
        if (symbol.is_undefined())
354
0
            return IterationDecision::Continue;
355
0
        auto demangled = demangle(symbol.name());
356
0
        auto index_of_paren = demangled.find('(');
357
0
        if (index_of_paren.has_value()) {
358
0
            demangled = demangled.substring(0, index_of_paren.value());
359
0
        }
360
0
        if (demangled != name)
361
0
            return IterationDecision::Continue;
362
0
        found = symbol;
363
0
        return IterationDecision::Break;
364
0
    });
365
0
    return found;
366
0
}
367
368
Image::SortedSymbol* Image::find_sorted_symbol(FlatPtr address) const
369
0
{
370
0
    if (symbol_count() == 0)
371
0
        return nullptr;
372
373
0
    if (m_sorted_symbols.is_empty())
374
0
        sort_symbols();
375
376
0
    auto maybe_index = upper_bound(m_sorted_symbols, address, [address](auto, auto const& candidate) {
377
0
        if (address >= candidate.address)
378
0
            return 1;
379
0
        return -1;
380
0
    });
381
382
0
    if (!maybe_index.has_value())
383
0
        return &m_sorted_symbols.last();
384
385
0
    if (maybe_index.value() == 0)
386
0
        return nullptr;
387
388
0
    return &m_sorted_symbols[maybe_index.value() - 1];
389
0
}
390
391
Optional<Image::Symbol> Image::find_symbol(FlatPtr address, u32* out_offset) const
392
0
{
393
0
    auto symbol_count = this->symbol_count();
394
0
    if (!symbol_count)
395
0
        return {};
396
397
0
    auto* symbol = find_sorted_symbol(address);
398
0
    if (!symbol)
399
0
        return {};
400
0
    if (out_offset)
401
0
        *out_offset = address - symbol->address;
402
0
    return symbol->symbol;
403
0
}
404
405
NEVER_INLINE void Image::sort_symbols() const
406
0
{
407
0
    m_sorted_symbols.ensure_capacity(symbol_count());
408
0
    bool const is_aarch64_or_riscv = header().e_machine == EM_AARCH64 || header().e_machine == EM_RISCV;
409
0
    for_each_symbol([this, is_aarch64_or_riscv](auto const& symbol) {
410
        // The AArch64 and RISC-V ABIs mark the boundaries of literal pools in a function with $x/$d.
411
        // https://github.com/ARM-software/abi-aa/blob/2023q1-release/aaelf64/aaelf64.rst#mapping-symbols
412
        // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#mapping-symbol
413
        // Skip them so we don't accidentally print these instead of function names.
414
0
        if (is_aarch64_or_riscv && (symbol.name().starts_with("$x"sv) || symbol.name().starts_with("$d"sv)))
415
0
            return;
416
        // STT_SECTION has the same address as the first function in the section, but shows up as the empty string.
417
0
        if (symbol.type() == STT_SECTION)
418
0
            return;
419
0
        m_sorted_symbols.append({ symbol.value(), symbol.name(), {}, symbol });
420
0
    });
421
0
    quick_sort(m_sorted_symbols, [](auto& a, auto& b) {
422
0
        return a.address < b.address;
423
0
    });
424
0
}
425
426
ByteString Image::symbolicate(FlatPtr address, u32* out_offset) const
427
0
{
428
0
    auto symbol_count = this->symbol_count();
429
0
    if (!symbol_count) {
430
0
        if (out_offset)
431
0
            *out_offset = 0;
432
0
        return "??";
433
0
    }
434
435
0
    auto* symbol = find_sorted_symbol(address);
436
0
    if (!symbol) {
437
0
        if (out_offset)
438
0
            *out_offset = 0;
439
0
        return "??";
440
0
    }
441
442
0
    auto& demangled_name = symbol->demangled_name;
443
0
    if (demangled_name.is_empty())
444
0
        demangled_name = demangle(symbol->name);
445
446
0
    if (out_offset) {
447
0
        *out_offset = address - symbol->address;
448
0
        return demangled_name;
449
0
    }
450
0
    return ByteString::formatted("{} +{:#x}", demangled_name, address - symbol->address);
451
0
}
452
#endif
453
454
} // end namespace ELF