summaryrefslogtreecommitdiff
path: root/src/elf_image.h
blob: 20627d399542c21aacf7a8b12c00af981baa3316 (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
#pragma once

/* SPDX-License-Identifier: Unlicense
 */

#include "elf.h"
#include "data_buffer.h"

#include <cstdlib>

namespace ELF {

struct ProgramHeader32Table {
    const ProgramHeader32 *headers{};
    size_t size{};
    static ProgramHeader32Table FromView(const DataView &, DataEncoding);
};

struct Segment {
    Segment *next{};
    const DataView view{};
};

class Image {
    const DataBuffer _data;
    char *const _error;
    const Header32 _h;
    const ProgramHeader32Table _pht;
    const SectionHeader32 _shstrtab, _symtab, _strtab;
public:
    explicit Image(DataBuffer&&);
    ~Image();
    constexpr bool IsValid() const { return _error == nullptr; }
    constexpr const DataBuffer &Data() const { return _data; };
    constexpr const DataView ProgramView() const
    {
        if (!IsValid()) {
            return DataView{};
        }
        for (size_t i = 0; i < _pht.size; i++) {
            const auto ph = _pht.headers[i];
            const bool is_code = (ph.flags & (kPHFlagX | kPHFlagW | kPHFlagR)) ==
                (kPHFlagX | kPHFlagR);
            const bool is_load = ParsePHType(ph.type) == PHType::kLoad;
            const bool contains_entry = _h.entry >= ph.vaddr && _h.entry < ph.vaddr + ph.memsz;
            if (is_load && is_code && ph.vaddr == 0 && contains_entry)
            {
                return _data.View(ph.offset, ph.filesz);
            }
        }
        return DataView{};
    };
    constexpr const char *Error() const { return _error; }
    ELF::SectionHeader32 GetSectionHeaderByName(const char *name) const;
    constexpr const ELF::SectionHeader32 GetSectionHeader(uint32_t index) const
    {
        if (index > _h.shnum) {
            return SectionHeader32{};
        }
        const size_t offset = _h.shoff + kSectionHeaderSize * index;
        if (offset + kSectionHeaderSize > _data.buffer_size) {
            return SectionHeader32{};
        }
        return SectionHeader32::FromBytes(
                _data.buffer + offset, _h.ident.data_encoding);
    }
    uint32_t GetSectionHeaderIndexByName(const char *name) const;
    constexpr ELF::Symbol32 GetSymbolByIndex(uint32_t index) const
    {
        if (!IsValid()) {
            return Symbol32{};
        }
        if (_symtab.entsize == 0 || index >= _symtab.size / _symtab.entsize) {
            return Symbol32{};
        }
        auto symbol = Symbol32::FromBytes(
                _data.buffer + _symtab.offset + _symtab.entsize * index,
                _h.ident.data_encoding);
        if (symbol.namendx < _strtab.size && _data.buffer[_strtab.offset + _strtab.size] == '\0') {
            symbol.name = reinterpret_cast<const char *>(
                    _data.buffer + _strtab.offset + symbol.namendx);
        }
        return symbol;
    }
};

}