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