Fix skip.exp test failure observed with gcc-9.2.0
[deliverable/binutils-gdb.git] / gdb / testsuite / gdb.base / sym-file-loader.c
1 /* Copyright 2013-2019 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 <limits.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/mman.h>
23
24 #include "sym-file-loader.h"
25
26 #include <inttypes.h>
27 #include <ansidecl.h>
28 #include <elf/common.h>
29 #include <elf/external.h>
30
31 #ifdef TARGET_LP64
32
33 typedef Elf64_External_Phdr Elf_External_Phdr;
34 typedef Elf64_External_Ehdr Elf_External_Ehdr;
35 typedef Elf64_External_Shdr Elf_External_Shdr;
36 typedef Elf64_External_Sym Elf_External_Sym;
37 typedef uint64_t Elf_Addr;
38
39 #elif defined TARGET_ILP32
40
41 typedef Elf32_External_Phdr Elf_External_Phdr;
42 typedef Elf32_External_Ehdr Elf_External_Ehdr;
43 typedef Elf32_External_Shdr Elf_External_Shdr;
44 typedef Elf32_External_Sym Elf_External_Sym;
45 typedef uint32_t Elf_Addr;
46
47 #endif
48
49 #define GET(hdr, field) (\
50 sizeof ((hdr)->field) == 1 ? (uint64_t) (hdr)->field[0] : \
51 sizeof ((hdr)->field) == 2 ? (uint64_t) *(uint16_t *) (hdr)->field : \
52 sizeof ((hdr)->field) == 4 ? (uint64_t) *(uint32_t *) (hdr)->field : \
53 sizeof ((hdr)->field) == 8 ? *(uint64_t *) (hdr)->field : \
54 *(uint64_t *) NULL)
55
56 #define GETADDR(hdr, field) (\
57 sizeof ((hdr)->field) == sizeof (Elf_Addr) ? *(Elf_Addr *) (hdr)->field : \
58 *(Elf_Addr *) NULL)
59
60 struct segment
61 {
62 uint8_t *mapped_addr;
63 size_t mapped_size;
64 Elf_External_Phdr *phdr;
65 struct segment *next;
66 };
67
68 struct library
69 {
70 int fd;
71 Elf_External_Ehdr *ehdr;
72 struct segment *segments;
73 };
74
75 static Elf_External_Shdr *find_shdr (Elf_External_Ehdr *ehdr,
76 const char *section);
77 static int translate_offset (uint64_t file_offset, struct segment *seg,
78 void **addr);
79
80 #ifdef TARGET_LP64
81
82 uint8_t
83 elf_st_type (uint8_t st_info)
84 {
85 return ELF64_ST_TYPE (st_info);
86 }
87
88 #elif defined TARGET_ILP32
89
90 uint8_t
91 elf_st_type (uint8_t st_info)
92 {
93 return ELF32_ST_TYPE (st_info);
94 }
95
96 #endif
97
98 /* Load a program segment. */
99
100 static struct segment *
101 load (uint8_t *addr, Elf_External_Phdr *phdr, struct segment *tail_seg)
102 {
103 struct segment *seg = NULL;
104 uint8_t *mapped_addr = NULL;
105 size_t mapped_size = 0;
106 void *from = NULL;
107 void *to = NULL;
108
109 /* For the sake of simplicity all operations are permitted. */
110 unsigned perm = PROT_READ | PROT_WRITE | PROT_EXEC;
111
112 mapped_addr = (uint8_t *) mmap ((void *) GETADDR (phdr, p_vaddr),
113 GET (phdr, p_memsz), perm,
114 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
115 mapped_size = GET (phdr, p_memsz);
116
117 from = (void *) (addr + GET (phdr, p_offset));
118 to = (void *) mapped_addr;
119
120 memcpy (to, from, GET (phdr, p_filesz));
121
122 seg = (struct segment *) malloc (sizeof (struct segment));
123
124 if (seg == 0)
125 return 0;
126
127 seg->mapped_addr = mapped_addr;
128 seg->mapped_size = mapped_size;
129 seg->phdr = phdr;
130 seg->next = 0;
131
132 if (tail_seg != 0)
133 tail_seg->next = seg;
134
135 return seg;
136 }
137
138 #ifdef __linux__
139 # define SELF_LINK "/proc/self/exe"
140 #elif defined NETBSD
141 # define SELF_LINK "/proc/curproc/exe"
142 #elif defined __OpenBSD__ || defined __FreeBSD__ || defined __DragonFly__
143 # define SELF_LINK "/proc/curproc/file"
144 #elif defined SunOS
145 # define SELF_LINK "/proc/self/path/a.out"
146 #endif
147
148 /* Like RPATH=$ORIGIN, return the dirname of the current
149 executable. */
150
151 static const char *
152 get_origin (void)
153 {
154 static char self_path[PATH_MAX];
155 static ssize_t self_path_len;
156
157 if (self_path_len == 0)
158 {
159 #ifdef SELF_LINK
160 self_path_len = readlink (SELF_LINK, self_path, PATH_MAX - 1);
161 if (self_path_len != -1)
162 {
163 char *dirsep;
164
165 self_path[self_path_len] = '\0';
166 dirsep = strrchr (self_path, '/');
167 *dirsep = '\0';
168 }
169 #else
170 self_path_len = -1;
171 #endif
172 }
173
174 if (self_path_len == -1)
175 return NULL;
176 else
177 return self_path;
178 }
179
180 /* Unload/unmap a segment. */
181
182 static void
183 unload (struct segment *seg)
184 {
185 munmap (seg->mapped_addr, seg->mapped_size);
186 free (seg);
187 }
188
189 void
190 unload_shlib (struct library *lib)
191 {
192 struct segment *seg, *next_seg;
193
194 for (seg = lib->segments; seg != NULL; seg = next_seg)
195 {
196 next_seg = seg->next;
197 unload (seg);
198 }
199
200 close (lib->fd);
201 free (lib);
202 }
203
204 /* Mini shared library loader. No reallocation
205 is performed for the sake of simplicity. */
206
207 struct library *
208 load_shlib (const char *file)
209 {
210 struct library *lib;
211 uint64_t i;
212 int fd = -1;
213 off_t fsize;
214 uint8_t *addr;
215 Elf_External_Ehdr *ehdr;
216 Elf_External_Phdr *phdr;
217 struct segment *head_seg = NULL;
218 struct segment *tail_seg = NULL;
219 const char *origin;
220 char *path;
221
222 /* Map the lib in memory for reading.
223
224 If the file name is relative, try looking it up relative to the
225 main executable's path. I.e., emulate RPATH=$ORIGIN. */
226 if (file[0] != '/')
227 {
228 origin = get_origin ();
229 if (origin == NULL)
230 {
231 fprintf (stderr, "get_origin not implemented.");
232 return NULL;
233 }
234
235 path = alloca (strlen (origin) + 1 + strlen (file) + 1);
236 sprintf (path, "%s/%s", origin, file);
237 fd = open (path, O_RDONLY);
238 }
239
240 if (fd < 0)
241 fd = open (file, O_RDONLY);
242
243 if (fd < 0)
244 {
245 perror ("fopen failed.");
246 return NULL;
247 }
248
249 fsize = lseek (fd, 0, SEEK_END);
250
251 if (fsize < 0)
252 {
253 perror ("lseek failed.");
254 return NULL;
255 }
256
257 addr = (uint8_t *) mmap (NULL, fsize, PROT_READ, MAP_PRIVATE, fd, 0);
258 if (addr == (uint8_t *) -1)
259 {
260 perror ("mmap failed.");
261 return NULL;
262 }
263
264 /* Check if the lib is an ELF file. */
265 ehdr = (Elf_External_Ehdr *) addr;
266 if (ehdr->e_ident[EI_MAG0] != ELFMAG0
267 || ehdr->e_ident[EI_MAG1] != ELFMAG1
268 || ehdr->e_ident[EI_MAG2] != ELFMAG2
269 || ehdr->e_ident[EI_MAG3] != ELFMAG3)
270 {
271 printf ("Not an ELF file: %x\n", ehdr->e_ident[EI_MAG0]);
272 return NULL;
273 }
274
275 if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
276 {
277 if (sizeof (void *) != 4)
278 {
279 printf ("Architecture mismatch.");
280 return NULL;
281 }
282 }
283 else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
284 {
285 if (sizeof (void *) != 8)
286 {
287 printf ("Architecture mismatch.");
288 return NULL;
289 }
290 }
291
292 lib = malloc (sizeof (struct library));
293 if (lib == NULL)
294 {
295 printf ("malloc failed.");
296 return NULL;
297 }
298
299 lib->fd = fd;
300
301 /* Load the program segments. For the sake of simplicity
302 assume that no reallocation is needed. */
303 phdr = (Elf_External_Phdr *) (addr + GET (ehdr, e_phoff));
304 for (i = 0; i < GET (ehdr, e_phnum); i++, phdr++)
305 {
306 if (GET (phdr, p_type) == PT_LOAD)
307 {
308 struct segment *next_seg = load (addr, phdr, tail_seg);
309 if (next_seg == 0)
310 continue;
311 tail_seg = next_seg;
312 if (head_seg == 0)
313 head_seg = next_seg;
314 }
315 }
316 lib->ehdr = ehdr;
317 lib->segments = head_seg;
318 return lib;
319 }
320
321 int
322 get_text_addr (struct library *lib, void **text_addr)
323 {
324 Elf_External_Shdr *text;
325
326 /* Get the text section. */
327 text = find_shdr (lib->ehdr, ".text");
328 if (text == NULL)
329 return -1;
330
331 if (translate_offset (GET (text, sh_offset), lib->segments, text_addr)
332 != 0)
333 return -1;
334
335 return 0;
336 }
337
338 /* Return the section-header table. */
339
340 Elf_External_Shdr *
341 find_shdrtab (Elf_External_Ehdr *ehdr)
342 {
343 return (Elf_External_Shdr *) (((uint8_t *) ehdr) + GET (ehdr, e_shoff));
344 }
345
346 /* Return the string table of the section headers. */
347
348 const char *
349 find_shstrtab (Elf_External_Ehdr *ehdr, uint64_t *size)
350 {
351 const Elf_External_Shdr *shdr;
352 const Elf_External_Shdr *shstr;
353
354 if (GET (ehdr, e_shnum) <= GET (ehdr, e_shstrndx))
355 {
356 printf ("The index of the string table is corrupt.");
357 return NULL;
358 }
359
360 shdr = find_shdrtab (ehdr);
361
362 shstr = &shdr[GET (ehdr, e_shstrndx)];
363 *size = GET (shstr, sh_size);
364 return ((const char *) ehdr) + GET (shstr, sh_offset);
365 }
366
367 /* Return the string table named SECTION. */
368
369 const char *
370 find_strtab (Elf_External_Ehdr *ehdr,
371 const char *section, uint64_t *strtab_size)
372 {
373 uint64_t shstrtab_size = 0;
374 const char *shstrtab;
375 uint64_t i;
376 const Elf_External_Shdr *shdr = find_shdrtab (ehdr);
377
378 /* Get the string table of the section headers. */
379 shstrtab = find_shstrtab (ehdr, &shstrtab_size);
380 if (shstrtab == NULL)
381 return NULL;
382
383 for (i = 0; i < GET (ehdr, e_shnum); i++)
384 {
385 uint64_t name = GET (shdr + i, sh_name);
386 if (GET (shdr + i, sh_type) == SHT_STRTAB && name <= shstrtab_size
387 && strcmp ((const char *) &shstrtab[name], section) == 0)
388 {
389 *strtab_size = GET (shdr + i, sh_size);
390 return ((const char *) ehdr) + GET (shdr + i, sh_offset);
391 }
392
393 }
394 return NULL;
395 }
396
397 /* Return the section header named SECTION. */
398
399 static Elf_External_Shdr *
400 find_shdr (Elf_External_Ehdr *ehdr, const char *section)
401 {
402 uint64_t shstrtab_size = 0;
403 const char *shstrtab;
404 uint64_t i;
405
406 /* Get the string table of the section headers. */
407 shstrtab = find_shstrtab (ehdr, &shstrtab_size);
408 if (shstrtab == NULL)
409 return NULL;
410
411 Elf_External_Shdr *shdr = find_shdrtab (ehdr);
412 for (i = 0; i < GET (ehdr, e_shnum); i++)
413 {
414 uint64_t name = GET (shdr + i, sh_name);
415 if (name <= shstrtab_size)
416 {
417 if (strcmp ((const char *) &shstrtab[name], section) == 0)
418 return &shdr[i];
419 }
420
421 }
422 return NULL;
423 }
424
425 /* Return the symbol table. */
426
427 static Elf_External_Sym *
428 find_symtab (Elf_External_Ehdr *ehdr, uint64_t *symtab_size)
429 {
430 uint64_t i;
431 const Elf_External_Shdr *shdr = find_shdrtab (ehdr);
432
433 for (i = 0; i < GET (ehdr, e_shnum); i++)
434 {
435 if (GET (shdr + i, sh_type) == SHT_SYMTAB)
436 {
437 *symtab_size = GET (shdr + i, sh_size) / sizeof (Elf_External_Sym);
438 return (Elf_External_Sym *) (((const char *) ehdr) +
439 GET (shdr + i, sh_offset));
440 }
441 }
442 return NULL;
443 }
444
445 /* Translate a file offset to an address in a loaded segment. */
446
447 static int
448 translate_offset (uint64_t file_offset, struct segment *seg, void **addr)
449 {
450 while (seg)
451 {
452 uint64_t p_from, p_to;
453
454 Elf_External_Phdr *phdr = seg->phdr;
455
456 if (phdr == NULL)
457 {
458 seg = seg->next;
459 continue;
460 }
461
462 p_from = GET (phdr, p_offset);
463 p_to = p_from + GET (phdr, p_filesz);
464
465 if (p_from <= file_offset && file_offset < p_to)
466 {
467 *addr = (void *) (seg->mapped_addr + (file_offset - p_from));
468 return 0;
469 }
470 seg = seg->next;
471 }
472
473 return -1;
474 }
475
476 /* Lookup the address of FUNC. */
477
478 int
479 lookup_function (struct library *lib, const char *func, void **addr)
480 {
481 const char *strtab;
482 uint64_t strtab_size = 0;
483 Elf_External_Sym *symtab;
484 uint64_t symtab_size = 0;
485 uint64_t i;
486 Elf_External_Ehdr *ehdr = lib->ehdr;
487 struct segment *seg = lib->segments;
488
489 /* Get the string table for the symbols. */
490 strtab = find_strtab (ehdr, ".strtab", &strtab_size);
491 if (strtab == NULL)
492 {
493 printf (".strtab not found.");
494 return -1;
495 }
496
497 /* Get the symbol table. */
498 symtab = find_symtab (ehdr, &symtab_size);
499 if (symtab == NULL)
500 {
501 printf ("symbol table not found.");
502 return -1;
503 }
504
505 for (i = 0; i < symtab_size; i++)
506 {
507 Elf_External_Sym *sym = &symtab[i];
508
509 if (elf_st_type (GET (sym, st_info)) != STT_FUNC)
510 continue;
511
512 if (GET (sym, st_name) < strtab_size)
513 {
514 const char *name = &strtab[GET (sym, st_name)];
515 if (strcmp (name, func) == 0)
516 {
517
518 uint64_t offset = GET (sym, st_value);
519 return translate_offset (offset, seg, addr);
520 }
521 }
522 }
523
524 return -1;
525 }
This page took 0.041307 seconds and 4 git commands to generate.