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