Internally these would treat the cast same as a normal conversion from int[7] to int[], which allows code at CTFE to erroneously succeed where it would raise a SEGV at run-time.
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 |
error(loc, "corrupt ELF object module `%s` %d", module_name, reason); |
|
55 |
}
|
|
56 |
|
|
57 | 1 |
if (base.length < Elf32_Ehdr.sizeof) |
58 |
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 |
return corrupt(__LINE__); |
|
62 |
|
|
63 | 1 |
if (base[EI_VERSION] != EV_CURRENT) |
64 |
{
|
|
65 |
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 |
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 |
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 |
return corrupt(__LINE__); |
|
95 |
|
|
96 | 1 |
const eh = cast(const(ElfXX_Ehdr)*) base.ptr; |
97 | 1 |
if (eh.e_type != ET_REL) |
98 |
return error(loc, "ELF object module `%s` is not relocatable", module_name); |
|
99 | 1 |
if (eh.e_version != EV_CURRENT) |
100 |
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 |
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 |
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 |
return corrupt(__LINE__); |
|
129 |
|
|
130 | 1 |
const string_section = §ions[section.sh_link]; |
131 | 1 |
if (string_section.sh_type != SHT_STRTAB) |
132 |
return corrupt(__LINE__); |
|
133 |
|
|
134 | 1 |
if (checkShdrXX(*string_section)) |
135 |
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 |
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 |
return corrupt(__LINE__); |
|
160 | 1 |
pAddSymbol(name[0 .. pend - name], 1); |
161 |
}
|
|
162 |
}
|
|
163 |
}
|
|
164 |
|
|
165 | 1 |
if (base[EI_CLASS] == ELFCLASS32) |
166 |
{
|
|
167 |
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 .