summaryrefslogtreecommitdiff
path: root/ELFLoader/ELFImage.h
blob: ff0715ee21d1b511c855507b114687e1a7cc89c8 (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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#pragma once

#ifndef SERENITY
#include <AK/MappedFile.h>
#endif

#include <AK/OwnPtr.h>
#include <AK/HashMap.h>
#include <AK/String.h>
#include "elf.h"

class ELFImage {
public:
#ifdef SERENITY
    explicit ELFImage(ByteBuffer&&);
#else
    explicit ELFImage(MappedFile&&);
#endif
    ~ELFImage();
    void dump();
    bool isValid() const { return m_isValid; }
    bool parse();

    class Section;
    class RelocationSection;
    class Symbol;
    class Relocation;

    class Symbol {
    public:
        Symbol(const ELFImage& image, unsigned index, const Elf32_Sym& sym)
            : m_image(image)
            , m_sym(sym)
            , m_index(index)
        {
        }

        ~Symbol() { }

        const char* name() const { return m_image.tableString(m_sym.st_name); }
        unsigned sectionIndex() const { return m_sym.st_shndx; }
        unsigned value() const { return m_sym.st_value; }
        unsigned size() const { return m_sym.st_size; }
        unsigned index() const { return m_index; }
        unsigned type() const { return ELF32_ST_TYPE(m_sym.st_info); }
        const Section section() const { return m_image.section(sectionIndex()); }

    private:
        const ELFImage& m_image;
        const Elf32_Sym& m_sym;
        const unsigned m_index;
    };

    class Section {
    public:
        Section(const ELFImage& image, unsigned sectionIndex)
            : m_image(image)
            , m_sectionHeader(image.sectionHeader(sectionIndex))
            , m_sectionIndex(sectionIndex)
        {
        }
        ~Section() { }

        const char* name() const { return m_image.sectionHeaderTableString(m_sectionHeader.sh_name); }
        unsigned type() const { return m_sectionHeader.sh_type; }
        unsigned offset() const { return m_sectionHeader.sh_offset; }
        unsigned size() const { return m_sectionHeader.sh_size; }
        unsigned entrySize() const { return m_sectionHeader.sh_entsize; }
        unsigned entryCount() const { return size() / entrySize(); }
        const char* rawData() const { return m_image.rawData(m_sectionHeader.sh_offset); }
        bool isUndefined() const { return m_sectionIndex == SHN_UNDEF; }
        const RelocationSection relocations() const;

    protected:
        friend class RelocationSection;
        const ELFImage& m_image;
        const Elf32_Shdr& m_sectionHeader;
        unsigned m_sectionIndex;
    };

    class RelocationSection : public Section {
    public:
        RelocationSection(const Section& section)
            : Section(section.m_image, section.m_sectionIndex)
        {
        }
        unsigned relocationCount() const { return entryCount(); }
        const Relocation relocation(unsigned index) const;
        template<typename F> void forEachRelocation(F) const;
    };

    class Relocation {
    public:
        Relocation(const ELFImage& image, const Elf32_Rel& rel)
            : m_image(image)
            , m_rel(rel)
        {
        }

        ~Relocation() { }

        unsigned offset() const { return m_rel.r_offset; }
        unsigned type() const { return ELF32_R_TYPE(m_rel.r_info); }
        unsigned symbolIndex() const { return ELF32_R_SYM(m_rel.r_info); }
        const Symbol symbol() const { return m_image.symbol(symbolIndex()); }

    private:
        const ELFImage& m_image;
        const Elf32_Rel& m_rel;
    };

    unsigned symbolCount() const;
    unsigned sectionCount() const;

    const Symbol symbol(unsigned) const;
    const Section section(unsigned) const;

    template<typename F> void forEachSectionOfType(unsigned, F) const;
    template<typename F> void forEachSymbol(F) const;

    // NOTE: Returns section(0) if section with name is not found.
    // FIXME: I don't love this API.
    const Section lookupSection(const char* name) const;

private:
    bool parseHeader();
    const char* rawData(unsigned offset) const;
    const Elf32_Ehdr& header() const;
    const Elf32_Shdr& sectionHeader(unsigned) const;
    const char* tableString(unsigned offset) const;
    const char* sectionHeaderTableString(unsigned offset) const;
    const char* sectionIndexToString(unsigned index);

#ifdef SERENITY
    ByteBuffer m_buffer;
#else
    MappedFile m_file;
#endif
    HashMap<String, unsigned> m_sections;
    bool m_isValid { false };
    unsigned m_symbolTableSectionIndex { 0 };
    unsigned m_stringTableSectionIndex { 0 };
};

template<typename F>
inline void ELFImage::forEachSectionOfType(unsigned type, F func) const
{
    for (unsigned i = 0; i < sectionCount(); ++i) {
        auto& section = this->section(i);
        if (section.type() == type) {
            if (!func(section))
                break;
        }
    }
}

template<typename F>
inline void ELFImage::RelocationSection::forEachRelocation(F func) const
{
    for (unsigned i = 0; i < relocationCount(); ++i) {
        if (!func(relocation(i)))
            break;
    }
}

template<typename F>
inline void ELFImage::forEachSymbol(F func) const
{
    for (unsigned i = 0; i < symbolCount(); ++i) {
        if (!func(symbol(i)))
            break;
    }
}