1
/**
2
 * Extract symbols from an ELF object file.
3
 *
4
 * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
5
 * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
6
 * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7
 * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/scanelf.d, _scanelf.d)
8
 * Documentation:  https://dlang.org/phobos/dmd_scanelf.html
9
 * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/scanelf.d
10
 */
11

12
module dmd.scanelf;
13

14
import core.stdc.string;
15
import core.stdc.stdint;
16
import core.checkedint;
17

18
import dmd.globals;
19
import dmd.errors;
20

21
enum LOG = false;
22

23
/*****************************************
24
 * Reads an object module from base[] and passes the names
25
 * of any exported symbols to (*pAddSymbol)().
26
 * Params:
27
 *      pAddSymbol =  function to pass the names to
28
 *      base =        array of contents of object module
29
 *      module_name = name of the object module (used for error messages)
30
 *      loc =         location to use for error printing
31
 */
32
void scanElfObjModule(void delegate(const(char)[] name, int pickAny) pAddSymbol,
33
        const(ubyte)[] base, const(char)* module_name, Loc loc)
34
{
35
    static if (LOG)
36
    {
37
        printf("scanElfObjModule(%s)\n", module_name);
38
    }
39

40
    void corrupt(int reason)
41
    {
42 0
        error(loc, "corrupt ELF object module `%s` %d", module_name, reason);
43
    }
44

45 3
    if (base.length < Elf32_Ehdr.sizeof)
46 0
        return corrupt(__LINE__); // must be at least large enough for ELF32
47
    static immutable ubyte[4] elf = [0x7F, 'E', 'L', 'F']; // ELF file signature
48 3
    if (base[0 .. elf.length] != elf[])
49 0
        return corrupt(__LINE__);
50

51 3
    if (base[EI_VERSION] != EV_CURRENT)
52
    {
53 0
        return error(loc, "ELF object module `%s` has EI_VERSION = %d, should be %d",
54
            module_name, base[EI_VERSION], EV_CURRENT);
55
    }
56 3
    if (base[EI_DATA] != ELFDATA2LSB)
57
    {
58 0
        return error(loc, "ELF object module `%s` is byte swapped and unsupported", module_name);
59
    }
60 3
    if (base[EI_CLASS] != ELFCLASS32 && base[EI_CLASS] != ELFCLASS64)
61
    {
62 0
        return error(loc, "ELF object module `%s` is unrecognized class %d", module_name, base[EI_CLASS]);
63
    }
64

65
    void scanELF(uint model)()
66
    {
67
        static if (model == 32)
68
        {
69
            alias ElfXX_Ehdr = Elf32_Ehdr;
70
            alias ElfXX_Shdr = Elf32_Shdr;
71
            alias ElfXX_Sym = Elf32_Sym;
72
        }
73
        else
74
        {
75
            static assert(model == 64);
76
            alias ElfXX_Ehdr = Elf64_Ehdr;
77
            alias ElfXX_Shdr = Elf64_Shdr;
78
            alias ElfXX_Sym = Elf64_Sym;
79
        }
80

81 3
        if (base.length < ElfXX_Ehdr.sizeof)
82 0
            return corrupt(__LINE__);
83

84 3
        const eh = cast(const(ElfXX_Ehdr)*) base.ptr;
85 3
        if (eh.e_type != ET_REL)
86 0
            return error(loc, "ELF object module `%s` is not relocatable", module_name);
87 3
        if (eh.e_version != EV_CURRENT)
88 0
            return corrupt(__LINE__);
89

90 3
        bool overflow;
91 3
        const end = addu(eh.e_shoff, mulu(eh.e_shentsize, eh.e_shnum, overflow), overflow);
92 3
        if (overflow || end > base.length)
93 0
            return corrupt(__LINE__);
94

95
        /* For each Section
96
         */
97 3
        const sections = (cast(const(ElfXX_Shdr)*)(base.ptr + eh.e_shoff))[0 .. eh.e_shnum];
98 3
        foreach (ref const section; sections)
99
        {
100 3
            if (section.sh_type != SHT_SYMTAB)
101 3
                continue;
102

103
            bool checkShdrXX(const ref ElfXX_Shdr shdr)
104
            {
105 3
                bool overflow;
106 3
                return addu(shdr.sh_offset, shdr.sh_size, overflow) > base.length || overflow;
107
            }
108

109 3
            if (checkShdrXX(section))
110 0
                return corrupt(__LINE__);
111

112
            /* sh_link gives the particular string table section
113
             * used for the symbol names.
114
             */
115 3
            if (section.sh_link >= eh.e_shnum)
116 0
                return corrupt(__LINE__);
117

118 3
            const string_section = &sections[section.sh_link];
119 3
            if (string_section.sh_type != SHT_STRTAB)
120 0
                return corrupt(__LINE__);
121

122 3
            if (checkShdrXX(*string_section))
123 0
                return corrupt(__LINE__);
124

125 3
            const string_tab = (cast(const(char)[])base)
126
                [cast(size_t)string_section.sh_offset ..
127
                 cast(size_t)(string_section.sh_offset + string_section.sh_size)];
128

129
            /* Get the array of symbols this section refers to
130
             */
131 3
            const symbols = (cast(ElfXX_Sym*)(base.ptr + cast(size_t)section.sh_offset))
132
                [0 .. cast(size_t)(section.sh_size / ElfXX_Sym.sizeof)];
133

134 3
            foreach (ref const sym; symbols)
135
            {
136 3
                const stb = sym.st_info >> 4;
137 3
                if (stb != STB_GLOBAL && stb != STB_WEAK || sym.st_shndx == SHN_UNDEF)
138 3
                    continue; // it's extern
139

140 3
                if (sym.st_name >= string_tab.length)
141 0
                    return corrupt(__LINE__);
142

143 3
                const name = &string_tab[sym.st_name];
144
                //printf("sym st_name = x%x\n", sym.st_name);
145 3
                const pend = cast(const(char*)) memchr(name, 0, string_tab.length - sym.st_name);
146 3
                if (!pend)       // if didn't find terminating 0 inside the string section
147 0
                    return corrupt(__LINE__);
148 3
                pAddSymbol(name[0 .. pend - name], 1);
149
            }
150
        }
151
    }
152

153 3
    if (base[EI_CLASS] == ELFCLASS32)
154
    {
155 1
        scanELF!32;
156
    }
157
    else
158
    {
159 2
        assert(base[EI_CLASS] == ELFCLASS64);
160 2
        scanELF!64;
161
    }
162
}
163

164
alias Elf32_Half = uint16_t;
165
alias Elf64_Half = uint16_t;
166

167
alias Elf32_Word  = uint32_t;
168
alias Elf32_Sword = int32_t;
169
alias Elf64_Word  = uint32_t;
170
alias Elf64_Sword = int32_t;
171

172
alias Elf32_Xword  = uint64_t;
173
alias Elf32_Sxword = int64_t;
174
alias Elf64_Xword  = uint64_t;
175
alias Elf64_Sxword = int64_t;
176

177
alias Elf32_Addr = uint32_t;
178
alias Elf64_Addr = uint64_t;
179

180
alias Elf32_Off = uint32_t;
181
alias Elf64_Off = uint64_t;
182

183
alias Elf32_Section = uint16_t;
184
alias Elf64_Section = uint16_t;
185

186
alias Elf32_Versym = Elf32_Half;
187
alias Elf64_Versym = Elf64_Half;
188

189
struct Elf32_Ehdr
190
{
191
    char[EI_NIDENT] e_ident = 0;
192
    Elf32_Half    e_type;
193
    Elf32_Half    e_machine;
194
    Elf32_Word    e_version;
195
    Elf32_Addr    e_entry;
196
    Elf32_Off     e_phoff;
197
    Elf32_Off     e_shoff;
198
    Elf32_Word    e_flags;
199
    Elf32_Half    e_ehsize;
200
    Elf32_Half    e_phentsize;
201
    Elf32_Half    e_phnum;
202
    Elf32_Half    e_shentsize;
203
    Elf32_Half    e_shnum;
204
    Elf32_Half    e_shstrndx;
205
}
206

207
struct Elf64_Ehdr
208
{
209
    char[EI_NIDENT] e_ident = 0;
210
    Elf64_Half    e_type;
211
    Elf64_Half    e_machine;
212
    Elf64_Word    e_version;
213
    Elf64_Addr    e_entry;
214
    Elf64_Off     e_phoff;
215
    Elf64_Off     e_shoff;
216
    Elf64_Word    e_flags;
217
    Elf64_Half    e_ehsize;
218
    Elf64_Half    e_phentsize;
219
    Elf64_Half    e_phnum;
220
    Elf64_Half    e_shentsize;
221
    Elf64_Half    e_shnum;
222
    Elf64_Half    e_shstrndx;
223
}
224

225
enum EI_NIDENT = 16;
226
enum EI_VERSION =      6;
227
enum EI_CLASS =        4;
228
enum EI_DATA =         5;
229
enum EV_CURRENT =      1;
230

231
enum ELFDATANONE =     0;
232
enum ELFDATA2LSB =     1;
233
enum ELFDATA2MSB =     2;
234
enum ELFDATANUM =      3;
235
enum ELFCLASSNONE =    0;
236
enum ELFCLASS32 =      1;
237
enum ELFCLASS64 =      2;
238
enum ELFCLASSNUM =     3;
239

240
enum ET_REL =          1;
241

242
struct Elf32_Shdr
243
{
244
    Elf32_Word    sh_name;
245
    Elf32_Word    sh_type;
246
    Elf32_Word    sh_flags;
247
    Elf32_Addr    sh_addr;
248
    Elf32_Off     sh_offset;
249
    Elf32_Word    sh_size;
250
    Elf32_Word    sh_link;
251
    Elf32_Word    sh_info;
252
    Elf32_Word    sh_addralign;
253
    Elf32_Word    sh_entsize;
254
}
255

256
struct Elf64_Shdr
257
{
258
    Elf64_Word    sh_name;
259
    Elf64_Word    sh_type;
260
    Elf64_Xword   sh_flags;
261
    Elf64_Addr    sh_addr;
262
    Elf64_Off     sh_offset;
263
    Elf64_Xword   sh_size;
264
    Elf64_Word    sh_link;
265
    Elf64_Word    sh_info;
266
    Elf64_Xword   sh_addralign;
267
    Elf64_Xword   sh_entsize;
268
}
269

270
enum SHT_SYMTAB =        2;
271
enum SHT_STRTAB =        3;
272

273
struct Elf32_Sym
274
{
275
    Elf32_Word    st_name;
276
    Elf32_Addr    st_value;
277
    Elf32_Word    st_size;
278
    ubyte st_info;
279
    ubyte st_other;
280
    Elf32_Section st_shndx;
281
}
282

283
struct Elf64_Sym
284
{
285
    Elf64_Word    st_name;
286
    ubyte st_info;
287
    ubyte st_other;
288
    Elf64_Section st_shndx;
289
    Elf64_Addr    st_value;
290
    Elf64_Xword   st_size;
291
}
292

293
enum STB_GLOBAL =      1;
294
enum STB_WEAK =        2;
295

296
enum SHN_UNDEF =       0;

Read our documentation on viewing source code .

Loading