Make sym-file.exp work with remote targets and hosts.
[deliverable/binutils-gdb.git] / gdb / testsuite / gdb.base / sym-file-loader.c
CommitLineData
ecd75fc8 1/* Copyright 2013-2014 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>
23
24#include "sym-file-loader.h"
25
26#ifdef TARGET_LP64
27
28uint8_t
29elf_st_type (uint8_t st_info)
30{
31 return ELF64_ST_TYPE (st_info);
32}
33
34#elif defined TARGET_ILP32
35
36uint8_t
37elf_st_type (uint8_t st_info)
38{
39 return ELF32_ST_TYPE (st_info);
40}
41
42#endif
43
44/* Load a program segment. */
45
46static struct segment *
47load (uint8_t *addr, Elf_External_Phdr *phdr, struct segment *tail_seg)
48{
49 struct segment *seg = NULL;
50 uint8_t *mapped_addr = NULL;
51 void *from = NULL;
52 void *to = NULL;
53
54 /* For the sake of simplicity all operations are permitted. */
55 unsigned perm = PROT_READ | PROT_WRITE | PROT_EXEC;
56
57 mapped_addr = (uint8_t *) mmap ((void *) GETADDR (phdr, p_vaddr),
58 GET (phdr, p_memsz), perm,
59 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
60
61 from = (void *) (addr + GET (phdr, p_offset));
62 to = (void *) mapped_addr;
63
64 memcpy (to, from, GET (phdr, p_filesz));
65
66 seg = (struct segment *) malloc (sizeof (struct segment));
67
68 if (seg == 0)
69 return 0;
70
71 seg->mapped_addr = mapped_addr;
72 seg->phdr = phdr;
73 seg->next = 0;
74
75 if (tail_seg != 0)
76 tail_seg->next = seg;
77
78 return seg;
79}
80
2d1baf52
PA
81#ifdef __linux__
82# define SELF_LINK "/proc/self/exe"
83#elif defined NETBSD
84# define SELK_LINK "/proc/curproc/exe"
85#elif defined __OpenBSD__ || defined __FreeBSD__ || defined __DragonFly__
86# define SELK_LINK "/proc/curproc/file"
87#elif defined SunOS
88# define SELK_LINK "/proc/self/path/a.out"
89#endif
90
91/* Like RPATH=$ORIGIN, return the dirname of the current
92 executable. */
93
94static const char *
95get_origin (void)
96{
97 static char self_path[PATH_MAX];
98 static ssize_t self_path_len;
99
100 if (self_path_len == 0)
101 {
102#ifdef SELF_LINK
103 self_path_len = readlink (SELF_LINK, self_path, PATH_MAX - 1);
104 if (self_path_len != -1)
105 {
106 char *dirsep;
107
108 self_path[self_path_len] = '\0';
109 dirsep = strrchr (self_path, '/');
110 *dirsep = '\0';
111 }
112#else
113 self_path_len = -1;
114#endif
115 }
116
117 if (self_path_len == -1)
118 return NULL;
119 else
120 return self_path;
121}
122
681f229a
NB
123/* Mini shared library loader. No reallocation
124 is performed for the sake of simplicity. */
125
126int
127load_shlib (const char *file, Elf_External_Ehdr **ehdr_out,
128 struct segment **seg_out)
129{
130 uint64_t i;
2d1baf52 131 int fd = -1;
681f229a
NB
132 off_t fsize;
133 uint8_t *addr;
134 Elf_External_Ehdr *ehdr;
135 Elf_External_Phdr *phdr;
136 struct segment *head_seg = NULL;
137 struct segment *tail_seg = NULL;
2d1baf52
PA
138 const char *origin;
139 char *path;
140
141 /* Map the lib in memory for reading.
142
143 If the file name is relative, try looking it up relative to the
144 main executable's path. I.e., emulate RPATH=$ORIGIN. */
145 if (file[0] != '/')
146 {
147 origin = get_origin ();
148 if (origin == NULL)
149 {
150 fprintf (stderr, "get_origin not implemented.");
151 return -1;
152 }
153
154 path = alloca (strlen (origin) + 1 + strlen (file) + 1);
155 sprintf (path, "%s/%s", origin, file);
156 fd = open (path, O_RDONLY);
157 }
158
159 if (fd < 0)
160 fd = open (file, O_RDONLY);
681f229a 161
681f229a
NB
162 if (fd < 0)
163 {
164 perror ("fopen failed.");
165 return -1;
166 }
167
168 fsize = lseek (fd, 0, SEEK_END);
169
170 if (fsize < 0)
171 {
172 perror ("lseek failed.");
173 return -1;
174 }
175
176 addr = (uint8_t *) mmap (NULL, fsize, PROT_READ, MAP_PRIVATE, fd, 0);
177 if (addr == (uint8_t *) -1)
178 {
179 perror ("mmap failed.");
180 return -1;
181 }
182
183 /* Check if the lib is an ELF file. */
184 ehdr = (Elf_External_Ehdr *) addr;
185 if (ehdr->e_ident[EI_MAG0] != ELFMAG0
186 || ehdr->e_ident[EI_MAG1] != ELFMAG1
187 || ehdr->e_ident[EI_MAG2] != ELFMAG2
188 || ehdr->e_ident[EI_MAG3] != ELFMAG3)
189 {
190 printf ("Not an ELF file: %x\n", ehdr->e_ident[EI_MAG0]);
191 return -1;
192 }
193
194 if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
195 {
196 if (sizeof (void *) != 4)
197 {
198 printf ("Architecture mismatch.");
199 return -1;
200 }
201 }
202 else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
203 {
204 if (sizeof (void *) != 8)
205 {
206 printf ("Architecture mismatch.");
207 return -1;
208 }
209 }
210
211 /* Load the program segments. For the sake of simplicity
212 assume that no reallocation is needed. */
213 phdr = (Elf_External_Phdr *) (addr + GET (ehdr, e_phoff));
214 for (i = 0; i < GET (ehdr, e_phnum); i++, phdr++)
215 {
216 if (GET (phdr, p_type) == PT_LOAD)
217 {
218 struct segment *next_seg = load (addr, phdr, tail_seg);
219 if (next_seg == 0)
220 continue;
221 tail_seg = next_seg;
222 if (head_seg == 0)
223 head_seg = next_seg;
224 }
225 }
226 *ehdr_out = ehdr;
227 *seg_out = head_seg;
228 return 0;
229}
230
231/* Return the section-header table. */
232
233Elf_External_Shdr *
234find_shdrtab (Elf_External_Ehdr *ehdr)
235{
236 return (Elf_External_Shdr *) (((uint8_t *) ehdr) + GET (ehdr, e_shoff));
237}
238
239/* Return the string table of the section headers. */
240
241const char *
242find_shstrtab (Elf_External_Ehdr *ehdr, uint64_t *size)
243{
244 const Elf_External_Shdr *shdr;
245 const Elf_External_Shdr *shstr;
246
247 if (GET (ehdr, e_shnum) <= GET (ehdr, e_shstrndx))
248 {
249 printf ("The index of the string table is corrupt.");
250 return NULL;
251 }
252
253 shdr = find_shdrtab (ehdr);
254
255 shstr = &shdr[GET (ehdr, e_shstrndx)];
256 *size = GET (shstr, sh_size);
257 return ((const char *) ehdr) + GET (shstr, sh_offset);
258}
259
260/* Return the string table named SECTION. */
261
262const char *
263find_strtab (Elf_External_Ehdr *ehdr,
264 const char *section, uint64_t *strtab_size)
265{
266 uint64_t shstrtab_size = 0;
267 const char *shstrtab;
268 uint64_t i;
269 const Elf_External_Shdr *shdr = find_shdrtab (ehdr);
270
271 /* Get the string table of the section headers. */
272 shstrtab = find_shstrtab (ehdr, &shstrtab_size);
273 if (shstrtab == NULL)
274 return NULL;
275
276 for (i = 0; i < GET (ehdr, e_shnum); i++)
277 {
278 uint64_t name = GET (shdr + i, sh_name);
279 if (GET (shdr + i, sh_type) == SHT_STRTAB && name <= shstrtab_size
280 && strcmp ((const char *) &shstrtab[name], section) == 0)
281 {
282 *strtab_size = GET (shdr + i, sh_size);
283 return ((const char *) ehdr) + GET (shdr + i, sh_offset);
284 }
285
286 }
287 return NULL;
288}
289
290/* Return the section header named SECTION. */
291
292Elf_External_Shdr *
293find_shdr (Elf_External_Ehdr *ehdr, const char *section)
294{
295 uint64_t shstrtab_size = 0;
296 const char *shstrtab;
297 uint64_t i;
298
299 /* Get the string table of the section headers. */
300 shstrtab = find_shstrtab (ehdr, &shstrtab_size);
301 if (shstrtab == NULL)
302 return NULL;
303
304 Elf_External_Shdr *shdr = find_shdrtab (ehdr);
305 for (i = 0; i < GET (ehdr, e_shnum); i++)
306 {
307 uint64_t name = GET (shdr + i, sh_name);
308 if (name <= shstrtab_size)
309 {
310 if (strcmp ((const char *) &shstrtab[name], section) == 0)
311 return &shdr[i];
312 }
313
314 }
315 return NULL;
316}
317
318/* Return the symbol table. */
319
320Elf_External_Sym *
321find_symtab (Elf_External_Ehdr *ehdr, uint64_t *symtab_size)
322{
323 uint64_t i;
324 const Elf_External_Shdr *shdr = find_shdrtab (ehdr);
325
326 for (i = 0; i < GET (ehdr, e_shnum); i++)
327 {
328 if (GET (shdr + i, sh_type) == SHT_SYMTAB)
329 {
330 *symtab_size = GET (shdr + i, sh_size) / sizeof (Elf_External_Sym);
331 return (Elf_External_Sym *) (((const char *) ehdr) +
332 GET (shdr + i, sh_offset));
333 }
334 }
335 return NULL;
336}
337
338/* Translate a file offset to an address in a loaded segment. */
339
340int
341translate_offset (uint64_t file_offset, struct segment *seg, void **addr)
342{
343 while (seg)
344 {
345 uint64_t p_from, p_to;
346
347 Elf_External_Phdr *phdr = seg->phdr;
348
349 if (phdr == NULL)
350 {
351 seg = seg->next;
352 continue;
353 }
354
355 p_from = GET (phdr, p_offset);
356 p_to = p_from + GET (phdr, p_filesz);
357
358 if (p_from <= file_offset && file_offset < p_to)
359 {
360 *addr = (void *) (seg->mapped_addr + (file_offset - p_from));
361 return 0;
362 }
363 seg = seg->next;
364 }
365
366 return -1;
367}
368
369/* Lookup the address of FUNC. */
370
371int
372lookup_function (const char *func,
373 Elf_External_Ehdr *ehdr, struct segment *seg, void **addr)
374{
375 const char *strtab;
376 uint64_t strtab_size = 0;
377 Elf_External_Sym *symtab;
378 uint64_t symtab_size = 0;
379 uint64_t i;
380
381 /* Get the string table for the symbols. */
382 strtab = find_strtab (ehdr, ".strtab", &strtab_size);
383 if (strtab == NULL)
384 {
385 printf (".strtab not found.");
386 return -1;
387 }
388
389 /* Get the symbol table. */
390 symtab = find_symtab (ehdr, &symtab_size);
391 if (symtab == NULL)
392 {
393 printf ("symbol table not found.");
394 return -1;
395 }
396
397 for (i = 0; i < symtab_size; i++)
398 {
399 Elf_External_Sym *sym = &symtab[i];
400
401 if (elf_st_type (GET (sym, st_info)) != STT_FUNC)
402 continue;
403
404 if (GET (sym, st_name) < strtab_size)
405 {
406 const char *name = &strtab[GET (sym, st_name)];
407 if (strcmp (name, func) == 0)
408 {
409
410 uint64_t offset = GET (sym, st_value);
411 return translate_offset (offset, seg, addr);
412 }
413 }
414 }
415
416 return -1;
417}
This page took 0.10275 seconds and 4 git commands to generate.