1
/**
2
 * Extract symbols from an ELF object file.
3
 *
4
 * Copyright:   Copyright (C) 1999-2020 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
version(Windows) {}
15
else version(OSX) {}
16
else:
17

18
version (linux)
19
    import core.sys.linux.elf;
20
else version (FreeBSD)
21
    import core.sys.freebsd.sys.elf;
22
else version (DragonFlyBSD)
23
    import core.sys.dragonflybsd.sys.elf;
24
else version (Solaris)
25
    import core.sys.solaris.elf;
26

27
import core.stdc.string;
28
import core.checkedint;
29

30
import dmd.globals;
31
import dmd.errors;
32

33
enum LOG = false;
34

35
/*****************************************
36
 * Reads an object module from base[] and passes the names
37
 * of any exported symbols to (*pAddSymbol)().
38
 * Params:
39
 *      pAddSymbol =  function to pass the names to
40
 *      base =        array of contents of object module
41
 *      module_name = name of the object module (used for error messages)
42
 *      loc =         location to use for error printing
43
 */
44
void scanElfObjModule(void delegate(const(char)[] name, int pickAny) pAddSymbol,
45
        const(ubyte)[] base, const(char)* module_name, Loc loc)
46
{
47
    static if (LOG)
48
    {
49
        printf("scanElfObjModule(%s)\n", module_name);
50
    }
51

52
    void corrupt(int reason)
53
    {
54 0
        error(loc, "corrupt ELF object module `%s` %d", module_name, reason);
55
    }
56

57 1
    if (base.length < Elf32_Ehdr.sizeof)
58 0
        return corrupt(__LINE__); // must be at least large enough for ELF32
59
    static immutable ubyte[4] elf = [0x7F, 'E', 'L', 'F']; // ELF file signature
60 1
    if (base[0 .. elf.length] != elf[])
61 0
        return corrupt(__LINE__);
62

63 1
    if (base[EI_VERSION] != EV_CURRENT)
64
    {
65 0
        return error(loc, "ELF object module `%s` has EI_VERSION = %d, should be %d",
66
            module_name, base[EI_VERSION], EV_CURRENT);
67
    }
68 1
    if (base[EI_DATA] != ELFDATA2LSB)
69
    {
70 0
        return error(loc, "ELF object module `%s` is byte swapped and unsupported", module_name);
71
    }
72 1
    if (base[EI_CLASS] != ELFCLASS32 && base[EI_CLASS] != ELFCLASS64)
73
    {
74 0
        return error(loc, "ELF object module `%s` is unrecognized class %d", module_name, base[EI_CLASS]);
75
    }
76

77
    void scanELF(uint model)()
78
    {
79
        static if (model == 32)
80
        {
81
            alias ElfXX_Ehdr = Elf32_Ehdr;
82
            alias ElfXX_Shdr = Elf32_Shdr;
83
            alias ElfXX_Sym = Elf32_Sym;
84
        }
85
        else
86
        {
87
            static assert(model == 64);
88
            alias ElfXX_Ehdr = Elf64_Ehdr;
89
            alias ElfXX_Shdr = Elf64_Shdr;
90
            alias ElfXX_Sym = Elf64_Sym;
91
        }
92

93 1
        if (base.length < ElfXX_Ehdr.sizeof)
94 0
            return corrupt(__LINE__);
95

96 1
        const eh = cast(const(ElfXX_Ehdr)*) base.ptr;
97 1
        if (eh.e_type != ET_REL)
98 0
            return error(loc, "ELF object module `%s` is not relocatable", module_name);
99 1
        if (eh.e_version != EV_CURRENT)
100 0
            return corrupt(__LINE__);
101

102 1
        bool overflow;
103 1
        const end = addu(eh.e_shoff, mulu(eh.e_shentsize, eh.e_shnum, overflow), overflow);
104 1
        if (overflow || end > base.length)
105 0
            return corrupt(__LINE__);
106

107
        /* For each Section
108
         */
109 1
        const sections = (cast(const(ElfXX_Shdr)*)(base.ptr + eh.e_shoff))[0 .. eh.e_shnum];
110 1
        foreach (ref const section; sections)
111
        {
112 1
            if (section.sh_type != SHT_SYMTAB)
113 1
                continue;
114

115
            bool checkShdrXX(const ref ElfXX_Shdr shdr)
116
            {
117 1
                bool overflow;
118 1
                return addu(shdr.sh_offset, shdr.sh_size, overflow) > base.length || overflow;
119
            }
120

121 1
            if (checkShdrXX(section))
122 0
                return corrupt(__LINE__);
123

124
            /* sh_link gives the particular string table section
125
             * used for the symbol names.
126
             */
127 1
            if (section.sh_link >= eh.e_shnum)
128 0
                return corrupt(__LINE__);
129

130 1
            const string_section = &sections[section.sh_link];
131 1
            if (string_section.sh_type != SHT_STRTAB)
132 0
                return corrupt(__LINE__);
133

134 1
            if (checkShdrXX(*string_section))
135 0
                return corrupt(__LINE__);
136

137 1
            const string_tab = (cast(const(char)[])base)
138
                [cast(size_t)string_section.sh_offset ..
139
                 cast(size_t)(string_section.sh_offset + string_section.sh_size)];
140

141
            /* Get the array of symbols this section refers to
142
             */
143 1
            const symbols = (cast(ElfXX_Sym*)(base.ptr + cast(size_t)section.sh_offset))
144
                [0 .. cast(size_t)(section.sh_size / ElfXX_Sym.sizeof)];
145

146 1
            foreach (ref const sym; symbols)
147
            {
148 1
                const stb = sym.st_info >> 4;
149 1
                if (stb != STB_GLOBAL && stb != STB_WEAK || sym.st_shndx == SHN_UNDEF)
150 1
                    continue; // it's extern
151

152 1
                if (sym.st_name >= string_tab.length)
153 0
                    return corrupt(__LINE__);
154

155 1
                const name = &string_tab[sym.st_name];
156
                //printf("sym st_name = x%x\n", sym.st_name);
157 1
                const pend = cast(const(char*)) memchr(name, 0, string_tab.length - sym.st_name);
158 1
                if (!pend)       // if didn't find terminating 0 inside the string section
159 0
                    return corrupt(__LINE__);
160 1
                pAddSymbol(name[0 .. pend - name], 1);
161
            }
162
        }
163
    }
164

165 1
    if (base[EI_CLASS] == ELFCLASS32)
166
    {
167 0
        scanELF!32;
168
    }
169
    else
170
    {
171 1
        assert(base[EI_CLASS] == ELFCLASS64);
172 1
        scanELF!64;
173
    }
174
}

Read our documentation on viewing source code .

Loading