LCOV - code coverage report
Current view: top level - libdwfl - dwfl_module_getdwarf.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 466 564 82.6 %
Date: 2017-01-05 09:15:16 Functions: 19 20 95.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Find debugging and symbol information for a module in libdwfl.
       2             :    Copyright (C) 2005-2012, 2014, 2015 Red Hat, Inc.
       3             :    This file is part of elfutils.
       4             : 
       5             :    This file is free software; you can redistribute it and/or modify
       6             :    it under the terms of either
       7             : 
       8             :      * the GNU Lesser General Public License as published by the Free
       9             :        Software Foundation; either version 3 of the License, or (at
      10             :        your option) any later version
      11             : 
      12             :    or
      13             : 
      14             :      * the GNU General Public License as published by the Free
      15             :        Software Foundation; either version 2 of the License, or (at
      16             :        your option) any later version
      17             : 
      18             :    or both in parallel, as here.
      19             : 
      20             :    elfutils is distributed in the hope that it will be useful, but
      21             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      22             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      23             :    General Public License for more details.
      24             : 
      25             :    You should have received copies of the GNU General Public License and
      26             :    the GNU Lesser General Public License along with this program.  If
      27             :    not, see <http://www.gnu.org/licenses/>.  */
      28             : 
      29             : #include "libdwflP.h"
      30             : #include <inttypes.h>
      31             : #include <fcntl.h>
      32             : #include <string.h>
      33             : #include <unistd.h>
      34             : #include "../libdw/libdwP.h"  /* DWARF_E_* values are here.  */
      35             : #include "../libelf/libelfP.h"
      36             : 
      37             : static inline Dwfl_Error
      38        5196 : open_elf_file (Elf **elf, int *fd, char **name)
      39             : {
      40        5196 :   if (*elf == NULL)
      41             :     {
      42             :       /* CBFAIL uses errno if it's set, so clear it first in case we don't
      43             :          set it with an open failure below.  */
      44        5142 :       errno = 0;
      45             : 
      46             :       /* If there was a pre-primed file name left that the callback left
      47             :          behind, try to open that file name.  */
      48        5142 :       if (*fd < 0 && *name != NULL)
      49           0 :         *fd = TEMP_FAILURE_RETRY (open (*name, O_RDONLY));
      50             : 
      51        5142 :       if (*fd < 0)
      52          95 :         return CBFAIL;
      53             : 
      54        5047 :       return __libdw_open_file (fd, elf, true, false);
      55             :     }
      56          54 :   else if (unlikely (elf_kind (*elf) != ELF_K_ELF))
      57             :     {
      58           0 :       elf_end (*elf);
      59           0 :       *elf = NULL;
      60           0 :       close (*fd);
      61           0 :       *fd = -1;
      62           0 :       return DWFL_E_BADELF;
      63             :     }
      64             : 
      65             :   /* Elf file already open and looks fine.  */
      66             :   return DWFL_E_NOERROR;
      67             : }
      68             : 
      69             : /* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD.
      70             :    When we return success, FILE->elf and FILE->vaddr are set up.  */
      71             : static inline Dwfl_Error
      72        5190 : open_elf (Dwfl_Module *mod, struct dwfl_file *file)
      73             : {
      74        5190 :   Dwfl_Error error = open_elf_file (&file->elf, &file->fd, &file->name);
      75        5190 :   if (error != DWFL_E_NOERROR)
      76             :     return error;
      77             : 
      78        5095 :   GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (file->elf, &ehdr_mem);
      79        5095 :   if (ehdr == NULL)
      80             :     {
      81             :     elf_error:
      82           0 :       elf_end (file->elf);
      83           0 :       file->elf = NULL;
      84           0 :       close (file->fd);
      85           0 :       file->fd = -1;
      86           0 :       return DWFL_E (LIBELF, elf_errno ());
      87             :     }
      88             : 
      89        5095 :   if (ehdr->e_type != ET_REL)
      90             :     {
      91             :       /* In any non-ET_REL file, we compute the "synchronization address".
      92             : 
      93             :          We start with the address at the end of the first PT_LOAD
      94             :          segment.  When prelink converts REL to RELA in an ET_DYN
      95             :          file, it expands the space between the beginning of the
      96             :          segment and the actual code/data addresses.  Since that
      97             :          change wasn't made in the debug file, the distance from
      98             :          p_vaddr to an address of interest (in an st_value or DWARF
      99             :          data) now differs between the main and debug files.  The
     100             :          distance from address_sync to an address of interest remains
     101             :          consistent.
     102             : 
     103             :          If there are no section headers at all (full stripping), then
     104             :          the end of the first segment is a valid synchronization address.
     105             :          This cannot happen in a prelinked file, since prelink itself
     106             :          relies on section headers for prelinking and for undoing it.
     107             :          (If you do full stripping on a prelinked file, then you get what
     108             :          you deserve--you can neither undo the prelinking, nor expect to
     109             :          line it up with a debug file separated before prelinking.)
     110             : 
     111             :          However, when prelink processes an ET_EXEC file, it can do
     112             :          something different.  There it juggles the "special" sections
     113             :          (SHT_DYNSYM et al) to make space for the additional prelink
     114             :          special sections.  Sometimes it will do this by moving a special
     115             :          section like .dynstr after the real program sections in the first
     116             :          PT_LOAD segment--i.e. to the end.  That changes the end address of
     117             :          the segment, so it no longer lines up correctly and is not a valid
     118             :          synchronization address to use.  Because of this, we need to apply
     119             :          a different prelink-savvy means to discover the synchronization
     120             :          address when there is a separate debug file and a prelinked main
     121             :          file.  That is done in find_debuginfo, below.  */
     122             : 
     123             :       size_t phnum;
     124        5094 :       if (unlikely (elf_getphdrnum (file->elf, &phnum) != 0))
     125             :         goto elf_error;
     126             : 
     127        5094 :       file->vaddr = file->address_sync = 0;
     128       15190 :       for (size_t i = 0; i < phnum; ++i)
     129             :         {
     130             :           GElf_Phdr ph_mem;
     131       15190 :           GElf_Phdr *ph = gelf_getphdr (file->elf, i, &ph_mem);
     132       15190 :           if (unlikely (ph == NULL))
     133             :             goto elf_error;
     134       15190 :           if (ph->p_type == PT_LOAD)
     135             :             {
     136        5094 :               file->vaddr = ph->p_vaddr & -ph->p_align;
     137        5094 :               file->address_sync = ph->p_vaddr + ph->p_memsz;
     138        5094 :               break;
     139             :             }
     140             :         }
     141             :     }
     142             : 
     143             :   /* We only want to set the module e_type explictly once, derived from
     144             :      the main ELF file.  (It might be changed for the kernel, because
     145             :      that is special - see below.)  open_elf is always called first for
     146             :      the main ELF file, because both find_dw and find_symtab call
     147             :      __libdwfl_getelf first to open the main file.  So don't let debug
     148             :      or aux files override the module e_type.  The kernel heuristic
     149             :      below could otherwise trigger for non-kernel/non-main files, since
     150             :      their phdrs might not match the actual load addresses.  */
     151        5095 :   if (file == &mod->main)
     152             :     {
     153        5051 :       mod->e_type = ehdr->e_type;
     154             : 
     155             :       /* Relocatable Linux kernels are ET_EXEC but act like ET_DYN.  */
     156        5051 :       if (mod->e_type == ET_EXEC && file->vaddr != mod->low_addr)
     157           0 :         mod->e_type = ET_DYN;
     158             :     }
     159             :   else
     160          44 :     assert (mod->main.elf != NULL);
     161             : 
     162             :   return DWFL_E_NOERROR;
     163             : }
     164             : 
     165             : /* We have an authoritative build ID for this module MOD, so don't use
     166             :    a file by name that doesn't match that ID.  */
     167             : static void
     168           0 : mod_verify_build_id (Dwfl_Module *mod)
     169             : {
     170           0 :   assert (mod->build_id_len > 0);
     171             : 
     172           0 :   switch (__builtin_expect (__libdwfl_find_build_id (mod, false,
     173             :                                                      mod->main.elf), 2))
     174             :     {
     175             :     case 2:
     176             :       /* Build ID matches as it should. */
     177             :       return;
     178             : 
     179             :     case -1:                    /* ELF error.  */
     180           0 :       mod->elferr = INTUSE(dwfl_errno) ();
     181           0 :       break;
     182             : 
     183             :     case 0:                     /* File has no build ID note.  */
     184             :     case 1:                     /* FIle has a build ID that does not match.  */
     185           0 :       mod->elferr = DWFL_E_WRONG_ID_ELF;
     186           0 :       break;
     187             : 
     188             :     default:
     189           0 :       abort ();
     190             :     }
     191             : 
     192             :   /* We get here when it was the right ELF file.  Clear it out.  */
     193           0 :   elf_end (mod->main.elf);
     194           0 :   mod->main.elf = NULL;
     195           0 :   if (mod->main.fd >= 0)
     196             :     {
     197           0 :       close (mod->main.fd);
     198           0 :       mod->main.fd = -1;
     199             :     }
     200             : }
     201             : 
     202             : /* Find the main ELF file for this module and open libelf on it.
     203             :    When we return success, MOD->main.elf and MOD->main.bias are set up.  */
     204             : void
     205             : internal_function
     206        6073 : __libdwfl_getelf (Dwfl_Module *mod)
     207             : {
     208        6073 :   if (mod->main.elf != NULL  /* Already done.  */
     209        5087 :       || mod->elferr != DWFL_E_NOERROR)      /* Cached failure.  */
     210             :     return;
     211             : 
     212        5067 :   mod->main.fd = (*mod->dwfl->callbacks->find_elf) (MODCB_ARGS (mod),
     213             :                                                     &mod->main.name,
     214             :                                                     &mod->main.elf);
     215        5067 :   const bool fallback = mod->main.elf == NULL && mod->main.fd < 0;
     216        5067 :   mod->elferr = open_elf (mod, &mod->main);
     217        5067 :   if (mod->elferr != DWFL_E_NOERROR)
     218             :     return;
     219             : 
     220        5051 :   if (!mod->main.valid)
     221             :     {
     222             :       /* Clear any explicitly reported build ID, just in case it was wrong.
     223             :          We'll fetch it from the file when asked.  */
     224        5051 :       free (mod->build_id_bits);
     225        5051 :       mod->build_id_bits = NULL;
     226        5051 :       mod->build_id_len = 0;
     227             :     }
     228           0 :   else if (fallback)
     229           0 :     mod_verify_build_id (mod);
     230             : 
     231        5051 :   mod->main_bias = mod->e_type == ET_REL ? 0 : mod->low_addr - mod->main.vaddr;
     232             : }
     233             : 
     234             : static inline void
     235             : consider_shdr (GElf_Addr interp,
     236             :                GElf_Word sh_type,
     237             :                GElf_Xword sh_flags,
     238             :                GElf_Addr sh_addr,
     239             :                GElf_Xword sh_size,
     240             :                GElf_Addr *phighest)
     241             : {
     242         640 :   if ((sh_flags & SHF_ALLOC)
     243         548 :       && ((sh_type == SHT_PROGBITS && sh_addr != interp)
     244         288 :           || sh_type == SHT_NOBITS))
     245             :     {
     246         280 :       const GElf_Addr sh_end = sh_addr + sh_size;
     247         280 :       if (sh_end > *phighest)
     248         280 :         *phighest = sh_end;
     249             :     }
     250             : }
     251             : 
     252             : /* If the main file might have been prelinked, then we need to
     253             :    discover the correct synchronization address between the main and
     254             :    debug files.  Because of prelink's section juggling, we cannot rely
     255             :    on the address_sync computed from PT_LOAD segments (see open_elf).
     256             : 
     257             :    We will attempt to discover a synchronization address based on the
     258             :    section headers instead.  But finding a section address that is
     259             :    safe to use requires identifying which sections are SHT_PROGBITS.
     260             :    We can do that in the main file, but in the debug file all the
     261             :    allocated sections have been transformed into SHT_NOBITS so we have
     262             :    lost the means to match them up correctly.
     263             : 
     264             :    The only method left to us is to decode the .gnu.prelink_undo
     265             :    section in the prelinked main file.  This shows what the sections
     266             :    looked like before prelink juggled them--when they still had a
     267             :    direct correspondence to the debug file.  */
     268             : static Dwfl_Error
     269          43 : find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
     270             : {
     271             :   /* The magic section is only identified by name.  */
     272             :   size_t shstrndx;
     273          43 :   if (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0)
     274             :     return DWFL_E_LIBELF;
     275             : 
     276             :   Elf_Scn *scn = NULL;
     277        1255 :   while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
     278             :     {
     279             :       GElf_Shdr shdr_mem;
     280        1224 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
     281        1224 :       if (unlikely (shdr == NULL))
     282           0 :         return DWFL_E_LIBELF;
     283        1224 :       if (shdr->sh_type == SHT_PROGBITS
     284         676 :           && !(shdr->sh_flags & SHF_ALLOC)
     285         183 :           && shdr->sh_name != 0)
     286             :         {
     287         183 :           const char *secname = elf_strptr (mod->main.elf, shstrndx,
     288             :                                             shdr->sh_name);
     289         183 :           if (unlikely (secname == NULL))
     290             :             return DWFL_E_LIBELF;
     291         183 :           if (!strcmp (secname, ".gnu.prelink_undo"))
     292             :             break;
     293             :         }
     294             :     }
     295             : 
     296          43 :   if (scn == NULL)
     297             :     /* There was no .gnu.prelink_undo section.  */
     298             :     return DWFL_E_NOERROR;
     299             : 
     300          12 :   Elf_Data *undodata = elf_rawdata (scn, NULL);
     301          12 :   if (unlikely (undodata == NULL))
     302             :     return DWFL_E_LIBELF;
     303             : 
     304             :   /* Decode the section.  It consists of the original ehdr, phdrs,
     305             :      and shdrs (but omits section 0).  */
     306             : 
     307             :   union
     308             :   {
     309             :     Elf32_Ehdr e32;
     310             :     Elf64_Ehdr e64;
     311             :   } ehdr;
     312          12 :   Elf_Data dst =
     313             :     {
     314             :       .d_buf = &ehdr,
     315             :       .d_size = sizeof ehdr,
     316             :       .d_type = ELF_T_EHDR,
     317             :       .d_version = EV_CURRENT
     318             :     };
     319          12 :   Elf_Data src = *undodata;
     320          12 :   src.d_size = gelf_fsize (mod->main.elf, ELF_T_EHDR, 1, EV_CURRENT);
     321          12 :   src.d_type = ELF_T_EHDR;
     322          12 :   if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
     323             :                                elf_getident (mod->main.elf, NULL)[EI_DATA])
     324             :                 == NULL))
     325             :     return DWFL_E_LIBELF;
     326             : 
     327          12 :   size_t shentsize = gelf_fsize (mod->main.elf, ELF_T_SHDR, 1, EV_CURRENT);
     328          12 :   size_t phentsize = gelf_fsize (mod->main.elf, ELF_T_PHDR, 1, EV_CURRENT);
     329             : 
     330             :   uint_fast16_t phnum;
     331             :   uint_fast16_t shnum;
     332          12 :   if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
     333             :     {
     334           4 :       if (ehdr.e32.e_shentsize != shentsize
     335           4 :           || ehdr.e32.e_phentsize != phentsize)
     336             :         return DWFL_E_BAD_PRELINK;
     337           4 :       phnum = ehdr.e32.e_phnum;
     338           4 :       shnum = ehdr.e32.e_shnum;
     339             :     }
     340             :   else
     341             :     {
     342           8 :       if (ehdr.e64.e_shentsize != shentsize
     343           8 :           || ehdr.e64.e_phentsize != phentsize)
     344             :         return DWFL_E_BAD_PRELINK;
     345           8 :       phnum = ehdr.e64.e_phnum;
     346           8 :       shnum = ehdr.e64.e_shnum;
     347             :     }
     348             : 
     349             :   /* Since prelink does not store the zeroth section header in the undo
     350             :      section, it cannot support SHN_XINDEX encoding.  */
     351          12 :   if (unlikely (shnum >= SHN_LORESERVE)
     352          12 :       || unlikely (undodata->d_size != (src.d_size
     353             :                                         + phnum * phentsize
     354             :                                         + (shnum - 1) * shentsize)))
     355             :     return DWFL_E_BAD_PRELINK;
     356             : 
     357             :   /* We look at the allocated SHT_PROGBITS (or SHT_NOBITS) sections.  (Most
     358             :      every file will have some SHT_PROGBITS sections, but it's possible to
     359             :      have one with nothing but .bss, i.e. SHT_NOBITS.)  The special sections
     360             :      that can be moved around have different sh_type values--except for
     361             :      .interp, the section that became the PT_INTERP segment.  So we exclude
     362             :      the SHT_PROGBITS section whose address matches the PT_INTERP p_vaddr.
     363             :      For this reason, we must examine the phdrs first to find PT_INTERP.  */
     364             : 
     365          12 :   GElf_Addr main_interp = 0;
     366             :   {
     367             :     size_t main_phnum;
     368          12 :     if (unlikely (elf_getphdrnum (mod->main.elf, &main_phnum)))
     369           0 :       return DWFL_E_LIBELF;
     370          29 :     for (size_t i = 0; i < main_phnum; ++i)
     371             :       {
     372             :         GElf_Phdr phdr;
     373          37 :         if (unlikely (gelf_getphdr (mod->main.elf, i, &phdr) == NULL))
     374           0 :           return DWFL_E_LIBELF;
     375          37 :         if (phdr.p_type == PT_INTERP)
     376             :           {
     377           8 :             main_interp = phdr.p_vaddr;
     378           8 :             break;
     379             :           }
     380             :       }
     381             :   }
     382             : 
     383          12 :   src.d_buf += src.d_size;
     384          12 :   src.d_type = ELF_T_PHDR;
     385          12 :   src.d_size = phnum * phentsize;
     386             : 
     387          12 :   GElf_Addr undo_interp = 0;
     388          12 :   bool class32 = ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32;
     389             :   {
     390          24 :     size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr);
     391          12 :     if (unlikely (phnum > SIZE_MAX / phdr_size))
     392             :       return DWFL_E_NOMEM;
     393          12 :     const size_t phdrs_bytes = phnum * phdr_size;
     394          12 :     void *phdrs = malloc (phdrs_bytes);
     395          12 :     if (unlikely (phdrs == NULL))
     396             :       return DWFL_E_NOMEM;
     397          12 :     dst.d_buf = phdrs;
     398          12 :     dst.d_size = phdrs_bytes;
     399          12 :     if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
     400             :                                  ehdr.e32.e_ident[EI_DATA]) == NULL))
     401             :       {
     402           0 :         free (phdrs);
     403             :         return DWFL_E_LIBELF;
     404             :       }
     405          12 :     if (class32)
     406             :       {
     407             :         Elf32_Phdr (*p32)[phnum] = phdrs;
     408          12 :         for (uint_fast16_t i = 0; i < phnum; ++i)
     409          14 :           if ((*p32)[i].p_type == PT_INTERP)
     410             :             {
     411           2 :               undo_interp = (*p32)[i].p_vaddr;
     412             :               break;
     413             :             }
     414             :       }
     415             :     else
     416             :       {
     417             :         Elf64_Phdr (*p64)[phnum] = phdrs;
     418          17 :         for (uint_fast16_t i = 0; i < phnum; ++i)
     419          23 :           if ((*p64)[i].p_type == PT_INTERP)
     420             :             {
     421           6 :               undo_interp = (*p64)[i].p_vaddr;
     422             :               break;
     423             :             }
     424             :       }
     425          12 :     free (phdrs);
     426             :   }
     427             : 
     428          12 :   if (unlikely ((main_interp == 0) != (undo_interp == 0)))
     429             :     return DWFL_E_BAD_PRELINK;
     430             : 
     431          12 :   src.d_buf += src.d_size;
     432          12 :   src.d_type = ELF_T_SHDR;
     433          12 :   src.d_size = gelf_fsize (mod->main.elf, ELF_T_SHDR, shnum - 1, EV_CURRENT);
     434             : 
     435          12 :   size_t shdr_size = class32 ? sizeof (Elf32_Shdr) : sizeof (Elf64_Shdr);
     436          12 :   if (unlikely (shnum - 1  > SIZE_MAX / shdr_size))
     437             :     return DWFL_E_NOMEM;
     438          12 :   const size_t shdrs_bytes = (shnum - 1) * shdr_size;
     439          12 :   void *shdrs = malloc (shdrs_bytes);
     440          12 :   if (unlikely (shdrs == NULL))
     441             :     return DWFL_E_NOMEM;
     442          12 :   dst.d_buf = shdrs;
     443          12 :   dst.d_size = shdrs_bytes;
     444          12 :   if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
     445             :                                ehdr.e32.e_ident[EI_DATA]) == NULL))
     446             :     {
     447           0 :       free (shdrs);
     448             :       return DWFL_E_LIBELF;
     449             :     }
     450             : 
     451             :   /* Now we can look at the original section headers of the main file
     452             :      before it was prelinked.  First we'll apply our method to the main
     453             :      file sections as they are after prelinking, to calculate the
     454             :      synchronization address of the main file.  Then we'll apply that
     455             :      same method to the saved section headers, to calculate the matching
     456             :      synchronization address of the debug file.
     457             : 
     458             :      The method is to consider SHF_ALLOC sections that are either
     459             :      SHT_PROGBITS or SHT_NOBITS, excluding the section whose sh_addr
     460             :      matches the PT_INTERP p_vaddr.  The special sections that can be
     461             :      moved by prelink have other types, except for .interp (which
     462             :      becomes PT_INTERP).  The "real" sections cannot move as such, but
     463             :      .bss can be split into .dynbss and .bss, with the total memory
     464             :      image remaining the same but being spread across the two sections.
     465             :      So we consider the highest section end, which still matches up.  */
     466             : 
     467             :   GElf_Addr highest;
     468             : 
     469             :   highest = 0;
     470             :   scn = NULL;
     471         351 :   while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
     472             :     {
     473             :       GElf_Shdr sh_mem;
     474         339 :       GElf_Shdr *sh = gelf_getshdr (scn, &sh_mem);
     475         339 :       if (unlikely (sh == NULL))
     476             :         {
     477           0 :           free (shdrs);
     478           0 :           return DWFL_E_LIBELF;
     479             :         }
     480         678 :       consider_shdr (main_interp, sh->sh_type, sh->sh_flags,
     481             :                      sh->sh_addr, sh->sh_size, &highest);
     482             :     }
     483          12 :   if (highest > mod->main.vaddr)
     484             :     {
     485          12 :       mod->main.address_sync = highest;
     486             : 
     487          12 :       highest = 0;
     488          12 :       if (class32)
     489             :         {
     490             :           Elf32_Shdr (*s32)[shnum - 1] = shdrs;
     491          94 :           for (size_t i = 0; i < shnum - 1; ++i)
     492         376 :             consider_shdr (undo_interp, (*s32)[i].sh_type,
     493         188 :                            (*s32)[i].sh_flags, (*s32)[i].sh_addr,
     494          94 :                            (*s32)[i].sh_size, &highest);
     495             :         }
     496             :       else
     497             :         {
     498             :           Elf64_Shdr (*s64)[shnum - 1] = shdrs;
     499         207 :           for (size_t i = 0; i < shnum - 1; ++i)
     500         414 :             consider_shdr (undo_interp, (*s64)[i].sh_type,
     501             :                            (*s64)[i].sh_flags, (*s64)[i].sh_addr,
     502             :                            (*s64)[i].sh_size, &highest);
     503             :         }
     504             : 
     505          12 :       if (highest > file->vaddr)
     506          12 :         file->address_sync = highest;
     507             :       else
     508             :         {
     509           0 :           free (shdrs);
     510             :           return DWFL_E_BAD_PRELINK;
     511             :         }
     512             :     }
     513             : 
     514          12 :   free (shdrs);
     515             : 
     516             :   return DWFL_E_NOERROR;
     517             : }
     518             : 
     519             : /* Find the separate debuginfo file for this module and open libelf on it.
     520             :    When we return success, MOD->debug is set up.  */
     521             : static Dwfl_Error
     522         141 : find_debuginfo (Dwfl_Module *mod)
     523             : {
     524         141 :   if (mod->debug.elf != NULL)
     525             :     return DWFL_E_NOERROR;
     526             : 
     527         115 :   GElf_Word debuglink_crc = 0;
     528             :   const char *debuglink_file;
     529         115 :   debuglink_file = INTUSE(dwelf_elf_gnu_debuglink) (mod->main.elf,
     530             :                                                     &debuglink_crc);
     531             : 
     532         230 :   mod->debug.fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod),
     533         115 :                                                            mod->main.name,
     534             :                                                            debuglink_file,
     535             :                                                            debuglink_crc,
     536             :                                                            &mod->debug.name);
     537         115 :   Dwfl_Error result = open_elf (mod, &mod->debug);
     538         115 :   if (result == DWFL_E_NOERROR && mod->debug.address_sync != 0)
     539          35 :     result = find_prelink_address_sync (mod, &mod->debug);
     540             :   return result;
     541             : }
     542             : 
     543             : /* Try to find the alternative debug link for the given DWARF and set
     544             :    it if found.  Only called when mod->dw is already setup but still
     545             :    might need an alternative (dwz multi) debug file.  filename is either
     546             :    the main or debug name from which the Dwarf was created. */
     547             : static void
     548        5213 : find_debug_altlink (Dwfl_Module *mod, const char *filename)
     549             : {
     550        5213 :   assert (mod->dw != NULL);
     551             : 
     552             :   const char *altname;
     553             :   const void *build_id;
     554        5213 :   ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw,
     555             :                                                                &altname,
     556             :                                                                &build_id);
     557             : 
     558        5213 :   if (build_id_len > 0)
     559             :     {
     560             :       /* We could store altfile in the module, but don't really need it.  */
     561           6 :       char *altfile = NULL;
     562           6 :       mod->alt_fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod),
     563             :                                                              filename,
     564             :                                                              altname,
     565             :                                                              0,
     566             :                                                              &altfile);
     567             : 
     568             :       /* The (internal) callbacks might just set mod->alt_elf directly
     569             :          because they open the Elf anyway for sanity checking.
     570             :          Otherwise open either the given file name or use the fd
     571             :          returned.  */
     572           6 :       Dwfl_Error error = open_elf_file (&mod->alt_elf, &mod->alt_fd,
     573             :                                         &altfile);
     574           6 :       if (error == DWFL_E_NOERROR)
     575             :         {
     576           6 :           mod->alt = INTUSE(dwarf_begin_elf) (mod->alt_elf,
     577             :                                               DWARF_C_READ, NULL);
     578           6 :           if (mod->alt == NULL)
     579             :             {
     580           0 :               elf_end (mod->alt_elf);
     581           0 :               mod->alt_elf = NULL;
     582           0 :               close (mod->alt_fd);
     583           0 :               mod->alt_fd = -1;
     584             :             }
     585             :           else
     586           6 :             dwarf_setalt (mod->dw, mod->alt);
     587             :         }
     588             : 
     589           6 :       free (altfile); /* See above, we don't really need it.  */
     590             :     }
     591        5213 : }
     592             : 
     593             : /* Try to find a symbol table in FILE.
     594             :    Returns DWFL_E_NOERROR if a proper one is found.
     595             :    Returns DWFL_E_NO_SYMTAB if not, but still sets results for SHT_DYNSYM.  */
     596             : static Dwfl_Error
     597         205 : load_symtab (struct dwfl_file *file, struct dwfl_file **symfile,
     598             :              Elf_Scn **symscn, Elf_Scn **xndxscn,
     599             :              size_t *syments, int *first_global, GElf_Word *strshndx)
     600             : {
     601         205 :   bool symtab = false;
     602         205 :   Elf_Scn *scn = NULL;
     603        6450 :   while ((scn = elf_nextscn (file->elf, scn)) != NULL)
     604             :     {
     605        6040 :       GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
     606        6040 :       if (shdr != NULL)
     607        6040 :         switch (shdr->sh_type)
     608             :           {
     609             :           case SHT_SYMTAB:
     610         157 :             if (shdr->sh_entsize == 0)
     611             :               break;
     612         157 :             symtab = true;
     613         157 :             *symscn = scn;
     614         157 :             *symfile = file;
     615         157 :             *strshndx = shdr->sh_link;
     616         157 :             *syments = shdr->sh_size / shdr->sh_entsize;
     617         157 :             *first_global = shdr->sh_info;
     618         157 :             if (*xndxscn != NULL)
     619           0 :               return DWFL_E_NOERROR;
     620             :             break;
     621             : 
     622             :           case SHT_DYNSYM:
     623         105 :             if (symtab)
     624             :               break;
     625             :             /* Use this if need be, but keep looking for SHT_SYMTAB.  */
     626         105 :             if (shdr->sh_entsize == 0)
     627             :               break;
     628         105 :             *symscn = scn;
     629         105 :             *symfile = file;
     630         105 :             *strshndx = shdr->sh_link;
     631         105 :             *syments = shdr->sh_size / shdr->sh_entsize;
     632         105 :             *first_global = shdr->sh_info;
     633         105 :             break;
     634             : 
     635             :           case SHT_SYMTAB_SHNDX:
     636           0 :             *xndxscn = scn;
     637           0 :             if (symtab)
     638             :               return DWFL_E_NOERROR;
     639             :             break;
     640             : 
     641             :           default:
     642             :             break;
     643             :           }
     644             :     }
     645             : 
     646         205 :   if (symtab)
     647             :     /* We found one, though no SHT_SYMTAB_SHNDX to go with it.  */
     648             :     return DWFL_E_NOERROR;
     649             : 
     650             :   /* We found no SHT_SYMTAB, so any SHT_SYMTAB_SHNDX was bogus.
     651             :      We might have found an SHT_DYNSYM and set *SYMSCN et al though.  */
     652          48 :   *xndxscn = NULL;
     653          48 :   return DWFL_E_NO_SYMTAB;
     654             : }
     655             : 
     656             : 
     657             : /* Translate addresses into file offsets.
     658             :    OFFS[*] start out zero and remain zero if unresolved.  */
     659             : static void
     660           6 : find_offsets (Elf *elf, GElf_Addr main_bias, size_t phnum, size_t n,
     661             :               GElf_Addr addrs[n], GElf_Off offs[n])
     662             : {
     663           6 :   size_t unsolved = n;
     664          38 :   for (size_t i = 0; i < phnum; ++i)
     665             :     {
     666             :       GElf_Phdr phdr_mem;
     667          32 :       GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
     668          32 :       if (phdr != NULL && phdr->p_type == PT_LOAD && phdr->p_memsz > 0)
     669          38 :         for (size_t j = 0; j < n; ++j)
     670          40 :           if (offs[j] == 0
     671          31 :               && addrs[j] >= phdr->p_vaddr + main_bias
     672          24 :               && addrs[j] - (phdr->p_vaddr + main_bias) < phdr->p_filesz)
     673             :             {
     674          18 :               offs[j] = addrs[j] - (phdr->p_vaddr + main_bias) + phdr->p_offset;
     675          18 :               if (--unsolved == 0)
     676             :                 break;
     677             :             }
     678             :     }
     679           6 : }
     680             : 
     681             : /* Various addresses we might want to pull from the dynamic segment.  */
     682             : enum
     683             : {
     684             :   i_symtab,
     685             :   i_strtab,
     686             :   i_hash,
     687             :   i_gnu_hash,
     688             :   i_max
     689             : };
     690             : 
     691             : /* Translate pointers into file offsets.  ADJUST is either zero
     692             :    in case the dynamic segment wasn't adjusted or mod->main_bias.
     693             :    Will set mod->symfile if the translated offsets can be used as
     694             :    symbol table.  */
     695             : static void
     696           6 : translate_offs (GElf_Addr adjust,
     697             :                 Dwfl_Module *mod, size_t phnum,
     698             :                 GElf_Addr addrs[i_max], GElf_Xword strsz,
     699             :                 GElf_Ehdr *ehdr)
     700             : {
     701           6 :   GElf_Off offs[i_max] = { 0, };
     702           6 :   find_offsets (mod->main.elf, adjust, phnum, i_max, addrs, offs);
     703             : 
     704             :   /* Figure out the size of the symbol table.  */
     705           6 :   if (offs[i_hash] != 0)
     706             :     {
     707             :       /* In the original format, .hash says the size of .dynsym.  */
     708             : 
     709           2 :       size_t entsz = SH_ENTSIZE_HASH (ehdr);
     710           4 :       Elf_Data *data = elf_getdata_rawchunk (mod->main.elf,
     711           2 :                                              offs[i_hash] + entsz, entsz,
     712             :                                              (entsz == 4
     713             :                                               ? ELF_T_WORD : ELF_T_XWORD));
     714           2 :       if (data != NULL)
     715           2 :         mod->syments = (entsz == 4
     716           2 :                         ? *(const GElf_Word *) data->d_buf
     717           4 :                         : *(const GElf_Xword *) data->d_buf);
     718             :     }
     719           6 :   if (offs[i_gnu_hash] != 0 && mod->syments == 0)
     720             :     {
     721             :       /* In the new format, we can derive it with some work.  */
     722             : 
     723             :       const struct
     724             :       {
     725             :         Elf32_Word nbuckets;
     726             :         Elf32_Word symndx;
     727             :         Elf32_Word maskwords;
     728             :         Elf32_Word shift2;
     729             :       } *header;
     730             : 
     731           3 :       Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, offs[i_gnu_hash],
     732             :                                              sizeof *header, ELF_T_WORD);
     733           3 :       if (data != NULL)
     734             :         {
     735           3 :           header = data->d_buf;
     736           3 :           Elf32_Word nbuckets = header->nbuckets;
     737           3 :           Elf32_Word symndx = header->symndx;
     738           6 :           GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header
     739           6 :                                  + (gelf_getclass (mod->main.elf)
     740             :                                     * sizeof (Elf32_Word)
     741           3 :                                     * header->maskwords));
     742             : 
     743             :           // elf_getdata_rawchunk takes a size_t, make sure it
     744             :           // doesn't overflow.
     745             : #if SIZE_MAX <= UINT32_MAX
     746             :           if (nbuckets > SIZE_MAX / sizeof (Elf32_Word))
     747             :             data = NULL;
     748             :           else
     749             : #endif
     750           3 :             data = elf_getdata_rawchunk (mod->main.elf, buckets_at,
     751             :                                            nbuckets * sizeof (Elf32_Word),
     752             :                                            ELF_T_WORD);
     753           3 :           if (data != NULL && symndx < nbuckets)
     754             :             {
     755           1 :               const Elf32_Word *const buckets = data->d_buf;
     756           1 :               Elf32_Word maxndx = symndx;
     757           4 :               for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket)
     758           3 :                 if (buckets[bucket] > maxndx)
     759           1 :                   maxndx = buckets[bucket];
     760             : 
     761           1 :               GElf_Off hasharr_at = (buckets_at
     762             :                                      + nbuckets * sizeof (Elf32_Word));
     763           1 :               hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word);
     764             :               do
     765             :                 {
     766           1 :                   data = elf_getdata_rawchunk (mod->main.elf,
     767             :                                                hasharr_at,
     768             :                                                sizeof (Elf32_Word),
     769             :                                                ELF_T_WORD);
     770           1 :                   if (data != NULL
     771           1 :                       && (*(const Elf32_Word *) data->d_buf & 1u))
     772             :                     {
     773           1 :                       mod->syments = maxndx + 1;
     774             :                       break;
     775             :                     }
     776           0 :                   ++maxndx;
     777           0 :                   hasharr_at += sizeof (Elf32_Word);
     778             :                 }
     779           0 :               while (data != NULL);
     780             :             }
     781             :         }
     782             :     }
     783           6 :   if (offs[i_strtab] > offs[i_symtab] && mod->syments == 0)
     784           4 :     mod->syments = ((offs[i_strtab] - offs[i_symtab])
     785           2 :                     / gelf_fsize (mod->main.elf,
     786             :                                   ELF_T_SYM, 1, EV_CURRENT));
     787             : 
     788           6 :   if (mod->syments > 0)
     789             :     {
     790          10 :       mod->symdata = elf_getdata_rawchunk (mod->main.elf,
     791           5 :                                            offs[i_symtab],
     792             :                                            gelf_fsize (mod->main.elf,
     793             :                                                        ELF_T_SYM,
     794             :                                                        mod->syments,
     795             :                                                        EV_CURRENT),
     796             :                                                        ELF_T_SYM);
     797           5 :       if (mod->symdata != NULL)
     798             :         {
     799           5 :           mod->symstrdata = elf_getdata_rawchunk (mod->main.elf,
     800           5 :                                                   offs[i_strtab],
     801             :                                                   strsz,
     802             :                                                   ELF_T_BYTE);
     803           5 :           if (mod->symstrdata == NULL)
     804           0 :             mod->symdata = NULL;
     805             :         }
     806           5 :       if (mod->symdata == NULL)
     807           0 :         mod->symerr = DWFL_E (LIBELF, elf_errno ());
     808             :       else
     809             :         {
     810           5 :           mod->symfile = &mod->main;
     811           5 :           mod->symerr = DWFL_E_NOERROR;
     812             :         }
     813             :     }
     814           6 : }
     815             : 
     816             : /* Try to find a dynamic symbol table via phdrs.  */
     817             : static void
     818           5 : find_dynsym (Dwfl_Module *mod)
     819             : {
     820             :   GElf_Ehdr ehdr_mem;
     821           5 :   GElf_Ehdr *ehdr = gelf_getehdr (mod->main.elf, &ehdr_mem);
     822             : 
     823             :   size_t phnum;
     824           5 :   if (unlikely (elf_getphdrnum (mod->main.elf, &phnum) != 0))
     825           5 :     return;
     826             : 
     827           8 :   for (size_t i = 0; i < phnum; ++i)
     828             :     {
     829             :       GElf_Phdr phdr_mem;
     830          13 :       GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem);
     831          13 :       if (phdr == NULL)
     832             :         break;
     833             : 
     834          13 :       if (phdr->p_type == PT_DYNAMIC)
     835             :         {
     836             :           /* Examine the dynamic section for the pointers we need.  */
     837             : 
     838          10 :           Elf_Data *data = elf_getdata_rawchunk (mod->main.elf,
     839           5 :                                                  phdr->p_offset, phdr->p_filesz,
     840             :                                                  ELF_T_DYN);
     841           5 :           if (data == NULL)
     842           0 :             continue;
     843             : 
     844           5 :           GElf_Addr addrs[i_max] = { 0, };
     845           5 :           GElf_Xword strsz = 0;
     846           5 :           size_t n = data->d_size / gelf_fsize (mod->main.elf,
     847             :                                                 ELF_T_DYN, 1, EV_CURRENT);
     848         156 :           for (size_t j = 0; j < n; ++j)
     849             :             {
     850             :               GElf_Dyn dyn_mem;
     851          78 :               GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
     852          78 :               if (dyn != NULL)
     853          78 :                 switch (dyn->d_tag)
     854             :                   {
     855             :                   case DT_SYMTAB:
     856           5 :                     addrs[i_symtab] = dyn->d_un.d_ptr;
     857          78 :                     continue;
     858             : 
     859             :                   case DT_HASH:
     860           2 :                     addrs[i_hash] = dyn->d_un.d_ptr;
     861           2 :                     continue;
     862             : 
     863             :                   case DT_GNU_HASH:
     864           5 :                     addrs[i_gnu_hash] = dyn->d_un.d_ptr;
     865           5 :                     continue;
     866             : 
     867             :                   case DT_STRTAB:
     868           5 :                     addrs[i_strtab] = dyn->d_un.d_ptr;
     869           5 :                     continue;
     870             : 
     871             :                   case DT_STRSZ:
     872           5 :                     strsz = dyn->d_un.d_val;
     873           5 :                     continue;
     874             : 
     875             :                   default:
     876          51 :                     continue;
     877             : 
     878             :                   case DT_NULL:
     879             :                     break;
     880             :                   }
     881           5 :               break;
     882             :             }
     883             : 
     884             :           /* First try unadjusted, like ELF files from disk, vdso.
     885             :              Then try for already adjusted dynamic section, like ELF
     886             :              from remote memory.  */
     887           5 :           translate_offs (0, mod, phnum, addrs, strsz, ehdr);
     888           5 :           if (mod->symfile == NULL)
     889           1 :             translate_offs (mod->main_bias, mod, phnum, addrs, strsz, ehdr);
     890             : 
     891           5 :           return;
     892             :         }
     893             :     }
     894             : }
     895             : 
     896             : 
     897             : #if USE_LZMA
     898             : /* Try to find the offset between the main file and .gnu_debugdata.  */
     899             : static bool
     900           8 : find_aux_address_sync (Dwfl_Module *mod)
     901             : {
     902             :   /* Don't trust the phdrs in the minisymtab elf file to be setup correctly.
     903             :      The address_sync is equal to the main file it is embedded in at first.  */
     904           8 :   mod->aux_sym.address_sync = mod->main.address_sync;
     905             : 
     906             :   /* Adjust address_sync for the difference in entry addresses, attempting to
     907             :      account for ELF relocation changes after aux was split.  */
     908             :   GElf_Ehdr ehdr_main, ehdr_aux;
     909           8 :   if (unlikely (gelf_getehdr (mod->main.elf, &ehdr_main) == NULL)
     910           8 :       || unlikely (gelf_getehdr (mod->aux_sym.elf, &ehdr_aux) == NULL))
     911             :     return false;
     912           8 :   mod->aux_sym.address_sync += ehdr_aux.e_entry - ehdr_main.e_entry;
     913             : 
     914             :   /* The shdrs are setup OK to make find_prelink_address_sync () do the right
     915             :      thing, which is possibly more reliable, but it needs .gnu.prelink_undo.  */
     916           8 :   if (mod->aux_sym.address_sync != 0)
     917           8 :     return find_prelink_address_sync (mod, &mod->aux_sym) == DWFL_E_NOERROR;
     918             : 
     919             :   return true;
     920             : }
     921             : #endif
     922             : 
     923             : /* Try to find the auxiliary symbol table embedded in the main elf file
     924             :    section .gnu_debugdata.  Only matters if the symbol information comes
     925             :    from the main file dynsym.  No harm done if not found.  */
     926             : static void
     927          22 : find_aux_sym (Dwfl_Module *mod __attribute__ ((unused)),
     928             :               Elf_Scn **aux_symscn __attribute__ ((unused)),
     929             :               Elf_Scn **aux_xndxscn __attribute__ ((unused)),
     930             :               GElf_Word *aux_strshndx __attribute__ ((unused)))
     931             : {
     932             :   /* Since a .gnu_debugdata section is compressed using lzma don't do
     933             :      anything unless we have support for that.  */
     934             : #if USE_LZMA
     935          22 :   Elf *elf = mod->main.elf;
     936             : 
     937             :   size_t shstrndx;
     938          22 :   if (elf_getshdrstrndx (elf, &shstrndx) < 0)
     939          22 :     return;
     940             : 
     941             :   Elf_Scn *scn = NULL;
     942         400 :   while ((scn = elf_nextscn (elf, scn)) != NULL)
     943             :     {
     944             :       GElf_Shdr shdr_mem;
     945         386 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
     946         386 :       if (shdr == NULL)
     947           0 :         return;
     948             : 
     949         386 :       const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
     950         386 :       if (name == NULL)
     951             :         return;
     952             : 
     953         386 :       if (!strcmp (name, ".gnu_debugdata"))
     954             :         break;
     955             :     }
     956             : 
     957          22 :   if (scn == NULL)
     958             :     return;
     959             : 
     960             :   /* Found the .gnu_debugdata section.  Uncompress the lzma image and
     961             :      turn it into an ELF image.  */
     962           8 :   Elf_Data *rawdata = elf_rawdata (scn, NULL);
     963           8 :   if (rawdata == NULL)
     964             :     return;
     965             : 
     966             :   Dwfl_Error error;
     967           8 :   void *buffer = NULL;
     968           8 :   size_t size = 0;
     969           8 :   error = __libdw_unlzma (-1, 0, rawdata->d_buf, rawdata->d_size,
     970             :                           &buffer, &size);
     971           8 :   if (error == DWFL_E_NOERROR)
     972             :     {
     973           8 :       if (unlikely (size == 0))
     974           0 :         free (buffer);
     975             :       else
     976             :         {
     977           8 :           mod->aux_sym.elf = elf_memory (buffer, size);
     978           8 :           if (mod->aux_sym.elf == NULL)
     979           0 :             free (buffer);
     980             :           else
     981             :             {
     982           8 :               mod->aux_sym.fd = -1;
     983           8 :               mod->aux_sym.elf->flags |= ELF_F_MALLOCED;
     984           8 :               if (open_elf (mod, &mod->aux_sym) != DWFL_E_NOERROR)
     985             :                 return;
     986           8 :               if (! find_aux_address_sync (mod))
     987             :                 {
     988           0 :                   elf_end (mod->aux_sym.elf);
     989           0 :                   mod->aux_sym.elf = NULL;
     990           0 :                   return;
     991             :                 }
     992             : 
     993             :               /* So far, so good. Get minisymtab table data and cache it. */
     994             :               bool minisymtab = false;
     995             :               scn = NULL;
     996         217 :               while ((scn = elf_nextscn (mod->aux_sym.elf, scn)) != NULL)
     997             :                 {
     998         209 :                   GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
     999         209 :                   if (shdr != NULL)
    1000         209 :                     switch (shdr->sh_type)
    1001             :                       {
    1002             :                       case SHT_SYMTAB:
    1003           8 :                         minisymtab = true;
    1004           8 :                         *aux_symscn = scn;
    1005           8 :                         *aux_strshndx = shdr->sh_link;
    1006           8 :                         mod->aux_syments = shdr->sh_size / shdr->sh_entsize;
    1007           8 :                         mod->aux_first_global = shdr->sh_info;
    1008           8 :                         if (*aux_xndxscn != NULL)
    1009           0 :                           return;
    1010             :                         break;
    1011             : 
    1012             :                       case SHT_SYMTAB_SHNDX:
    1013           0 :                         *aux_xndxscn = scn;
    1014           0 :                         if (minisymtab)
    1015             :                           return;
    1016             :                         break;
    1017             : 
    1018             :                       default:
    1019             :                         break;
    1020             :                       }
    1021             :                 }
    1022             : 
    1023           8 :               if (minisymtab)
    1024             :                 /* We found one, though no SHT_SYMTAB_SHNDX to go with it.  */
    1025             :                 return;
    1026             : 
    1027             :               /* We found no SHT_SYMTAB, so everything else is bogus.  */
    1028           0 :               *aux_xndxscn = NULL;
    1029           0 :               *aux_strshndx = 0;
    1030           0 :               mod->aux_syments = 0;
    1031           0 :               elf_end (mod->aux_sym.elf);
    1032           0 :               mod->aux_sym.elf = NULL;
    1033           0 :               return;
    1034             :             }
    1035             :         }
    1036             :     }
    1037             :   else
    1038           0 :     free (buffer);
    1039             : #endif
    1040             : }
    1041             : 
    1042             : /* Try to find a symbol table in either MOD->main.elf or MOD->debug.elf.  */
    1043             : static void
    1044     1341467 : find_symtab (Dwfl_Module *mod)
    1045             : {
    1046     1341467 :   if (mod->symdata != NULL || mod->aux_symdata != NULL    /* Already done.  */
    1047         182 :       || mod->symerr != DWFL_E_NOERROR) /* Cached previous failure.  */
    1048     1341293 :     return;
    1049             : 
    1050         182 :   __libdwfl_getelf (mod);
    1051         182 :   mod->symerr = mod->elferr;
    1052         182 :   if (mod->symerr != DWFL_E_NOERROR)
    1053             :     return;
    1054             : 
    1055             :   /* First see if the main ELF file has the debugging information.  */
    1056         179 :   Elf_Scn *symscn = NULL, *xndxscn = NULL;
    1057         179 :   Elf_Scn *aux_symscn = NULL, *aux_xndxscn = NULL;
    1058         179 :   GElf_Word strshndx, aux_strshndx = 0;
    1059         179 :   mod->symerr = load_symtab (&mod->main, &mod->symfile, &symscn,
    1060             :                              &xndxscn, &mod->syments, &mod->first_global,
    1061             :                              &strshndx);
    1062         179 :   switch (mod->symerr)
    1063             :     {
    1064             :     default:
    1065             :       return;
    1066             : 
    1067             :     case DWFL_E_NOERROR:
    1068             :       break;
    1069             : 
    1070             :     case DWFL_E_NO_SYMTAB:
    1071             :       /* Now we have to look for a separate debuginfo file.  */
    1072          48 :       mod->symerr = find_debuginfo (mod);
    1073          48 :       switch (mod->symerr)
    1074             :         {
    1075             :         default:
    1076             :           return;
    1077             : 
    1078             :         case DWFL_E_NOERROR:
    1079          26 :           mod->symerr = load_symtab (&mod->debug, &mod->symfile, &symscn,
    1080             :                                      &xndxscn, &mod->syments,
    1081             :                                      &mod->first_global, &strshndx);
    1082          26 :           break;
    1083             : 
    1084             :         case DWFL_E_CB:         /* The find_debuginfo hook failed.  */
    1085          22 :           mod->symerr = DWFL_E_NO_SYMTAB;
    1086          22 :           break;
    1087             :         }
    1088             : 
    1089          48 :       switch (mod->symerr)
    1090             :         {
    1091             :         default:
    1092             :           return;
    1093             : 
    1094             :         case DWFL_E_NOERROR:
    1095             :           break;
    1096             : 
    1097             :         case DWFL_E_NO_SYMTAB:
    1098             :           /* There might be an auxiliary table.  */
    1099          22 :           find_aux_sym (mod, &aux_symscn, &aux_xndxscn, &aux_strshndx);
    1100             : 
    1101          22 :           if (symscn != NULL)
    1102             :             {
    1103             :               /* We still have the dynamic symbol table.  */
    1104          16 :               mod->symerr = DWFL_E_NOERROR;
    1105          16 :               break;
    1106             :             }
    1107             : 
    1108           6 :           if (aux_symscn != NULL)
    1109             :             {
    1110             :               /* We still have the auxiliary symbol table.  */
    1111           1 :               mod->symerr = DWFL_E_NOERROR;
    1112           1 :               goto aux_cache;
    1113             :             }
    1114             : 
    1115             :           /* Last ditch, look for dynamic symbols without section headers.  */
    1116           5 :           find_dynsym (mod);
    1117           5 :           return;
    1118             :         }
    1119             :       break;
    1120             :     }
    1121             : 
    1122             :   /* This does some sanity checks on the string table section.  */
    1123         173 :   if (elf_strptr (mod->symfile->elf, strshndx, 0) == NULL)
    1124             :     {
    1125             :     elferr:
    1126           0 :       mod->symdata = NULL;
    1127           0 :       mod->syments = 0;
    1128           0 :       mod->first_global = 0;
    1129           0 :       mod->symerr = DWFL_E (LIBELF, elf_errno ());
    1130           0 :       goto aux_cleanup; /* This cleans up some more and tries find_dynsym.  */
    1131             :     }
    1132             : 
    1133             :   /* Cache the data; MOD->syments and MOD->first_global were set
    1134             :      above.  If any of the sections is compressed, uncompress it
    1135             :      first.  Only the string data setion could theoretically be
    1136             :      compressed GNU style (as .zdebug_str).  Everything else only ELF
    1137             :      gabi style (SHF_COMPRESSED).  */
    1138             : 
    1139         173 :   Elf_Scn *symstrscn = elf_getscn (mod->symfile->elf, strshndx);
    1140         173 :   if (symstrscn == NULL)
    1141             :     goto elferr;
    1142             : 
    1143             :   GElf_Shdr shdr_mem;
    1144         173 :   GElf_Shdr *shdr = gelf_getshdr (symstrscn, &shdr_mem);
    1145         173 :   if (shdr == NULL)
    1146             :     goto elferr;
    1147             : 
    1148             :   size_t shstrndx;
    1149         173 :   if (elf_getshdrstrndx (mod->symfile->elf, &shstrndx) < 0)
    1150             :     goto elferr;
    1151             : 
    1152         173 :   const char *sname = elf_strptr (mod->symfile->elf, shstrndx, shdr->sh_name);
    1153         173 :   if (sname == NULL)
    1154             :     goto elferr;
    1155             : 
    1156         173 :   if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
    1157             :     /* Try to uncompress, but it might already have been, an error
    1158             :        might just indicate, already uncompressed.  */
    1159           0 :     elf_compress_gnu (symstrscn, 0, 0);
    1160             : 
    1161         173 :   if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    1162           0 :     if (elf_compress (symstrscn, 0, 0) < 0)
    1163             :       goto elferr;
    1164             : 
    1165         173 :   mod->symstrdata = elf_getdata (symstrscn, NULL);
    1166         173 :   if (mod->symstrdata == NULL || mod->symstrdata->d_buf == NULL)
    1167             :     goto elferr;
    1168             : 
    1169         173 :   if (xndxscn == NULL)
    1170         173 :     mod->symxndxdata = NULL;
    1171             :   else
    1172             :     {
    1173           0 :       shdr = gelf_getshdr (xndxscn, &shdr_mem);
    1174           0 :       if (shdr == NULL)
    1175             :         goto elferr;
    1176             : 
    1177           0 :       if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    1178           0 :         if (elf_compress (xndxscn, 0, 0) < 0)
    1179             :           goto elferr;
    1180             : 
    1181           0 :       mod->symxndxdata = elf_getdata (xndxscn, NULL);
    1182           0 :       if (mod->symxndxdata == NULL || mod->symxndxdata->d_buf == NULL)
    1183             :         goto elferr;
    1184             :     }
    1185             : 
    1186         173 :   shdr = gelf_getshdr (symscn, &shdr_mem);
    1187         173 :   if (shdr == NULL)
    1188             :     goto elferr;
    1189             : 
    1190         173 :   if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    1191           0 :     if (elf_compress (symscn, 0, 0) < 0)
    1192             :       goto elferr;
    1193             : 
    1194         173 :   mod->symdata = elf_getdata (symscn, NULL);
    1195         173 :   if (mod->symdata == NULL || mod->symdata->d_buf == NULL)
    1196             :     goto elferr;
    1197             : 
    1198             :   // Sanity check number of symbols.
    1199         173 :   shdr = gelf_getshdr (symscn, &shdr_mem);
    1200         173 :   if (shdr == NULL || shdr->sh_entsize == 0
    1201         173 :       || mod->syments > mod->symdata->d_size / shdr->sh_entsize
    1202         173 :       || (size_t) mod->first_global > mod->syments)
    1203             :     goto elferr;
    1204             : 
    1205             :   /* Cache any auxiliary symbol info, when it fails, just ignore aux_sym.  */
    1206         173 :   if (aux_symscn != NULL)
    1207             :     {
    1208             :   aux_cache:
    1209             :       /* This does some sanity checks on the string table section.  */
    1210           8 :       if (elf_strptr (mod->aux_sym.elf, aux_strshndx, 0) == NULL)
    1211             :         {
    1212             :         aux_cleanup:
    1213           0 :           mod->aux_syments = 0;
    1214           0 :           elf_end (mod->aux_sym.elf);
    1215           0 :           mod->aux_sym.elf = NULL;
    1216             :           /* We thought we had something through shdrs, but it failed...
    1217             :              Last ditch, look for dynamic symbols without section headers.  */
    1218           0 :           find_dynsym (mod);
    1219           0 :           return;
    1220             :         }
    1221             : 
    1222           8 :       Elf_Scn *aux_strscn = elf_getscn (mod->aux_sym.elf, aux_strshndx);
    1223           8 :       if (aux_strscn == NULL)
    1224             :         goto elferr;
    1225             : 
    1226           8 :       shdr = gelf_getshdr (aux_strscn, &shdr_mem);
    1227           8 :       if (shdr == NULL)
    1228             :         goto elferr;
    1229             : 
    1230             :       size_t aux_shstrndx;
    1231           8 :       if (elf_getshdrstrndx (mod->aux_sym.elf, &aux_shstrndx) < 0)
    1232             :         goto elferr;
    1233             : 
    1234           8 :       sname = elf_strptr (mod->aux_sym.elf, aux_shstrndx,
    1235           8 :                                       shdr->sh_name);
    1236           8 :       if (sname == NULL)
    1237             :         goto elferr;
    1238             : 
    1239           8 :       if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
    1240             :         /* Try to uncompress, but it might already have been, an error
    1241             :            might just indicate, already uncompressed.  */
    1242           0 :         elf_compress_gnu (aux_strscn, 0, 0);
    1243             : 
    1244           8 :       if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    1245           0 :         if (elf_compress (aux_strscn, 0, 0) < 0)
    1246             :           goto elferr;
    1247             : 
    1248           8 :       mod->aux_symstrdata = elf_getdata (aux_strscn, NULL);
    1249           8 :       if (mod->aux_symstrdata == NULL || mod->aux_symstrdata->d_buf == NULL)
    1250             :         goto aux_cleanup;
    1251             : 
    1252           8 :       if (aux_xndxscn == NULL)
    1253           8 :         mod->aux_symxndxdata = NULL;
    1254             :       else
    1255             :         {
    1256           0 :           shdr = gelf_getshdr (aux_xndxscn, &shdr_mem);
    1257           0 :           if (shdr == NULL)
    1258             :             goto elferr;
    1259             : 
    1260           0 :           if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    1261           0 :             if (elf_compress (aux_xndxscn, 0, 0) < 0)
    1262             :               goto elferr;
    1263             : 
    1264           0 :           mod->aux_symxndxdata = elf_getdata (aux_xndxscn, NULL);
    1265           0 :           if (mod->aux_symxndxdata == NULL
    1266           0 :               || mod->aux_symxndxdata->d_buf == NULL)
    1267             :             goto aux_cleanup;
    1268             :         }
    1269             : 
    1270           8 :       shdr = gelf_getshdr (aux_symscn, &shdr_mem);
    1271           8 :       if (shdr == NULL)
    1272             :         goto elferr;
    1273             : 
    1274           8 :       if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    1275           0 :         if (elf_compress (aux_symscn, 0, 0) < 0)
    1276             :           goto elferr;
    1277             : 
    1278           8 :       mod->aux_symdata = elf_getdata (aux_symscn, NULL);
    1279           8 :       if (mod->aux_symdata == NULL || mod->aux_symdata->d_buf == NULL)
    1280             :         goto aux_cleanup;
    1281             : 
    1282             :       // Sanity check number of aux symbols.
    1283           8 :       shdr = gelf_getshdr (aux_symscn, &shdr_mem);
    1284           8 :       if (mod->aux_syments > mod->aux_symdata->d_size / shdr->sh_entsize
    1285           8 :           || (size_t) mod->aux_first_global > mod->aux_syments)
    1286             :         goto aux_cleanup;
    1287             :     }
    1288             : }
    1289             : 
    1290             : 
    1291             : /* Try to open a libebl backend for MOD.  */
    1292             : Dwfl_Error
    1293             : internal_function
    1294   297961636 : __libdwfl_module_getebl (Dwfl_Module *mod)
    1295             : {
    1296   297961636 :   if (mod->ebl == NULL)
    1297             :     {
    1298         232 :       __libdwfl_getelf (mod);
    1299         232 :       if (mod->elferr != DWFL_E_NOERROR)
    1300             :         return mod->elferr;
    1301             : 
    1302         232 :       mod->ebl = ebl_openbackend (mod->main.elf);
    1303         232 :       if (mod->ebl == NULL)
    1304             :         return DWFL_E_LIBEBL;
    1305             :     }
    1306             :   return DWFL_E_NOERROR;
    1307             : }
    1308             : 
    1309             : /* Try to start up libdw on DEBUGFILE.  */
    1310             : static Dwfl_Error
    1311        5307 : load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile)
    1312             : {
    1313        5307 :   if (mod->e_type == ET_REL && !debugfile->relocated)
    1314             :     {
    1315          25 :       const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
    1316             : 
    1317             :       /* The debugging sections have to be relocated.  */
    1318          25 :       if (cb->section_address == NULL)
    1319             :         return DWFL_E_NOREL;
    1320             : 
    1321          25 :       Dwfl_Error error = __libdwfl_module_getebl (mod);
    1322          25 :       if (error != DWFL_E_NOERROR)
    1323             :         return error;
    1324             : 
    1325          25 :       find_symtab (mod);
    1326          25 :       Dwfl_Error result = mod->symerr;
    1327          25 :       if (result == DWFL_E_NOERROR)
    1328          25 :         result = __libdwfl_relocate (mod, debugfile->elf, true);
    1329          25 :       if (result != DWFL_E_NOERROR)
    1330             :         return result;
    1331             : 
    1332             :       /* Don't keep the file descriptors around.  */
    1333          25 :       if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
    1334             :         {
    1335           0 :           close (mod->main.fd);
    1336           0 :           mod->main.fd = -1;
    1337             :         }
    1338          25 :       if (debugfile->fd != -1 && elf_cntl (debugfile->elf, ELF_C_FDREAD) == 0)
    1339             :         {
    1340           1 :           close (debugfile->fd);
    1341           1 :           debugfile->fd = -1;
    1342             :         }
    1343             :     }
    1344             : 
    1345        5307 :   mod->dw = INTUSE(dwarf_begin_elf) (debugfile->elf, DWARF_C_READ, NULL);
    1346        5307 :   if (mod->dw == NULL)
    1347             :     {
    1348          94 :       int err = INTUSE(dwarf_errno) ();
    1349          94 :       return err == DWARF_E_NO_DWARF ? DWFL_E_NO_DWARF : DWFL_E (LIBDW, err);
    1350             :     }
    1351             : 
    1352             :   /* Until we have iterated through all CU's, we might do lazy lookups.  */
    1353        5213 :   mod->lazycu = 1;
    1354             : 
    1355        5213 :   return DWFL_E_NOERROR;
    1356             : }
    1357             : 
    1358             : /* Try to start up libdw on either the main file or the debuginfo file.  */
    1359             : static void
    1360        5866 : find_dw (Dwfl_Module *mod)
    1361             : {
    1362        5866 :   if (mod->dw != NULL                /* Already done.  */
    1363        5494 :       || mod->dwerr != DWFL_E_NOERROR) /* Cached previous failure.  */
    1364             :     return;
    1365             : 
    1366        5285 :   __libdwfl_getelf (mod);
    1367        5285 :   mod->dwerr = mod->elferr;
    1368        5285 :   if (mod->dwerr != DWFL_E_NOERROR)
    1369             :     return;
    1370             : 
    1371             :   /* First see if the main ELF file has the debugging information.  */
    1372        5271 :   mod->dwerr = load_dw (mod, &mod->main);
    1373        5271 :   switch (mod->dwerr)
    1374             :     {
    1375             :     case DWFL_E_NOERROR:
    1376        5177 :       mod->debug.elf = mod->main.elf;
    1377        5177 :       mod->debug.address_sync = mod->main.address_sync;
    1378             : 
    1379             :       /* The Dwarf might need an alt debug file, find that now after
    1380             :          everything about the debug file has been setup (the
    1381             :          find_debuginfo callback might need it).  */
    1382        5177 :       find_debug_altlink (mod, mod->main.name);
    1383        5177 :       return;
    1384             : 
    1385             :     case DWFL_E_NO_DWARF:
    1386             :       break;
    1387             : 
    1388             :     default:
    1389             :       goto canonicalize;
    1390             :     }
    1391             : 
    1392             :   /* Now we have to look for a separate debuginfo file.  */
    1393          93 :   mod->dwerr = find_debuginfo (mod);
    1394          93 :   switch (mod->dwerr)
    1395             :     {
    1396             :     case DWFL_E_NOERROR:
    1397          36 :       mod->dwerr = load_dw (mod, &mod->debug);
    1398          36 :       if (mod->dwerr == DWFL_E_NOERROR)
    1399             :         {
    1400             :           /* The Dwarf might need an alt debug file, find that now after
    1401             :              everything about the debug file has been setup (the
    1402             :              find_debuginfo callback might need it).  */
    1403          36 :           find_debug_altlink (mod, mod->debug.name);
    1404          36 :           return;
    1405             :         }
    1406             : 
    1407             :       break;
    1408             : 
    1409             :     case DWFL_E_CB:             /* The find_debuginfo hook failed.  */
    1410          57 :       mod->dwerr = DWFL_E_NO_DWARF;
    1411          57 :       return;
    1412             : 
    1413             :     default:
    1414             :       break;
    1415             :     }
    1416             : 
    1417             :  canonicalize:
    1418           1 :   mod->dwerr = __libdwfl_canon_error (mod->dwerr);
    1419             : }
    1420             : 
    1421             : Dwarf *
    1422        5866 : dwfl_module_getdwarf (Dwfl_Module *mod, Dwarf_Addr *bias)
    1423             : {
    1424        5866 :   if (mod == NULL)
    1425             :     return NULL;
    1426             : 
    1427        5866 :   find_dw (mod);
    1428        5866 :   if (mod->dwerr == DWFL_E_NOERROR)
    1429             :     {
    1430             :       /* If dwfl_module_getelf was used previously, then partial apply
    1431             :          relocation to miscellaneous sections in the debug file too.  */
    1432        5585 :       if (mod->e_type == ET_REL
    1433          47 :           && mod->main.relocated && ! mod->debug.relocated)
    1434             :         {
    1435          26 :           mod->debug.relocated = true;
    1436          26 :           if (mod->debug.elf != mod->main.elf)
    1437           0 :             (void) __libdwfl_relocate (mod, mod->debug.elf, false);
    1438             :         }
    1439             : 
    1440        5585 :       *bias = dwfl_adjusted_dwarf_addr (mod, 0);
    1441        5585 :       return mod->dw;
    1442             :     }
    1443             : 
    1444         281 :   __libdwfl_seterrno (mod->dwerr);
    1445         281 :   return NULL;
    1446             : }
    1447             : INTDEF (dwfl_module_getdwarf)
    1448             : 
    1449             : int
    1450      749393 : dwfl_module_getsymtab (Dwfl_Module *mod)
    1451             : {
    1452      749393 :   if (mod == NULL)
    1453             :     return -1;
    1454             : 
    1455      749393 :   find_symtab (mod);
    1456      749393 :   if (mod->symerr == DWFL_E_NOERROR)
    1457             :     /* We will skip the auxiliary zero entry if there is another one.  */
    1458      749390 :     return (mod->syments + mod->aux_syments
    1459      749390 :             - (mod->syments > 0 && mod->aux_syments > 0 ? 1 : 0));
    1460             : 
    1461           3 :   __libdwfl_seterrno (mod->symerr);
    1462           3 :   return -1;
    1463             : }
    1464             : INTDEF (dwfl_module_getsymtab)
    1465             : 
    1466             : int
    1467      592049 : dwfl_module_getsymtab_first_global (Dwfl_Module *mod)
    1468             : {
    1469      592049 :   if (mod == NULL)
    1470             :     return -1;
    1471             : 
    1472      592049 :   find_symtab (mod);
    1473      592049 :   if (mod->symerr == DWFL_E_NOERROR)
    1474             :     {
    1475             :       /* All local symbols should come before all global symbols.  If
    1476             :          we have an auxiliary table make sure all the main locals come
    1477             :          first, then all aux locals, then all main globals and finally all
    1478             :          aux globals.  And skip the auxiliary table zero undefined
    1479             :          entry.  */
    1480      592049 :       int skip_aux_zero = (mod->syments > 0 && mod->aux_syments > 0) ? 1 : 0;
    1481      592049 :       return mod->first_global + mod->aux_first_global - skip_aux_zero;
    1482             :     }
    1483             : 
    1484           0 :   __libdwfl_seterrno (mod->symerr);
    1485           0 :   return -1;
    1486             : }
    1487             : INTDEF (dwfl_module_getsymtab_first_global)

Generated by: LCOV version 1.12