LCOV - code coverage report
Current view: top level - elfutils/libdwfl - offline.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 49 101 48.5 %
Date: 2012-10-31 Functions: 5 7 71.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 33 93 35.5 %

           Branch data     Line data    Source code
       1                 :            : /* Recover relocatibility for addresses computed from debug information.
       2                 :            :    Copyright (C) 2005-2009, 2012 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 <fcntl.h>
      31                 :            : #include <unistd.h>
      32                 :            : 
      33                 :            : /* Since dwfl_report_elf lays out the sections already, this will only be
      34                 :            :    called when the section headers of the debuginfo file are being
      35                 :            :    consulted instead, or for the section placed at 0.  With binutils
      36                 :            :    strip-to-debug, the symbol table is in the debuginfo file and relocation
      37                 :            :    looks there.  */
      38                 :            : int
      39                 :      95735 : dwfl_offline_section_address (Dwfl_Module *mod,
      40                 :            :                               void **userdata __attribute__ ((unused)),
      41                 :            :                               const char *modname __attribute__ ((unused)),
      42                 :            :                               Dwarf_Addr base __attribute__ ((unused)),
      43                 :            :                               const char *secname __attribute__ ((unused)),
      44                 :            :                               Elf32_Word shndx,
      45                 :            :                               const GElf_Shdr *shdr __attribute__ ((unused)),
      46                 :            :                               Dwarf_Addr *addr)
      47                 :            : {
      48         [ -  + ]:      95735 :   assert (mod->e_type == ET_REL);
      49         [ -  + ]:      95735 :   assert (shdr->sh_addr == 0);
      50         [ -  + ]:      95735 :   assert (shdr->sh_flags & SHF_ALLOC);
      51                 :            : 
      52         [ +  + ]:      95735 :   if (mod->debug.elf == NULL)
      53                 :            :     /* We are only here because sh_addr is zero even though layout is complete.
      54                 :            :        The first section in the first file under -e is placed at 0.  */
      55                 :            :     return 0;
      56                 :            : 
      57                 :            :   /* The section numbers might not match between the two files.
      58                 :            :      The best we can rely on is the order of SHF_ALLOC sections.  */
      59                 :            : 
      60                 :      85298 :   Elf_Scn *ourscn = elf_getscn (mod->debug.elf, shndx);
      61                 :      85298 :   Elf_Scn *scn = NULL;
      62                 :      85298 :   uint_fast32_t skip_alloc = 0;
      63         [ +  + ]:      85343 :   while ((scn = elf_nextscn (mod->debug.elf, scn)) != ourscn)
      64                 :            :     {
      65         [ -  + ]:         45 :       assert (scn != NULL);
      66                 :            :       GElf_Shdr shdr_mem;
      67                 :         45 :       GElf_Shdr *sh = gelf_getshdr (scn, &shdr_mem);
      68         [ -  + ]:         45 :       if (unlikely (sh == NULL))
      69                 :            :         return -1;
      70         [ +  + ]:         45 :       if (sh->sh_flags & SHF_ALLOC)
      71                 :         45 :         ++skip_alloc;
      72                 :            :     }
      73                 :            : 
      74                 :            :   scn = NULL;
      75         [ +  - ]:     181063 :   while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
      76                 :            :     {
      77                 :            :       GElf_Shdr shdr_mem;
      78                 :      85328 :       GElf_Shdr *main_shdr = gelf_getshdr (scn, &shdr_mem);
      79         [ +  - ]:      85328 :       if (unlikely (main_shdr == NULL))
      80                 :            :         return -1;
      81 [ +  + ][ +  + ]:      85328 :       if ((main_shdr->sh_flags & SHF_ALLOC) && skip_alloc-- == 0)
      82                 :            :         {
      83         [ -  + ]:      85298 :           assert (main_shdr->sh_flags == shdr->sh_flags);
      84                 :      85328 :           *addr = main_shdr->sh_addr;
      85                 :            :           return 0;
      86                 :            :         }
      87                 :            :     }
      88                 :            : 
      89                 :            :   /* This should never happen.  */
      90                 :            :   return -1;
      91                 :            : }
      92                 :            : INTDEF (dwfl_offline_section_address)
      93                 :            : 
      94                 :            : /* Forward declarations.  */
      95                 :            : static Dwfl_Module *process_elf (Dwfl *dwfl, const char *name,
      96                 :            :                                  const char *file_name, int fd, Elf *elf);
      97                 :            : static Dwfl_Module *process_archive (Dwfl *dwfl, const char *name,
      98                 :            :                                      const char *file_name, int fd, Elf *elf,
      99                 :            :                                      int (*predicate) (const char *module,
     100                 :            :                                                        const char *file));
     101                 :            : 
     102                 :            : /* Report one module for an ELF file, or many for an archive.
     103                 :            :    Always consumes ELF and FD.  */
     104                 :            : static Dwfl_Module *
     105                 :        123 : process_file (Dwfl *dwfl, const char *name, const char *file_name, int fd,
     106                 :            :               Elf *elf, int (*predicate) (const char *module,
     107                 :            :                                           const char *file))
     108                 :            : {
     109      [ -  +  - ]:        123 :   switch (elf_kind (elf))
     110                 :            :     {
     111                 :            :     default:
     112                 :            :     case ELF_K_NONE:
     113         [ #  # ]:          0 :       __libdwfl_seterrno (elf == NULL ? DWFL_E_LIBELF : DWFL_E_BADELF);
     114                 :          0 :       return NULL;
     115                 :            : 
     116                 :            :     case ELF_K_ELF:
     117                 :        123 :       return process_elf (dwfl, name, file_name, fd, elf);
     118                 :            : 
     119                 :            :     case ELF_K_AR:
     120                 :        123 :       return process_archive (dwfl, name, file_name, fd, elf, predicate);
     121                 :            :     }
     122                 :            : }
     123                 :            : 
     124                 :            : /* Report the open ELF file as a module.  Always consumes ELF and FD.  */
     125                 :            : static Dwfl_Module *
     126                 :        123 : process_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd,
     127                 :            :              Elf *elf)
     128                 :            : {
     129                 :        123 :   Dwfl_Module *mod = __libdwfl_report_elf (dwfl, name, file_name, fd, elf,
     130                 :            :                                            dwfl->offline_next_address, false);
     131         [ +  - ]:        123 :   if (mod != NULL)
     132                 :            :     {
     133                 :            :       /* If this is an ET_EXEC file with fixed addresses, the address range
     134                 :            :          it consumed may or may not intersect with the arbitrary range we
     135                 :            :          will use for relocatable modules.  Make sure we always use a free
     136                 :            :          range for the offline allocations.  If this module did use
     137                 :            :          offline_next_address, it may have rounded it up for the module's
     138                 :            :          alignment requirements.  */
     139         [ +  + ]:        123 :       if ((dwfl->offline_next_address >= mod->low_addr
     140         [ +  + ]:         63 :            || mod->low_addr - dwfl->offline_next_address < OFFLINE_REDZONE)
     141         [ +  - ]:         62 :           && dwfl->offline_next_address < mod->high_addr + OFFLINE_REDZONE)
     142                 :         62 :         dwfl->offline_next_address = mod->high_addr + OFFLINE_REDZONE;
     143                 :            : 
     144                 :            :       /* Don't keep the file descriptor around.  */
     145 [ +  - ][ +  - ]:        123 :       if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
     146                 :            :         {
     147                 :        123 :           close (mod->main.fd);
     148                 :        123 :           mod->main.fd = -1;
     149                 :            :         }
     150                 :            :     }
     151                 :            : 
     152                 :        123 :   return mod;
     153                 :            : }
     154                 :            : 
     155                 :            : /* Always consumes MEMBER.  Returns elf_next result on success.
     156                 :            :    For errors returns ELF_C_NULL with *MOD set to null.  */
     157                 :            : static Elf_Cmd
     158                 :          0 : process_archive_member (Dwfl *dwfl, const char *name, const char *file_name,
     159                 :            :                         int (*predicate) (const char *module, const char *file),
     160                 :            :                         int fd, Elf *member, Dwfl_Module **mod)
     161                 :            : {
     162                 :          0 :   const Elf_Arhdr *h = elf_getarhdr (member);
     163         [ #  # ]:          0 :   if (unlikely (h == NULL))
     164                 :            :     {
     165                 :          0 :       __libdwfl_seterrno (DWFL_E_LIBELF);
     166                 :            :     fail:
     167                 :          0 :       elf_end (member);
     168                 :          0 :       *mod = NULL;
     169                 :            :       return ELF_C_NULL;
     170                 :            :     }
     171                 :            : 
     172 [ #  # ][ #  # ]:          0 :   if (!strcmp (h->ar_name, "/") || !strcmp (h->ar_name, "//")
         [ #  # ][ #  # ]
                 [ #  # ]
     173         [ #  # ]:          0 :       || !strcmp (h->ar_name, "/SYM64/"))
     174                 :            :     {
     175                 :            :     skip:;
     176                 :            :       /* Skip this and go to the next.  */
     177                 :          0 :       Elf_Cmd result = elf_next (member);
     178                 :          0 :       elf_end (member);
     179                 :            :       return result;
     180                 :            :     }
     181                 :            : 
     182                 :            :   char *member_name;
     183         [ #  # ]:          0 :   if (unlikely (asprintf (&member_name, "%s(%s)", file_name, h->ar_name) < 0))
     184                 :            :     {
     185                 :            :     nomem:
     186                 :          0 :       __libdwfl_seterrno (DWFL_E_NOMEM);
     187                 :          0 :       elf_end (member);
     188                 :          0 :       *mod = NULL;
     189                 :            :       return ELF_C_NULL;
     190                 :            :     }
     191                 :            : 
     192                 :          0 :   char *module_name = NULL;
     193 [ #  # ][ #  # ]:          0 :   if (name == NULL || name[0] == '\0')
     194                 :          0 :     name = h->ar_name;
     195         [ #  # ]:          0 :   else if (unlikely (asprintf (&module_name, "%s:%s", name, h->ar_name) < 0))
     196                 :            :     {
     197                 :          0 :       free (member_name);
     198                 :          0 :       goto nomem;
     199                 :            :     }
     200                 :            :   else
     201                 :          0 :     name = module_name;
     202                 :            : 
     203         [ #  # ]:          0 :   if (predicate != NULL)
     204                 :            :     {
     205                 :            :       /* Let the predicate decide whether to use this one.  */
     206                 :          0 :       int want = (*predicate) (name, member_name);
     207         [ #  # ]:          0 :       if (want <= 0)
     208                 :            :         {
     209                 :          0 :           free (member_name);
     210                 :          0 :           free (module_name);
     211         [ #  # ]:          0 :           if (unlikely (want < 0))
     212                 :            :             {
     213                 :          0 :               __libdwfl_seterrno (DWFL_E_CB);
     214                 :          0 :               goto fail;
     215                 :            :             }
     216                 :            :           goto skip;
     217                 :            :         }
     218                 :            :     }
     219                 :            : 
     220                 :            :   /* We let __libdwfl_report_elf cache the fd in mod->main.fd,
     221                 :            :      though it's the same fd for all the members.
     222                 :            :      On module teardown we will close it only on the last Elf reference.  */
     223                 :          0 :   *mod = process_file (dwfl, name, member_name, fd, member, predicate);
     224                 :          0 :   free (member_name);
     225                 :          0 :   free (module_name);
     226                 :            : 
     227         [ #  # ]:          0 :   if (*mod == NULL)             /* process_file called elf_end.  */
     228                 :            :     return ELF_C_NULL;
     229                 :            : 
     230                 :            :   /* Advance the archive-reading offset for the next iteration.  */
     231                 :          0 :   return elf_next (member);
     232                 :            : }
     233                 :            : 
     234                 :            : /* Report each member of the archive as its own module.  */
     235                 :            : static Dwfl_Module *
     236                 :          0 : process_archive (Dwfl *dwfl, const char *name, const char *file_name, int fd,
     237                 :            :                  Elf *archive,
     238                 :            :                  int (*predicate) (const char *module, const char *file))
     239                 :            : 
     240                 :            : {
     241                 :          0 :   Dwfl_Module *mod = NULL;
     242                 :          0 :   Elf *member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive);
     243         [ #  # ]:          0 :   if (unlikely (member == NULL)) /* Empty archive.  */
     244                 :            :     {
     245                 :          0 :       __libdwfl_seterrno (DWFL_E_BADELF);
     246                 :            :       return NULL;
     247                 :            :     }
     248                 :            : 
     249         [ #  # ]:          0 :   while (process_archive_member (dwfl, name, file_name, predicate,
     250                 :            :                                  fd, member, &mod) != ELF_C_NULL)
     251                 :          0 :     member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive);
     252                 :            : 
     253                 :            :   /* We can drop the archive Elf handle even if we're still using members
     254                 :            :      in live modules.  When the last module's elf_end on a member returns
     255                 :            :      zero, that module will close FD.  If no modules survived the predicate,
     256                 :            :      we are all done with the file right here.  */
     257         [ #  # ]:          0 :   if (mod != NULL               /* If no modules, caller will clean up.  */
     258         [ #  # ]:          0 :       && elf_end (archive) == 0)
     259                 :          0 :     close (fd);
     260                 :            : 
     261                 :          0 :   return mod;
     262                 :            : }
     263                 :            : 
     264                 :            : Dwfl_Module *
     265                 :            : internal_function
     266                 :        123 : __libdwfl_report_offline (Dwfl *dwfl, const char *name,
     267                 :            :                           const char *file_name, int fd, bool closefd,
     268                 :            :                           int (*predicate) (const char *module,
     269                 :            :                                             const char *file))
     270                 :            : {
     271                 :            :   Elf *elf;
     272                 :        123 :   Dwfl_Error error = __libdw_open_file (&fd, &elf, closefd, true);
     273         [ -  + ]:        123 :   if (error != DWFL_E_NOERROR)
     274                 :            :     {
     275                 :          0 :       __libdwfl_seterrno (error);
     276                 :            :       return NULL;
     277                 :            :     }
     278                 :        123 :   Dwfl_Module *mod = process_file (dwfl, name, file_name, fd, elf, predicate);
     279         [ -  + ]:        123 :   if (mod == NULL)
     280                 :            :     {
     281                 :          0 :       elf_end (elf);
     282         [ #  # ]:          0 :       if (closefd)
     283                 :        123 :         close (fd);
     284                 :            :     }
     285                 :            :   return mod;
     286                 :            : }
     287                 :            : 
     288                 :            : Dwfl_Module *
     289                 :        123 : dwfl_report_offline (Dwfl *dwfl, const char *name,
     290                 :            :                      const char *file_name, int fd)
     291                 :            : {
     292         [ +  - ]:        123 :   if (dwfl == NULL)
     293                 :            :     return NULL;
     294                 :            : 
     295                 :        123 :   bool closefd = false;
     296         [ +  + ]:        123 :   if (fd < 0)
     297                 :            :     {
     298                 :         51 :       closefd = true;
     299                 :         51 :       fd = open64 (file_name, O_RDONLY);
     300         [ -  + ]:         51 :       if (fd < 0)
     301                 :            :         {
     302                 :          0 :           __libdwfl_seterrno (DWFL_E_ERRNO);
     303                 :          0 :           return NULL;
     304                 :            :         }
     305                 :            :     }
     306                 :            : 
     307                 :        123 :   return __libdwfl_report_offline (dwfl, name, file_name, fd, closefd, NULL);
     308                 :            : }
     309                 :            : INTDEF (dwfl_report_offline)

Generated by: LCOV version 1.9