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 = §ions[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;
|