Home | History | Annotate | Download | only in libdwfl
      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
     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
    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 *
    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
    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
    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
    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
    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
    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;
    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
    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
    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
    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 *
    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 }
    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 }
    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