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.  */
58static inline Dwfl_Error
59open_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.  */
121static void
122find_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.  */
144static const char *
145find_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.  */
206static Dwfl_Error
207find_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.  */
227static Dwfl_Error
228load_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.  */
284static void
285find_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.  */
307static void
308find_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.  */
490static void
491find_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.  */
587Dwfl_Error
588internal_function
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.  */
605static Dwfl_Error
606load_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.  */
654static void
655find_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
703Elf *
704dwfl_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}
739INTDEF (dwfl_module_getelf)
740
741
742Dwarf *
743dwfl_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}
768INTDEF (dwfl_module_getdwarf)
769
770int
771dwfl_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}
783INTDEF (dwfl_module_getsymtab)
784