LCOV - code coverage report
Current view: top level - libdwfl - offline.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 51 116 44.0 %
Date: 2017-08-02 15:24:56 Functions: 5 7 71.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.12