]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/testsuite/gdb.base/sym-file-loader.c
Update Copyright year range in all files maintained by GDB.
[thirdparty/binutils-gdb.git] / gdb / testsuite / gdb.base / sym-file-loader.c
1 /* Copyright 2013-2014 Free Software Foundation, Inc.
2 This program is free software; you can redistribute it and/or modify
3 it under the terms of the GNU General Public License as published by
4 the Free Software Foundation; either version 3 of the License, or
5 (at your option) any later version.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program. If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/mman.h>
22
23 #include "sym-file-loader.h"
24
25 #ifdef TARGET_LP64
26
27 uint8_t
28 elf_st_type (uint8_t st_info)
29 {
30 return ELF64_ST_TYPE (st_info);
31 }
32
33 #elif defined TARGET_ILP32
34
35 uint8_t
36 elf_st_type (uint8_t st_info)
37 {
38 return ELF32_ST_TYPE (st_info);
39 }
40
41 #endif
42
43 /* Load a program segment. */
44
45 static struct segment *
46 load (uint8_t *addr, Elf_External_Phdr *phdr, struct segment *tail_seg)
47 {
48 struct segment *seg = NULL;
49 uint8_t *mapped_addr = NULL;
50 void *from = NULL;
51 void *to = NULL;
52
53 /* For the sake of simplicity all operations are permitted. */
54 unsigned perm = PROT_READ | PROT_WRITE | PROT_EXEC;
55
56 mapped_addr = (uint8_t *) mmap ((void *) GETADDR (phdr, p_vaddr),
57 GET (phdr, p_memsz), perm,
58 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
59
60 from = (void *) (addr + GET (phdr, p_offset));
61 to = (void *) mapped_addr;
62
63 memcpy (to, from, GET (phdr, p_filesz));
64
65 seg = (struct segment *) malloc (sizeof (struct segment));
66
67 if (seg == 0)
68 return 0;
69
70 seg->mapped_addr = mapped_addr;
71 seg->phdr = phdr;
72 seg->next = 0;
73
74 if (tail_seg != 0)
75 tail_seg->next = seg;
76
77 return seg;
78 }
79
80 /* Mini shared library loader. No reallocation
81 is performed for the sake of simplicity. */
82
83 int
84 load_shlib (const char *file, Elf_External_Ehdr **ehdr_out,
85 struct segment **seg_out)
86 {
87 uint64_t i;
88 int fd;
89 off_t fsize;
90 uint8_t *addr;
91 Elf_External_Ehdr *ehdr;
92 Elf_External_Phdr *phdr;
93 struct segment *head_seg = NULL;
94 struct segment *tail_seg = NULL;
95
96 /* Map the lib in memory for reading. */
97 fd = open (file, O_RDONLY);
98 if (fd < 0)
99 {
100 perror ("fopen failed.");
101 return -1;
102 }
103
104 fsize = lseek (fd, 0, SEEK_END);
105
106 if (fsize < 0)
107 {
108 perror ("lseek failed.");
109 return -1;
110 }
111
112 addr = (uint8_t *) mmap (NULL, fsize, PROT_READ, MAP_PRIVATE, fd, 0);
113 if (addr == (uint8_t *) -1)
114 {
115 perror ("mmap failed.");
116 return -1;
117 }
118
119 /* Check if the lib is an ELF file. */
120 ehdr = (Elf_External_Ehdr *) addr;
121 if (ehdr->e_ident[EI_MAG0] != ELFMAG0
122 || ehdr->e_ident[EI_MAG1] != ELFMAG1
123 || ehdr->e_ident[EI_MAG2] != ELFMAG2
124 || ehdr->e_ident[EI_MAG3] != ELFMAG3)
125 {
126 printf ("Not an ELF file: %x\n", ehdr->e_ident[EI_MAG0]);
127 return -1;
128 }
129
130 if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
131 {
132 if (sizeof (void *) != 4)
133 {
134 printf ("Architecture mismatch.");
135 return -1;
136 }
137 }
138 else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
139 {
140 if (sizeof (void *) != 8)
141 {
142 printf ("Architecture mismatch.");
143 return -1;
144 }
145 }
146
147 /* Load the program segments. For the sake of simplicity
148 assume that no reallocation is needed. */
149 phdr = (Elf_External_Phdr *) (addr + GET (ehdr, e_phoff));
150 for (i = 0; i < GET (ehdr, e_phnum); i++, phdr++)
151 {
152 if (GET (phdr, p_type) == PT_LOAD)
153 {
154 struct segment *next_seg = load (addr, phdr, tail_seg);
155 if (next_seg == 0)
156 continue;
157 tail_seg = next_seg;
158 if (head_seg == 0)
159 head_seg = next_seg;
160 }
161 }
162 *ehdr_out = ehdr;
163 *seg_out = head_seg;
164 return 0;
165 }
166
167 /* Return the section-header table. */
168
169 Elf_External_Shdr *
170 find_shdrtab (Elf_External_Ehdr *ehdr)
171 {
172 return (Elf_External_Shdr *) (((uint8_t *) ehdr) + GET (ehdr, e_shoff));
173 }
174
175 /* Return the string table of the section headers. */
176
177 const char *
178 find_shstrtab (Elf_External_Ehdr *ehdr, uint64_t *size)
179 {
180 const Elf_External_Shdr *shdr;
181 const Elf_External_Shdr *shstr;
182
183 if (GET (ehdr, e_shnum) <= GET (ehdr, e_shstrndx))
184 {
185 printf ("The index of the string table is corrupt.");
186 return NULL;
187 }
188
189 shdr = find_shdrtab (ehdr);
190
191 shstr = &shdr[GET (ehdr, e_shstrndx)];
192 *size = GET (shstr, sh_size);
193 return ((const char *) ehdr) + GET (shstr, sh_offset);
194 }
195
196 /* Return the string table named SECTION. */
197
198 const char *
199 find_strtab (Elf_External_Ehdr *ehdr,
200 const char *section, uint64_t *strtab_size)
201 {
202 uint64_t shstrtab_size = 0;
203 const char *shstrtab;
204 uint64_t i;
205 const Elf_External_Shdr *shdr = find_shdrtab (ehdr);
206
207 /* Get the string table of the section headers. */
208 shstrtab = find_shstrtab (ehdr, &shstrtab_size);
209 if (shstrtab == NULL)
210 return NULL;
211
212 for (i = 0; i < GET (ehdr, e_shnum); i++)
213 {
214 uint64_t name = GET (shdr + i, sh_name);
215 if (GET (shdr + i, sh_type) == SHT_STRTAB && name <= shstrtab_size
216 && strcmp ((const char *) &shstrtab[name], section) == 0)
217 {
218 *strtab_size = GET (shdr + i, sh_size);
219 return ((const char *) ehdr) + GET (shdr + i, sh_offset);
220 }
221
222 }
223 return NULL;
224 }
225
226 /* Return the section header named SECTION. */
227
228 Elf_External_Shdr *
229 find_shdr (Elf_External_Ehdr *ehdr, const char *section)
230 {
231 uint64_t shstrtab_size = 0;
232 const char *shstrtab;
233 uint64_t i;
234
235 /* Get the string table of the section headers. */
236 shstrtab = find_shstrtab (ehdr, &shstrtab_size);
237 if (shstrtab == NULL)
238 return NULL;
239
240 Elf_External_Shdr *shdr = find_shdrtab (ehdr);
241 for (i = 0; i < GET (ehdr, e_shnum); i++)
242 {
243 uint64_t name = GET (shdr + i, sh_name);
244 if (name <= shstrtab_size)
245 {
246 if (strcmp ((const char *) &shstrtab[name], section) == 0)
247 return &shdr[i];
248 }
249
250 }
251 return NULL;
252 }
253
254 /* Return the symbol table. */
255
256 Elf_External_Sym *
257 find_symtab (Elf_External_Ehdr *ehdr, uint64_t *symtab_size)
258 {
259 uint64_t i;
260 const Elf_External_Shdr *shdr = find_shdrtab (ehdr);
261
262 for (i = 0; i < GET (ehdr, e_shnum); i++)
263 {
264 if (GET (shdr + i, sh_type) == SHT_SYMTAB)
265 {
266 *symtab_size = GET (shdr + i, sh_size) / sizeof (Elf_External_Sym);
267 return (Elf_External_Sym *) (((const char *) ehdr) +
268 GET (shdr + i, sh_offset));
269 }
270 }
271 return NULL;
272 }
273
274 /* Translate a file offset to an address in a loaded segment. */
275
276 int
277 translate_offset (uint64_t file_offset, struct segment *seg, void **addr)
278 {
279 while (seg)
280 {
281 uint64_t p_from, p_to;
282
283 Elf_External_Phdr *phdr = seg->phdr;
284
285 if (phdr == NULL)
286 {
287 seg = seg->next;
288 continue;
289 }
290
291 p_from = GET (phdr, p_offset);
292 p_to = p_from + GET (phdr, p_filesz);
293
294 if (p_from <= file_offset && file_offset < p_to)
295 {
296 *addr = (void *) (seg->mapped_addr + (file_offset - p_from));
297 return 0;
298 }
299 seg = seg->next;
300 }
301
302 return -1;
303 }
304
305 /* Lookup the address of FUNC. */
306
307 int
308 lookup_function (const char *func,
309 Elf_External_Ehdr *ehdr, struct segment *seg, void **addr)
310 {
311 const char *strtab;
312 uint64_t strtab_size = 0;
313 Elf_External_Sym *symtab;
314 uint64_t symtab_size = 0;
315 uint64_t i;
316
317 /* Get the string table for the symbols. */
318 strtab = find_strtab (ehdr, ".strtab", &strtab_size);
319 if (strtab == NULL)
320 {
321 printf (".strtab not found.");
322 return -1;
323 }
324
325 /* Get the symbol table. */
326 symtab = find_symtab (ehdr, &symtab_size);
327 if (symtab == NULL)
328 {
329 printf ("symbol table not found.");
330 return -1;
331 }
332
333 for (i = 0; i < symtab_size; i++)
334 {
335 Elf_External_Sym *sym = &symtab[i];
336
337 if (elf_st_type (GET (sym, st_info)) != STT_FUNC)
338 continue;
339
340 if (GET (sym, st_name) < strtab_size)
341 {
342 const char *name = &strtab[GET (sym, st_name)];
343 if (strcmp (name, func) == 0)
344 {
345
346 uint64_t offset = GET (sym, st_value);
347 return translate_offset (offset, seg, addr);
348 }
349 }
350 }
351
352 return -1;
353 }