LCOV - code coverage report
Current view: top level - libdwfl - offline.c (source / functions) Coverage Total Hit
Test: elfutils-0.193 Lines: 69.8 % 139 97
Test Date: 2025-04-25 16:41:10 Functions: 100.0 % 8 8
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 59.8 % 97 58

             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                 :             :    Copyright (C) 2022 Mark J. Wielaard <mark@klomp.org>
       4                 :             :    Copyright (C) 2022 Google LLC
       5                 :             :    This file is part of elfutils.
       6                 :             : 
       7                 :             :    This file is free software; you can redistribute it and/or modify
       8                 :             :    it under the terms of either
       9                 :             : 
      10                 :             :      * the GNU Lesser General Public License as published by the Free
      11                 :             :        Software Foundation; either version 3 of the License, or (at
      12                 :             :        your option) any later version
      13                 :             : 
      14                 :             :    or
      15                 :             : 
      16                 :             :      * the GNU General Public License as published by the Free
      17                 :             :        Software Foundation; either version 2 of the License, or (at
      18                 :             :        your option) any later version
      19                 :             : 
      20                 :             :    or both in parallel, as here.
      21                 :             : 
      22                 :             :    elfutils is distributed in the hope that it will be useful, but
      23                 :             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      24                 :             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      25                 :             :    General Public License for more details.
      26                 :             : 
      27                 :             :    You should have received copies of the GNU General Public License and
      28                 :             :    the GNU Lesser General Public License along with this program.  If
      29                 :             :    not, see <http://www.gnu.org/licenses/>.  */
      30                 :             : 
      31                 :             : #ifdef HAVE_CONFIG_H
      32                 :             : # include <config.h>
      33                 :             : #endif
      34                 :             : 
      35                 :             : #include "libelfP.h"
      36                 :             : #include "libdwflP.h"
      37                 :             : #include <fcntl.h>
      38                 :             : 
      39                 :             : /* Since dwfl_report_elf lays out the sections already, this will only be
      40                 :             :    called when the section headers of the debuginfo file are being
      41                 :             :    consulted instead, or for the section placed at 0.  With binutils
      42                 :             :    strip-to-debug, the symbol table is in the debuginfo file and relocation
      43                 :             :    looks there.  */
      44                 :             : int
      45                 :        8428 : dwfl_offline_section_address (Dwfl_Module *mod,
      46                 :             :                               void **userdata __attribute__ ((unused)),
      47                 :             :                               const char *modname __attribute__ ((unused)),
      48                 :             :                               Dwarf_Addr base __attribute__ ((unused)),
      49                 :             :                               const char *secname __attribute__ ((unused)),
      50                 :             :                               Elf32_Word shndx,
      51                 :             :                               const GElf_Shdr *shdr __attribute__ ((unused)),
      52                 :             :                               Dwarf_Addr *addr)
      53                 :             : {
      54         [ +  - ]:        8428 :   if (mod->e_type != ET_REL
      55         [ +  - ]:        8428 :       || shdr->sh_addr != 0
      56         [ +  - ]:        8428 :       || !(shdr->sh_flags & SHF_ALLOC)
      57         [ -  + ]:        8428 :       || shndx == 0)
      58                 :           0 :     return -1;
      59                 :             : 
      60         [ +  + ]:        8428 :   if (mod->debug.elf == NULL)
      61                 :             :     /* We are only here because sh_addr is zero even though layout is complete.
      62                 :             :        The first section in the first file under -e is placed at 0.  */
      63                 :        8292 :     return 0;
      64                 :             : 
      65                 :             :   /* The section numbers might not match between the two files.
      66                 :             :      The best we can rely on is the order of SHF_ALLOC sections.  */
      67                 :             : 
      68                 :         136 :   Elf_Scn *ourscn = elf_getscn (mod->debug.elf, shndx);
      69                 :         136 :   Elf_Scn *scn = NULL;
      70                 :         136 :   uint_fast32_t skip_alloc = 0;
      71         [ +  + ]:         226 :   while ((scn = elf_nextscn (mod->debug.elf, scn)) != ourscn)
      72                 :             :     {
      73         [ -  + ]:          90 :       assert (scn != NULL);
      74                 :             :       GElf_Shdr shdr_mem;
      75                 :          90 :       GElf_Shdr *sh = gelf_getshdr (scn, &shdr_mem);
      76         [ -  + ]:          90 :       if (unlikely (sh == NULL))
      77                 :           0 :         return -1;
      78         [ +  + ]:          90 :       if (sh->sh_flags & SHF_ALLOC)
      79                 :          56 :         ++skip_alloc;
      80                 :             :     }
      81                 :             : 
      82                 :         136 :   scn = NULL;
      83         [ +  - ]:         196 :   while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
      84                 :             :     {
      85                 :             :       GElf_Shdr shdr_mem;
      86                 :         196 :       GElf_Shdr *main_shdr = gelf_getshdr (scn, &shdr_mem);
      87         [ -  + ]:         196 :       if (unlikely (main_shdr == NULL))
      88                 :         136 :         return -1;
      89   [ +  +  +  + ]:         196 :       if ((main_shdr->sh_flags & SHF_ALLOC) && skip_alloc-- == 0)
      90                 :             :         {
      91         [ -  + ]:         136 :           assert (main_shdr->sh_flags == shdr->sh_flags);
      92                 :         136 :           *addr = main_shdr->sh_addr;
      93                 :         136 :           return 0;
      94                 :             :         }
      95                 :             :     }
      96                 :             : 
      97                 :             :   /* This should never happen.  */
      98                 :           0 :   return -1;
      99                 :             : }
     100                 :             : INTDEF (dwfl_offline_section_address)
     101                 :             : 
     102                 :             : /* Forward declarations.  */
     103                 :             : static Dwfl_Module *process_elf (Dwfl *dwfl, const char *name,
     104                 :             :                                  const char *file_name, int fd, Elf *elf);
     105                 :             : static Dwfl_Module *process_archive (Dwfl *dwfl, const char *name,
     106                 :             :                                      const char *file_name, int fd, Elf *elf,
     107                 :             :                                      int (*predicate) (const char *module,
     108                 :             :                                                        const char *file));
     109                 :             : 
     110                 :             : /* Report one module for an ELF file, or many for an archive.
     111                 :             :    Always consumes ELF and FD.  */
     112                 :             : static Dwfl_Module *
     113                 :        1440 : process_file (Dwfl *dwfl, const char *name, const char *file_name, int fd,
     114                 :             :               Elf *elf, int (*predicate) (const char *module,
     115                 :             :                                           const char *file))
     116                 :             : {
     117      [ -  +  + ]:        1440 :   switch (elf_kind (elf))
     118                 :             :     {
     119                 :           0 :     default:
     120                 :             :     case ELF_K_NONE:
     121         [ #  # ]:           0 :       __libdwfl_seterrno (elf == NULL ? DWFL_E_LIBELF : DWFL_E_BADELF);
     122                 :           0 :       return NULL;
     123                 :             : 
     124                 :        1436 :     case ELF_K_ELF:
     125                 :        1436 :       return process_elf (dwfl, name, file_name, fd, elf);
     126                 :             : 
     127                 :           4 :     case ELF_K_AR:
     128                 :           4 :       return process_archive (dwfl, name, file_name, fd, elf, predicate);
     129                 :             :     }
     130                 :             : }
     131                 :             : 
     132                 :             : /* Report the open ELF file as a module.  Always consumes ELF and FD.  */
     133                 :             : static Dwfl_Module *
     134                 :        1436 : process_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd,
     135                 :             :              Elf *elf)
     136                 :             : {
     137                 :        1436 :   Dwfl_Module *mod = __libdwfl_report_elf (dwfl, name, file_name, fd, elf,
     138                 :             :                                            dwfl->offline_next_address, true,
     139                 :             :                                            false);
     140         [ +  - ]:        1436 :   if (mod != NULL)
     141                 :             :     {
     142                 :             :       /* If this is an ET_EXEC file with fixed addresses, the address range
     143                 :             :          it consumed may or may not intersect with the arbitrary range we
     144                 :             :          will use for relocatable modules.  Make sure we always use a free
     145                 :             :          range for the offline allocations.  If this module did use
     146                 :             :          offline_next_address, it may have rounded it up for the module's
     147                 :             :          alignment requirements.  */
     148         [ +  + ]:        1436 :       if ((dwfl->offline_next_address >= mod->low_addr
     149         [ +  + ]:         910 :            || mod->low_addr - dwfl->offline_next_address < OFFLINE_REDZONE)
     150         [ +  - ]:         548 :           && dwfl->offline_next_address < mod->high_addr + OFFLINE_REDZONE)
     151                 :         548 :         dwfl->offline_next_address = mod->high_addr + OFFLINE_REDZONE;
     152                 :             : 
     153                 :             :       /* Don't keep the file descriptor around.  */
     154   [ +  +  +  - ]:        1436 :       if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
     155                 :             :         {
     156                 :             :           /* Grab the path in case we want to report this file as
     157                 :             :              Dwarf later.  */
     158                 :        1408 :           mod->elfpath = __libdw_elfpath (mod->main.fd);
     159                 :        1408 :           close (mod->main.fd);
     160                 :        1408 :           mod->main.fd = -1;
     161                 :             :         }
     162                 :             :     }
     163                 :             : 
     164                 :        1436 :   return mod;
     165                 :             : }
     166                 :             : 
     167                 :             : /* Always consumes MEMBER.  Returns elf_next result on success.
     168                 :             :    For errors returns ELF_C_NULL with *MOD set to null.  */
     169                 :             : static Elf_Cmd
     170                 :          16 : process_archive_member (Dwfl *dwfl, const char *name, const char *file_name,
     171                 :             :                         int (*predicate) (const char *module, const char *file),
     172                 :             :                         int fd, Elf *member, Dwfl_Module **mod)
     173                 :             : {
     174                 :          16 :   const Elf_Arhdr *h = elf_getarhdr (member);
     175         [ -  + ]:          16 :   if (unlikely (h == NULL))
     176                 :             :     {
     177                 :           0 :       __libdwfl_seterrno (DWFL_E_LIBELF);
     178                 :           0 :     fail:
     179                 :           0 :       elf_end (member);
     180                 :           0 :       *mod = NULL;
     181                 :           0 :       return ELF_C_NULL;
     182                 :             :     }
     183                 :             : 
     184   [ +  +  -  + ]:          16 :   if (!strcmp (h->ar_name, "/") || !strcmp (h->ar_name, "//")
     185         [ +  + ]:          14 :       || !strcmp (h->ar_name, "/SYM64/"))
     186                 :             :     {
     187                 :           4 :     skip:;
     188                 :             :       /* Skip this and go to the next.  */
     189                 :           4 :       Elf_Cmd result = elf_next (member);
     190                 :           4 :       elf_end (member);
     191                 :           4 :       return result;
     192                 :             :     }
     193                 :             : 
     194                 :             :   char *member_name;
     195         [ -  + ]:          12 :   if (unlikely (asprintf (&member_name, "%s(%s)", file_name, h->ar_name) < 0))
     196                 :             :     {
     197                 :           0 :     nomem:
     198                 :           0 :       __libdwfl_seterrno (DWFL_E_NOMEM);
     199                 :           0 :       elf_end (member);
     200                 :           0 :       *mod = NULL;
     201                 :           0 :       return ELF_C_NULL;
     202                 :             :     }
     203                 :             : 
     204                 :          12 :   char *module_name = NULL;
     205   [ +  -  -  + ]:          12 :   if (name == NULL || name[0] == '\0')
     206                 :           0 :     name = h->ar_name;
     207         [ -  + ]:          12 :   else if (unlikely (asprintf (&module_name, "%s:%s", name, h->ar_name) < 0))
     208                 :             :     {
     209                 :           0 :       free (member_name);
     210                 :           0 :       goto nomem;
     211                 :             :     }
     212                 :             :   else
     213                 :          12 :     name = module_name;
     214                 :             : 
     215         [ -  + ]:          12 :   if (predicate != NULL)
     216                 :             :     {
     217                 :             :       /* Let the predicate decide whether to use this one.  */
     218                 :           0 :       int want = (*predicate) (name, member_name);
     219         [ #  # ]:           0 :       if (want <= 0)
     220                 :             :         {
     221                 :           0 :           free (member_name);
     222                 :           0 :           free (module_name);
     223         [ #  # ]:           0 :           if (unlikely (want < 0))
     224                 :             :             {
     225                 :           0 :               __libdwfl_seterrno (DWFL_E_CB);
     226                 :           0 :               goto fail;
     227                 :             :             }
     228                 :           0 :           goto skip;
     229                 :             :         }
     230                 :             :     }
     231                 :             : 
     232                 :             :   /* We let __libdwfl_report_elf cache the fd in mod->main.fd,
     233                 :             :      though it's the same fd for all the members.
     234                 :             :      On module teardown we will close it only on the last Elf reference.  */
     235                 :          12 :   *mod = process_file (dwfl, name, member_name, fd, member, predicate);
     236                 :          12 :   free (member_name);
     237                 :          12 :   free (module_name);
     238                 :             : 
     239         [ -  + ]:          12 :   if (*mod == NULL)
     240                 :             :     {
     241                 :           0 :       elf_end (member);
     242                 :           0 :       return ELF_C_NULL;
     243                 :             :     }
     244                 :             : 
     245                 :             :   /* Advance the archive-reading offset for the next iteration.  */
     246                 :          12 :   return elf_next (member);
     247                 :             : }
     248                 :             : 
     249                 :             : /* Report each member of the archive as its own module.  */
     250                 :             : static Dwfl_Module *
     251                 :           4 : process_archive (Dwfl *dwfl, const char *name, const char *file_name, int fd,
     252                 :             :                  Elf *archive,
     253                 :             :                  int (*predicate) (const char *module, const char *file))
     254                 :             : 
     255                 :             : {
     256                 :           4 :   Dwfl_Module *mod = NULL;
     257                 :             :   /* elf_begin supports opening archives even with fd == -1 passed.  */
     258                 :           4 :   Elf *member = elf_begin (fd, archive->cmd, archive);
     259         [ -  + ]:           4 :   if (unlikely (member == NULL)) /* Empty archive.  */
     260                 :             :     {
     261                 :           0 :       __libdwfl_seterrno (DWFL_E_BADELF);
     262                 :           0 :       return NULL;
     263                 :             :     }
     264                 :             : 
     265                 :          16 :   while (process_archive_member (dwfl, name, file_name, predicate,
     266         [ +  + ]:          16 :                                  fd, member, &mod) != ELF_C_NULL)
     267                 :          12 :     member = elf_begin (fd, archive->cmd, archive);
     268                 :             : 
     269                 :             :   /* We can drop the archive Elf handle even if we're still using members
     270                 :             :      in live modules.  When the last module's elf_end on a member returns
     271                 :             :      zero, that module will close FD.  If no modules survived the predicate,
     272                 :             :      we are all done with the file right here.  */
     273         [ +  - ]:           4 :   if (mod != NULL               /* If no modules, caller will clean up.  */
     274         [ +  - ]:           4 :       && elf_end (archive) == 0
     275         [ -  + ]:           4 :       && fd >= 0)
     276                 :           0 :     close (fd);
     277                 :             : 
     278                 :           4 :   return mod;
     279                 :             : }
     280                 :             : 
     281                 :             : Dwfl_Module *
     282                 :             : internal_function
     283                 :        1422 : __libdwfl_report_offline (Dwfl *dwfl, const char *name,
     284                 :             :                           const char *file_name, int fd, bool closefd,
     285                 :             :                           int (*predicate) (const char *module,
     286                 :             :                                             const char *file))
     287                 :             : {
     288                 :             :   Elf *elf;
     289                 :        1422 :   Dwfl_Error error = __libdw_open_file (&fd, &elf, closefd, true);
     290         [ -  + ]:        1422 :   if (error != DWFL_E_NOERROR)
     291                 :             :     {
     292                 :           0 :       __libdwfl_seterrno (error);
     293                 :           0 :       return NULL;
     294                 :             :     }
     295                 :        1422 :   Dwfl_Module *mod = process_file (dwfl, name, file_name, fd, elf, predicate);
     296         [ -  + ]:        1422 :   if (mod == NULL)
     297                 :             :     {
     298                 :           0 :       elf_end (elf);
     299         [ #  # ]:           0 :       if (closefd)
     300                 :           0 :         close (fd);
     301                 :             :     }
     302                 :        1422 :   return mod;
     303                 :             : }
     304                 :             : 
     305                 :             : Dwfl_Module *
     306                 :        1422 : dwfl_report_offline (Dwfl *dwfl, const char *name,
     307                 :             :                      const char *file_name, int fd)
     308                 :             : {
     309         [ -  + ]:        1422 :   if (dwfl == NULL)
     310                 :           0 :     return NULL;
     311                 :             : 
     312                 :        1422 :   bool closefd = false;
     313         [ +  + ]:        1422 :   if (fd < 0)
     314                 :             :     {
     315                 :         412 :       closefd = true;
     316                 :         412 :       fd = open (file_name, O_RDONLY);
     317         [ -  + ]:         412 :       if (fd < 0)
     318                 :             :         {
     319                 :           0 :           __libdwfl_seterrno (DWFL_E_ERRNO);
     320                 :           0 :           return NULL;
     321                 :             :         }
     322                 :             :     }
     323                 :             : 
     324                 :        1422 :   return __libdwfl_report_offline (dwfl, name, file_name, fd, closefd, NULL);
     325                 :             : }
     326                 :             : INTDEF (dwfl_report_offline)
     327                 :             : 
     328                 :             : Dwfl_Module *
     329                 :          12 : dwfl_report_offline_memory (Dwfl *dwfl, const char *name,
     330                 :             :                             const char *file_name, char *data, size_t size)
     331                 :             : {
     332         [ -  + ]:          12 :   if (dwfl == NULL)
     333                 :           0 :     return NULL;
     334                 :             : 
     335                 :             :   Elf *elf;
     336                 :          12 :   Dwfl_Error error = __libdw_open_elf_memory (data, size, &elf, true);
     337         [ +  + ]:          12 :   if (error != DWFL_E_NOERROR)
     338                 :             :     {
     339                 :           6 :       __libdwfl_seterrno (error);
     340                 :           6 :       return NULL;
     341                 :             :     }
     342                 :             :   /* It is ok to pass fd == -1 here, because libelf uses it as a value for
     343                 :             :      "no file opened" and supports working with files without fd, thanks to
     344                 :             :      the existence of the elf_memory function.  */
     345                 :           6 :   Dwfl_Module *mod = process_file (dwfl, name, file_name, -1, elf, NULL);
     346         [ -  + ]:           6 :   if (mod == NULL)
     347                 :           0 :     elf_end (elf);
     348                 :           6 :   return mod;
     349                 :             : }
     350                 :             : INTDEF (dwfl_report_offline_memory)
        

Generated by: LCOV version 2.0-1