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