1 /* Find debugging and symbol information for a module in libdwfl.
2 Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc.
3 This file is part of Red Hat elfutils.
4
5 Red Hat elfutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by the
7 Free Software Foundation; version 2 of the License.
8
9 Red Hat elfutils is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with Red Hat elfutils; if not, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
17
18 In addition, as a special exception, Red Hat, Inc. gives You the
19 additional right to link the code of Red Hat elfutils with code licensed
20 under any Open Source Initiative certified open source license
21 (http://www.opensource.org/licenses/index.php) which requires the
22 distribution of source code with any binary distribution and to
23 distribute linked combinations of the two. Non-GPL Code permitted under
24 this exception must only link to the code of Red Hat elfutils through
25 those well defined interfaces identified in the file named EXCEPTION
26 found in the source code files (the "Approved Interfaces"). The files
27 of Non-GPL Code may instantiate templates or use macros or inline
28 functions from the Approved Interfaces without causing the resulting
29 work to be covered by the GNU General Public License. Only Red Hat,
30 Inc. may make changes or additions to the list of Approved Interfaces.
31 Red Hat's grant of this exception is conditioned upon your not adding
32 any new exceptions. If you wish to add a new Approved Interface or
33 exception, please contact Red Hat. You must obey the GNU General Public
34 License in all respects for all of the Red Hat elfutils code and other
35 code used in conjunction with Red Hat elfutils except the Non-GPL Code
36 covered by this exception. If you modify this file, you may extend this
37 exception to your version of the file, but you are not obligated to do
38 so. If you do not wish to provide this exception without modification,
39 you must delete this exception statement from your version and license
40 this file solely under the GPL without exception.
41
42 Red Hat elfutils is an included package of the Open Invention Network.
43 An included package of the Open Invention Network is a package for which
44 Open Invention Network licensees cross-license their patents. No patent
45 license is granted, either expressly or impliedly, by designation as an
46 included package. Should you wish to participate in the Open Invention
47 Network licensing program, please visit www.openinventionnetwork.com
48 <http://www.openinventionnetwork.com>. */
49
50 #include "libdwflP.h"
51 #include <fcntl.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include "../libdw/libdwP.h" /* DWARF_E_* values are here. */
55
56 /* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD.
57 When we return success, FILE->elf and FILE->bias are set up. */
58 static inline Dwfl_Error
open_elf(Dwfl_Module * mod,struct dwfl_file * file)59 open_elf (Dwfl_Module *mod, struct dwfl_file *file)
60 {
61 if (file->elf == NULL)
62 {
63 /* If there was a pre-primed file name left that the callback left
64 behind, try to open that file name. */
65 if (file->fd < 0 && file->name != NULL)
66 file->fd = TEMP_FAILURE_RETRY (open64 (file->name, O_RDONLY));
67
68 if (file->fd < 0)
69 return CBFAIL;
70
71 file->elf = elf_begin (file->fd, ELF_C_READ_MMAP_PRIVATE, NULL);
72 }
73
74 if (unlikely (elf_kind (file->elf) != ELF_K_ELF))
75 {
76 close (file->fd);
77 file->fd = -1;
78 return DWFL_E_BADELF;
79 }
80
81 GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (file->elf, &ehdr_mem);
82 if (ehdr == NULL)
83 {
84 elf_error:
85 close (file->fd);
86 file->fd = -1;
87 return DWFL_E (LIBELF, elf_errno ());
88 }
89
90 /* The addresses in an ET_EXEC file are absolute. The lowest p_vaddr of
91 the main file can differ from that of the debug file due to prelink.
92 But that doesn't not change addresses that symbols, debuginfo, or
93 sh_addr of any program sections refer to. */
94 file->bias = 0;
95 if (mod->e_type != ET_EXEC)
96 for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
97 {
98 GElf_Phdr ph_mem;
99 GElf_Phdr *ph = gelf_getphdr (file->elf, i, &ph_mem);
100 if (ph == NULL)
101 goto elf_error;
102 if (ph->p_type == PT_LOAD)
103 {
104 file->bias = ((mod->low_addr & -ph->p_align)
105 - (ph->p_vaddr & -ph->p_align));
106 break;
107 }
108 }
109
110 mod->e_type = ehdr->e_type;
111
112 /* Relocatable Linux kernels are ET_EXEC but act like ET_DYN. */
113 if (mod->e_type == ET_EXEC && file->bias != 0)
114 mod->e_type = ET_DYN;
115
116 return DWFL_E_NOERROR;
117 }
118
119 /* Find the main ELF file for this module and open libelf on it.
120 When we return success, MOD->main.elf and MOD->main.bias are set up. */
121 static void
find_file(Dwfl_Module * mod)122 find_file (Dwfl_Module *mod)
123 {
124 if (mod->main.elf != NULL /* Already done. */
125 || mod->elferr != DWFL_E_NOERROR) /* Cached failure. */
126 return;
127
128 mod->main.fd = (*mod->dwfl->callbacks->find_elf) (MODCB_ARGS (mod),
129 &mod->main.name,
130 &mod->main.elf);
131 mod->elferr = open_elf (mod, &mod->main);
132
133 if (mod->elferr == DWFL_E_NOERROR && !mod->main.valid)
134 {
135 /* Clear any explicitly reported build ID, just in case it was wrong.
136 We'll fetch it from the file when asked. */
137 free (mod->build_id_bits);
138 mod->build_id_bits = NULL;
139 mod->build_id_len = 0;
140 }
141 }
142
143 /* Search an ELF file for a ".gnu_debuglink" section. */
144 static const char *
find_debuglink(Elf * elf,GElf_Word * crc)145 find_debuglink (Elf *elf, GElf_Word *crc)
146 {
147 size_t shstrndx;
148 if (elf_getshstrndx (elf, &shstrndx) < 0)
149 return NULL;
150
151 Elf_Scn *scn = NULL;
152 while ((scn = elf_nextscn (elf, scn)) != NULL)
153 {
154 GElf_Shdr shdr_mem;
155 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
156 if (shdr == NULL)
157 return NULL;
158
159 const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
160 if (name == NULL)
161 return NULL;
162
163 if (!strcmp (name, ".gnu_debuglink"))
164 break;
165 }
166
167 if (scn == NULL)
168 return NULL;
169
170 /* Found the .gnu_debuglink section. Extract its contents. */
171 Elf_Data *rawdata = elf_rawdata (scn, NULL);
172 if (rawdata == NULL)
173 return NULL;
174
175 Elf_Data crcdata =
176 {
177 .d_type = ELF_T_WORD,
178 .d_buf = crc,
179 .d_size = sizeof *crc,
180 .d_version = EV_CURRENT,
181 };
182 Elf_Data conv =
183 {
184 .d_type = ELF_T_WORD,
185 .d_buf = rawdata->d_buf + rawdata->d_size - sizeof *crc,
186 .d_size = sizeof *crc,
187 .d_version = EV_CURRENT,
188 };
189
190 GElf_Ehdr ehdr_mem;
191 GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
192 if (ehdr == NULL)
193 return NULL;
194
195 Elf_Data *d = gelf_xlatetom (elf, &crcdata, &conv, ehdr->e_ident[EI_DATA]);
196 if (d == NULL)
197 return NULL;
198 assert (d == &crcdata);
199
200 return rawdata->d_buf;
201 }
202
203
204 /* Find the separate debuginfo file for this module and open libelf on it.
205 When we return success, MOD->debug is set up. */
206 static Dwfl_Error
find_debuginfo(Dwfl_Module * mod)207 find_debuginfo (Dwfl_Module *mod)
208 {
209 if (mod->debug.elf != NULL)
210 return DWFL_E_NOERROR;
211
212 GElf_Word debuglink_crc = 0;
213 const char *debuglink_file = find_debuglink (mod->main.elf, &debuglink_crc);
214
215 mod->debug.fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod),
216 mod->main.name,
217 debuglink_file,
218 debuglink_crc,
219 &mod->debug.name);
220 return open_elf (mod, &mod->debug);
221 }
222
223
224 /* Try to find a symbol table in FILE.
225 Returns DWFL_E_NOERROR if a proper one is found.
226 Returns DWFL_E_NO_SYMTAB if not, but still sets results for SHT_DYNSYM. */
227 static Dwfl_Error
load_symtab(struct dwfl_file * file,struct dwfl_file ** symfile,Elf_Scn ** symscn,Elf_Scn ** xndxscn,size_t * syments,GElf_Word * strshndx)228 load_symtab (struct dwfl_file *file, struct dwfl_file **symfile,
229 Elf_Scn **symscn, Elf_Scn **xndxscn,
230 size_t *syments, GElf_Word *strshndx)
231 {
232 bool symtab = false;
233 Elf_Scn *scn = NULL;
234 while ((scn = elf_nextscn (file->elf, scn)) != NULL)
235 {
236 GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
237 if (shdr != NULL)
238 switch (shdr->sh_type)
239 {
240 case SHT_SYMTAB:
241 symtab = true;
242 *symscn = scn;
243 *symfile = file;
244 *strshndx = shdr->sh_link;
245 *syments = shdr->sh_size / shdr->sh_entsize;
246 if (*xndxscn != NULL)
247 return DWFL_E_NOERROR;
248 break;
249
250 case SHT_DYNSYM:
251 if (symtab)
252 break;
253 /* Use this if need be, but keep looking for SHT_SYMTAB. */
254 *symscn = scn;
255 *symfile = file;
256 *strshndx = shdr->sh_link;
257 *syments = shdr->sh_size / shdr->sh_entsize;
258 break;
259
260 case SHT_SYMTAB_SHNDX:
261 *xndxscn = scn;
262 if (symtab)
263 return DWFL_E_NOERROR;
264 break;
265
266 default:
267 break;
268 }
269 }
270
271 if (symtab)
272 /* We found one, though no SHT_SYMTAB_SHNDX to go with it. */
273 return DWFL_E_NOERROR;
274
275 /* We found no SHT_SYMTAB, so any SHT_SYMTAB_SHNDX was bogus.
276 We might have found an SHT_DYNSYM and set *SYMSCN et al though. */
277 *xndxscn = NULL;
278 return DWFL_E_NO_SYMTAB;
279 }
280
281
282 /* Translate addresses into file offsets.
283 OFFS[*] start out zero and remain zero if unresolved. */
284 static void
find_offsets(Elf * elf,const GElf_Ehdr * ehdr,size_t n,GElf_Addr addrs[n],GElf_Off offs[n])285 find_offsets (Elf *elf, const GElf_Ehdr *ehdr, size_t n,
286 GElf_Addr addrs[n], GElf_Off offs[n])
287 {
288 size_t unsolved = n;
289 for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
290 {
291 GElf_Phdr phdr_mem;
292 GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
293 if (phdr != NULL && phdr->p_type == PT_LOAD && phdr->p_memsz > 0)
294 for (size_t j = 0; j < n; ++j)
295 if (offs[j] == 0
296 && addrs[j] >= phdr->p_vaddr
297 && addrs[j] - phdr->p_vaddr < phdr->p_filesz)
298 {
299 offs[j] = addrs[j] - phdr->p_vaddr + phdr->p_offset;
300 if (--unsolved == 0)
301 break;
302 }
303 }
304 }
305
306 /* Try to find a dynamic symbol table via phdrs. */
307 static void
find_dynsym(Dwfl_Module * mod)308 find_dynsym (Dwfl_Module *mod)
309 {
310 GElf_Ehdr ehdr_mem;
311 GElf_Ehdr *ehdr = gelf_getehdr (mod->main.elf, &ehdr_mem);
312
313 for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
314 {
315 GElf_Phdr phdr_mem;
316 GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem);
317 if (phdr == NULL)
318 break;
319
320 if (phdr->p_type == PT_DYNAMIC)
321 {
322 /* Examine the dynamic section for the pointers we need. */
323
324 Elf_Data *data = elf_getdata_rawchunk (mod->main.elf,
325 phdr->p_offset, phdr->p_filesz,
326 ELF_T_DYN);
327 if (data == NULL)
328 continue;
329
330 enum
331 {
332 i_symtab,
333 i_strtab,
334 i_hash,
335 i_gnu_hash,
336 i_max
337 };
338 GElf_Addr addrs[i_max] = { 0, };
339 GElf_Xword strsz = 0;
340 size_t n = data->d_size / gelf_fsize (mod->main.elf,
341 ELF_T_DYN, 1, EV_CURRENT);
342 for (size_t j = 0; j < n; ++j)
343 {
344 GElf_Dyn dyn_mem;
345 GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
346 if (dyn != NULL)
347 switch (dyn->d_tag)
348 {
349 case DT_SYMTAB:
350 addrs[i_symtab] = dyn->d_un.d_ptr;
351 continue;
352
353 case DT_HASH:
354 addrs[i_hash] = dyn->d_un.d_ptr;
355 continue;
356
357 case DT_GNU_HASH:
358 addrs[i_gnu_hash] = dyn->d_un.d_ptr;
359 continue;
360
361 case DT_STRTAB:
362 addrs[i_strtab] = dyn->d_un.d_ptr;
363 continue;
364
365 case DT_STRSZ:
366 strsz = dyn->d_un.d_val;
367 continue;
368
369 default:
370 continue;
371
372 case DT_NULL:
373 break;
374 }
375 break;
376 }
377
378 /* Translate pointers into file offsets. */
379 GElf_Off offs[i_max] = { 0, };
380 find_offsets (mod->main.elf, ehdr, i_max, addrs, offs);
381
382 /* Figure out the size of the symbol table. */
383 if (offs[i_hash] != 0)
384 {
385 /* In the original format, .hash says the size of .dynsym. */
386
387 size_t entsz = SH_ENTSIZE_HASH (ehdr);
388 data = elf_getdata_rawchunk (mod->main.elf,
389 offs[i_hash] + entsz, entsz,
390 entsz == 4 ? ELF_T_WORD
391 : ELF_T_XWORD);
392 if (data != NULL)
393 mod->syments = (entsz == 4
394 ? *(const GElf_Word *) data->d_buf
395 : *(const GElf_Xword *) data->d_buf);
396 }
397 if (offs[i_gnu_hash] != 0 && mod->syments == 0)
398 {
399 /* In the new format, we can derive it with some work. */
400
401 const struct
402 {
403 Elf32_Word nbuckets;
404 Elf32_Word symndx;
405 Elf32_Word maskwords;
406 Elf32_Word shift2;
407 } *header;
408
409 data = elf_getdata_rawchunk (mod->main.elf, offs[i_gnu_hash],
410 sizeof *header, ELF_T_WORD);
411 if (data != NULL)
412 {
413 header = data->d_buf;
414 Elf32_Word nbuckets = header->nbuckets;
415 Elf32_Word symndx = header->symndx;
416 GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header
417 + (gelf_getclass (mod->main.elf)
418 * sizeof (Elf32_Word)
419 * header->maskwords));
420
421 data = elf_getdata_rawchunk (mod->main.elf, buckets_at,
422 nbuckets * sizeof (Elf32_Word),
423 ELF_T_WORD);
424 if (data != NULL && symndx < nbuckets)
425 {
426 const Elf32_Word *const buckets = data->d_buf;
427 Elf32_Word maxndx = symndx;
428 for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket)
429 if (buckets[bucket] > maxndx)
430 maxndx = buckets[bucket];
431
432 GElf_Off hasharr_at = (buckets_at
433 + nbuckets * sizeof (Elf32_Word));
434 hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word);
435 do
436 {
437 data = elf_getdata_rawchunk (mod->main.elf,
438 hasharr_at,
439 sizeof (Elf32_Word),
440 ELF_T_WORD);
441 if (data != NULL
442 && (*(const Elf32_Word *) data->d_buf & 1u))
443 {
444 mod->syments = maxndx + 1;
445 break;
446 }
447 ++maxndx;
448 hasharr_at += sizeof (Elf32_Word);
449 } while (data != NULL);
450 }
451 }
452 }
453 if (offs[i_strtab] > offs[i_symtab] && mod->syments == 0)
454 mod->syments = ((offs[i_strtab] - offs[i_symtab])
455 / gelf_fsize (mod->main.elf,
456 ELF_T_SYM, 1, EV_CURRENT));
457
458 if (mod->syments > 0)
459 {
460 mod->symdata = elf_getdata_rawchunk (mod->main.elf,
461 offs[i_symtab],
462 gelf_fsize (mod->main.elf,
463 ELF_T_SYM,
464 mod->syments,
465 EV_CURRENT),
466 ELF_T_SYM);
467 if (mod->symdata != NULL)
468 {
469 mod->symstrdata = elf_getdata_rawchunk (mod->main.elf,
470 offs[i_strtab],
471 strsz,
472 ELF_T_BYTE);
473 if (mod->symstrdata == NULL)
474 mod->symdata = NULL;
475 }
476 if (mod->symdata == NULL)
477 mod->symerr = DWFL_E (LIBELF, elf_errno ());
478 else
479 {
480 mod->symfile = &mod->main;
481 mod->symerr = DWFL_E_NOERROR;
482 }
483 return;
484 }
485 }
486 }
487 }
488
489 /* Try to find a symbol table in either MOD->main.elf or MOD->debug.elf. */
490 static void
find_symtab(Dwfl_Module * mod)491 find_symtab (Dwfl_Module *mod)
492 {
493 if (mod->symdata != NULL /* Already done. */
494 || mod->symerr != DWFL_E_NOERROR) /* Cached previous failure. */
495 return;
496
497 find_file (mod);
498 mod->symerr = mod->elferr;
499 if (mod->symerr != DWFL_E_NOERROR)
500 return;
501
502 /* First see if the main ELF file has the debugging information. */
503 Elf_Scn *symscn = NULL, *xndxscn = NULL;
504 GElf_Word strshndx = 0;
505 mod->symerr = load_symtab (&mod->main, &mod->symfile, &symscn,
506 &xndxscn, &mod->syments, &strshndx);
507 switch (mod->symerr)
508 {
509 default:
510 return;
511
512 case DWFL_E_NOERROR:
513 break;
514
515 case DWFL_E_NO_SYMTAB:
516 /* Now we have to look for a separate debuginfo file. */
517 mod->symerr = find_debuginfo (mod);
518 switch (mod->symerr)
519 {
520 default:
521 return;
522
523 case DWFL_E_NOERROR:
524 mod->symerr = load_symtab (&mod->debug, &mod->symfile, &symscn,
525 &xndxscn, &mod->syments, &strshndx);
526 break;
527
528 case DWFL_E_CB: /* The find_debuginfo hook failed. */
529 mod->symerr = DWFL_E_NO_SYMTAB;
530 break;
531 }
532
533 switch (mod->symerr)
534 {
535 default:
536 return;
537
538 case DWFL_E_NOERROR:
539 break;
540
541 case DWFL_E_NO_SYMTAB:
542 if (symscn != NULL)
543 {
544 /* We still have the dynamic symbol table. */
545 mod->symerr = DWFL_E_NOERROR;
546 break;
547 }
548
549 /* Last ditch, look for dynamic symbols without section headers. */
550 find_dynsym (mod);
551 return;
552 }
553 break;
554 }
555
556 /* This does some sanity checks on the string table section. */
557 if (elf_strptr (mod->symfile->elf, strshndx, 0) == NULL)
558 {
559 elferr:
560 mod->symerr = DWFL_E (LIBELF, elf_errno ());
561 return;
562 }
563
564 /* Cache the data; MOD->syments was set above. */
565
566 mod->symstrdata = elf_getdata (elf_getscn (mod->symfile->elf, strshndx),
567 NULL);
568 if (mod->symstrdata == NULL)
569 goto elferr;
570
571 if (xndxscn == NULL)
572 mod->symxndxdata = NULL;
573 else
574 {
575 mod->symxndxdata = elf_getdata (xndxscn, NULL);
576 if (mod->symxndxdata == NULL)
577 goto elferr;
578 }
579
580 mod->symdata = elf_getdata (symscn, NULL);
581 if (mod->symdata == NULL)
582 goto elferr;
583 }
584
585
586 /* Try to open a libebl backend for MOD. */
587 Dwfl_Error
588 internal_function
__libdwfl_module_getebl(Dwfl_Module * mod)589 __libdwfl_module_getebl (Dwfl_Module *mod)
590 {
591 if (mod->ebl == NULL)
592 {
593 find_file (mod);
594 if (mod->elferr != DWFL_E_NOERROR)
595 return mod->elferr;
596
597 mod->ebl = ebl_openbackend (mod->main.elf);
598 if (mod->ebl == NULL)
599 return DWFL_E_LIBEBL;
600 }
601 return DWFL_E_NOERROR;
602 }
603
604 /* Try to start up libdw on DEBUGFILE. */
605 static Dwfl_Error
load_dw(Dwfl_Module * mod,struct dwfl_file * debugfile)606 load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile)
607 {
608 if (mod->e_type == ET_REL && !debugfile->relocated)
609 {
610 const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
611
612 /* The debugging sections have to be relocated. */
613 if (cb->section_address == NULL)
614 return DWFL_E_NOREL;
615
616 Dwfl_Error error = __libdwfl_module_getebl (mod);
617 if (error != DWFL_E_NOERROR)
618 return error;
619
620 find_symtab (mod);
621 Dwfl_Error result = mod->symerr;
622 if (result == DWFL_E_NOERROR)
623 result = __libdwfl_relocate (mod, debugfile->elf, true);
624 if (result != DWFL_E_NOERROR)
625 return result;
626
627 /* Don't keep the file descriptors around. */
628 if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
629 {
630 close (mod->main.fd);
631 mod->main.fd = -1;
632 }
633 if (debugfile->fd != -1 && elf_cntl (debugfile->elf, ELF_C_FDREAD) == 0)
634 {
635 close (debugfile->fd);
636 debugfile->fd = -1;
637 }
638 }
639
640 mod->dw = INTUSE(dwarf_begin_elf) (debugfile->elf, DWARF_C_READ, NULL);
641 if (mod->dw == NULL)
642 {
643 int err = INTUSE(dwarf_errno) ();
644 return err == DWARF_E_NO_DWARF ? DWFL_E_NO_DWARF : DWFL_E (LIBDW, err);
645 }
646
647 /* Until we have iterated through all CU's, we might do lazy lookups. */
648 mod->lazycu = 1;
649
650 return DWFL_E_NOERROR;
651 }
652
653 /* Try to start up libdw on either the main file or the debuginfo file. */
654 static void
find_dw(Dwfl_Module * mod)655 find_dw (Dwfl_Module *mod)
656 {
657 if (mod->dw != NULL /* Already done. */
658 || mod->dwerr != DWFL_E_NOERROR) /* Cached previous failure. */
659 return;
660
661 find_file (mod);
662 mod->dwerr = mod->elferr;
663 if (mod->dwerr != DWFL_E_NOERROR)
664 return;
665
666 /* First see if the main ELF file has the debugging information. */
667 mod->dwerr = load_dw (mod, &mod->main);
668 switch (mod->dwerr)
669 {
670 case DWFL_E_NOERROR:
671 mod->debug.elf = mod->main.elf;
672 mod->debug.bias = mod->main.bias;
673 return;
674
675 case DWFL_E_NO_DWARF:
676 break;
677
678 default:
679 goto canonicalize;
680 }
681
682 /* Now we have to look for a separate debuginfo file. */
683 mod->dwerr = find_debuginfo (mod);
684 switch (mod->dwerr)
685 {
686 case DWFL_E_NOERROR:
687 mod->dwerr = load_dw (mod, &mod->debug);
688 break;
689
690 case DWFL_E_CB: /* The find_debuginfo hook failed. */
691 mod->dwerr = DWFL_E_NO_DWARF;
692 return;
693
694 default:
695 break;
696 }
697
698 canonicalize:
699 mod->dwerr = __libdwfl_canon_error (mod->dwerr);
700 }
701
702
703 Elf *
dwfl_module_getelf(Dwfl_Module * mod,GElf_Addr * loadbase)704 dwfl_module_getelf (Dwfl_Module *mod, GElf_Addr *loadbase)
705 {
706 if (mod == NULL)
707 return NULL;
708
709 find_file (mod);
710 if (mod->elferr == DWFL_E_NOERROR)
711 {
712 if (mod->e_type == ET_REL && ! mod->main.relocated)
713 {
714 /* Before letting them get at the Elf handle,
715 apply all the relocations we know how to. */
716
717 mod->main.relocated = true;
718 if (likely (__libdwfl_module_getebl (mod) == DWFL_E_NOERROR))
719 {
720 (void) __libdwfl_relocate (mod, mod->main.elf, false);
721
722 if (mod->debug.elf == mod->main.elf)
723 mod->debug.relocated = true;
724 else if (mod->debug.elf != NULL && ! mod->debug.relocated)
725 {
726 mod->debug.relocated = true;
727 (void) __libdwfl_relocate (mod, mod->debug.elf, false);
728 }
729 }
730 }
731
732 *loadbase = mod->main.bias;
733 return mod->main.elf;
734 }
735
736 __libdwfl_seterrno (mod->elferr);
737 return NULL;
738 }
INTDEF(dwfl_module_getelf)739 INTDEF (dwfl_module_getelf)
740
741
742 Dwarf *
743 dwfl_module_getdwarf (Dwfl_Module *mod, Dwarf_Addr *bias)
744 {
745 if (mod == NULL)
746 return NULL;
747
748 find_dw (mod);
749 if (mod->dwerr == DWFL_E_NOERROR)
750 {
751 /* If dwfl_module_getelf was used previously, then partial apply
752 relocation to miscellaneous sections in the debug file too. */
753 if (mod->e_type == ET_REL
754 && mod->main.relocated && ! mod->debug.relocated)
755 {
756 mod->debug.relocated = true;
757 if (mod->debug.elf != mod->main.elf)
758 (void) __libdwfl_relocate (mod, mod->debug.elf, false);
759 }
760
761 *bias = mod->debug.bias;
762 return mod->dw;
763 }
764
765 __libdwfl_seterrno (mod->dwerr);
766 return NULL;
767 }
INTDEF(dwfl_module_getdwarf)768 INTDEF (dwfl_module_getdwarf)
769
770 int
771 dwfl_module_getsymtab (Dwfl_Module *mod)
772 {
773 if (mod == NULL)
774 return -1;
775
776 find_symtab (mod);
777 if (mod->symerr == DWFL_E_NOERROR)
778 return mod->syments;
779
780 __libdwfl_seterrno (mod->symerr);
781 return -1;
782 }
783 INTDEF (dwfl_module_getsymtab)
784