LCOV - code coverage report
Current view: top level - elfutils/libdwfl - dwfl_segment_report_module.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 248 291 85.2 %
Date: 2012-10-31 Functions: 8 10 80.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 153 224 68.3 %

           Branch data     Line data    Source code
       1                 :            : /* Sniff out modules from ELF headers visible in memory segments.
       2                 :            :    Copyright (C) 2008-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 <config.h>
      30                 :            : #include "../libelf/libelfP.h"        /* For NOTE_ALIGN.  */
      31                 :            : #undef  _
      32                 :            : #include "libdwflP.h"
      33                 :            : 
      34                 :            : #include <elf.h>
      35                 :            : #include <gelf.h>
      36                 :            : #include <inttypes.h>
      37                 :            : #include <sys/param.h>
      38                 :            : #include <alloca.h>
      39                 :            : #include <endian.h>
      40                 :            : 
      41                 :            : 
      42                 :            : /* A good size for the initial read from memory, if it's not too costly.
      43                 :            :    This more than covers the phdrs and note segment in the average 64-bit
      44                 :            :    binary.  */
      45                 :            : 
      46                 :            : #define INITIAL_READ    1024
      47                 :            : 
      48                 :            : #if __BYTE_ORDER == __LITTLE_ENDIAN
      49                 :            : # define MY_ELFDATA     ELFDATA2LSB
      50                 :            : #else
      51                 :            : # define MY_ELFDATA     ELFDATA2MSB
      52                 :            : #endif
      53                 :            : 
      54                 :            : 
      55                 :            : /* Return user segment index closest to ADDR but not above it.
      56                 :            :    If NEXT, return the closest to ADDR but not below it.  */
      57                 :            : static int
      58                 :         29 : addr_segndx (Dwfl *dwfl, size_t segment, GElf_Addr addr, bool next)
      59                 :            : {
      60                 :         29 :   int ndx = -1;
      61                 :            :   do
      62                 :            :     {
      63         [ +  + ]:         66 :       if (dwfl->lookup_segndx[segment] >= 0)
      64                 :         64 :         ndx = dwfl->lookup_segndx[segment];
      65         [ -  + ]:         66 :       if (++segment >= dwfl->lookup_elts - 1)
      66         [ #  # ]:          0 :         return next ? ndx + 1 : ndx;
      67                 :            :     }
      68         [ +  + ]:         66 :   while (dwfl->lookup_addr[segment] < addr);
      69                 :            : 
      70         [ +  + ]:         29 :   if (next)
      71                 :            :     {
      72         [ +  + ]:         25 :       while (dwfl->lookup_segndx[segment] < 0)
      73         [ +  - ]:          9 :         if (++segment >= dwfl->lookup_elts - 1)
      74                 :         16 :           return ndx + 1;
      75                 :            :       ndx = dwfl->lookup_segndx[segment];
      76                 :            :     }
      77                 :            : 
      78                 :         29 :   return ndx;
      79                 :            : }
      80                 :            : 
      81                 :            : int
      82                 :         36 : dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
      83                 :            :                             Dwfl_Memory_Callback *memory_callback,
      84                 :            :                             void *memory_callback_arg,
      85                 :            :                             Dwfl_Module_Callback *read_eagerly,
      86                 :            :                             void *read_eagerly_arg)
      87                 :            : {
      88                 :         36 :   size_t segment = ndx;
      89                 :            : 
      90         [ -  + ]:         36 :   if (segment >= dwfl->lookup_elts)
      91                 :         36 :     segment = dwfl->lookup_elts - 1;
      92                 :            : 
      93         [ +  + ]:         43 :   while (segment > 0
      94         [ -  + ]:         39 :          && (dwfl->lookup_segndx[segment] > ndx
      95         [ +  + ]:         39 :              || dwfl->lookup_segndx[segment] == -1))
      96                 :          7 :     --segment;
      97                 :            : 
      98         [ +  + ]:        114 :   while (dwfl->lookup_segndx[segment] < ndx)
      99         [ +  - ]:        114 :     if (++segment == dwfl->lookup_elts)
     100                 :            :       return 0;
     101                 :            : 
     102                 :         36 :   GElf_Addr start = dwfl->lookup_addr[segment];
     103                 :            : 
     104                 :            :   inline bool segment_read (int segndx,
     105                 :            :                             void **buffer, size_t *buffer_available,
     106                 :            :                             GElf_Addr addr, size_t minread)
     107                 :            :   {
     108                 :         86 :     return ! (*memory_callback) (dwfl, segndx, buffer, buffer_available,
     109                 :         13 :                                  addr, minread, memory_callback_arg);
     110                 :            :   }
     111                 :            : 
     112                 :            :   inline void release_buffer (void **buffer, size_t *buffer_available)
     113                 :            :   {
     114 [ +  - ][ +  + ]:         45 :     if (*buffer != NULL)
     115                 :            :       (void) segment_read (-1, buffer, buffer_available, 0, 0);
     116                 :            :   }
     117                 :            : 
     118                 :            :   /* First read in the file header and check its sanity.  */
     119                 :            : 
     120                 :         36 :   void *buffer = NULL;
     121                 :         36 :   size_t buffer_available = INITIAL_READ;
     122                 :            : 
     123                 :         36 :   inline int finish (void)
     124                 :            :   {
     125                 :         36 :     release_buffer (&buffer, &buffer_available);
     126                 :         36 :     return ndx;
     127                 :            :   }
     128                 :            : 
     129         [ +  + ]:         36 :   if (segment_read (ndx, &buffer, &buffer_available,
     130                 :            :                     start, sizeof (Elf64_Ehdr))
     131         [ +  + ]:         35 :       || memcmp (buffer, ELFMAG, SELFMAG) != 0)
     132                 :         20 :     return finish ();
     133                 :            : 
     134                 :         58 :   inline bool read_portion (void **data, size_t *data_size,
     135                 :            :                             GElf_Addr vaddr, size_t filesz)
     136                 :            :   {
     137         [ +  + ]:         58 :     if (vaddr - start + filesz > buffer_available
     138                 :            :         /* If we're in string mode, then don't consider the buffer we have
     139                 :            :            sufficient unless it contains the terminator of the string.  */
     140 [ +  + ][ +  + ]:         46 :         || (filesz == 0 && memchr (vaddr - start + buffer, '\0',
     141                 :          8 :                                    buffer_available - (vaddr - start)) == NULL))
     142                 :            :       {
     143                 :         13 :         *data = NULL;
     144                 :         13 :         *data_size = filesz;
     145                 :         26 :         return segment_read (addr_segndx (dwfl, segment, vaddr, false),
     146                 :            :                              data, data_size, vaddr, filesz);
     147                 :            :       }
     148                 :            : 
     149                 :            :     /* We already have this whole note segment from our initial read.  */
     150                 :         45 :     *data = vaddr - start + buffer;
     151                 :         45 :     *data_size = 0;
     152                 :         58 :     return false;
     153                 :            :   }
     154                 :            : 
     155                 :         64 :   inline void finish_portion (void **data, size_t *data_size)
     156                 :            :   {
     157         [ +  + ]:         64 :     if (*data_size != 0)
     158                 :            :       release_buffer (data, data_size);
     159                 :         64 :   }
     160                 :            : 
     161                 :            :   /* Extract the information we need from the file header.  */
     162                 :            :   union
     163                 :            :   {
     164                 :            :     Elf32_Ehdr e32;
     165                 :            :     Elf64_Ehdr e64;
     166                 :            :   } ehdr;
     167                 :            :   GElf_Off phoff;
     168                 :            :   uint_fast16_t phnum;
     169                 :            :   uint_fast16_t phentsize;
     170                 :            :   GElf_Off shdrs_end;
     171                 :         16 :   Elf_Data xlatefrom =
     172                 :            :     {
     173                 :            :       .d_type = ELF_T_EHDR,
     174                 :            :       .d_buf = (void *) buffer,
     175                 :            :       .d_version = EV_CURRENT,
     176                 :            :     };
     177                 :         16 :   Elf_Data xlateto =
     178                 :            :     {
     179                 :            :       .d_type = ELF_T_EHDR,
     180                 :            :       .d_buf = &ehdr,
     181                 :            :       .d_size = sizeof ehdr,
     182                 :            :       .d_version = EV_CURRENT,
     183                 :            :     };
     184      [ +  +  - ]:         16 :   switch (((const unsigned char *) buffer)[EI_CLASS])
     185                 :            :     {
     186                 :            :     case ELFCLASS32:
     187                 :         12 :       xlatefrom.d_size = sizeof (Elf32_Ehdr);
     188         [ -  + ]:         12 :       if (elf32_xlatetom (&xlateto, &xlatefrom,
     189                 :         12 :                           ((const unsigned char *) buffer)[EI_DATA]) == NULL)
     190                 :          0 :         return finish ();
     191                 :         12 :       phoff = ehdr.e32.e_phoff;
     192                 :         12 :       phnum = ehdr.e32.e_phnum;
     193                 :         12 :       phentsize = ehdr.e32.e_phentsize;
     194         [ -  + ]:         12 :       if (phentsize != sizeof (Elf32_Phdr))
     195                 :          0 :         return finish ();
     196                 :         12 :       shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize;
     197                 :         12 :       break;
     198                 :            : 
     199                 :            :     case ELFCLASS64:
     200                 :          4 :       xlatefrom.d_size = sizeof (Elf64_Ehdr);
     201         [ -  + ]:          4 :       if (elf64_xlatetom (&xlateto, &xlatefrom,
     202                 :          4 :                           ((const unsigned char *) buffer)[EI_DATA]) == NULL)
     203                 :          0 :         return finish ();
     204                 :          4 :       phoff = ehdr.e64.e_phoff;
     205                 :          4 :       phnum = ehdr.e64.e_phnum;
     206                 :          4 :       phentsize = ehdr.e64.e_phentsize;
     207         [ -  + ]:          4 :       if (phentsize != sizeof (Elf64_Phdr))
     208                 :          0 :         return finish ();
     209                 :          4 :       shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize;
     210                 :          4 :       break;
     211                 :            : 
     212                 :            :     default:
     213                 :          0 :       return finish ();
     214                 :            :     }
     215                 :            : 
     216                 :            :   /* The file header tells where to find the program headers.
     217                 :            :      These are what we need to find the boundaries of the module.
     218                 :            :      Without them, we don't have a module to report.  */
     219                 :            : 
     220         [ -  + ]:         16 :   if (phnum == 0)
     221                 :          0 :     return finish ();
     222                 :            : 
     223                 :         16 :   xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
     224                 :         16 :   xlatefrom.d_size = phnum * phentsize;
     225                 :            : 
     226                 :         16 :   void *ph_buffer = NULL;
     227                 :         16 :   size_t ph_buffer_size = 0;
     228         [ -  + ]:         16 :   if (read_portion (&ph_buffer, &ph_buffer_size,
     229                 :            :                     start + phoff, xlatefrom.d_size))
     230                 :          0 :     return finish ();
     231                 :            : 
     232                 :         16 :   xlatefrom.d_buf = ph_buffer;
     233                 :            : 
     234                 :         48 :   union
     235                 :            :   {
     236                 :         16 :     Elf32_Phdr p32[phnum];
     237                 :         16 :     Elf64_Phdr p64[phnum];
     238                 :         16 :   } phdrs;
     239                 :            : 
     240                 :         16 :   xlateto.d_buf = &phdrs;
     241                 :         16 :   xlateto.d_size = sizeof phdrs;
     242                 :            : 
     243                 :            :   /* Track the bounds of the file visible in memory.  */
     244                 :         16 :   GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end.  */
     245                 :         16 :   GElf_Off file_end = 0;         /* Rounded up to effective page size.  */
     246                 :         16 :   GElf_Off contiguous = 0;       /* Visible as contiguous file from START.  */
     247                 :         16 :   GElf_Off total_filesz = 0;     /* Total size of data to read.  */
     248                 :            : 
     249                 :            :   /* Collect the bias between START and the containing PT_LOAD's p_vaddr.  */
     250                 :         16 :   GElf_Addr bias = 0;
     251                 :         16 :   bool found_bias = false;
     252                 :            : 
     253                 :            :   /* Collect the unbiased bounds of the module here.  */
     254                 :         16 :   GElf_Addr module_start = -1l;
     255                 :         16 :   GElf_Addr module_end = 0;
     256                 :         16 :   GElf_Addr module_address_sync = 0;
     257                 :            : 
     258                 :            :   /* If we see PT_DYNAMIC, record it here.  */
     259                 :         16 :   GElf_Addr dyn_vaddr = 0;
     260                 :         16 :   GElf_Xword dyn_filesz = 0;
     261                 :            : 
     262                 :            :   /* Collect the build ID bits here.  */
     263                 :         16 :   void *build_id = NULL;
     264                 :         16 :   size_t build_id_len = 0;
     265                 :         16 :   GElf_Addr build_id_vaddr = 0;
     266                 :            : 
     267                 :            :   /* Consider a PT_NOTE we've found in the image.  */
     268                 :         16 :   inline void consider_notes (GElf_Addr vaddr, GElf_Xword filesz)
     269                 :            :   {
     270                 :            :     /* If we have already seen a build ID, we don't care any more.  */
     271 [ +  - ][ +  - ]:         16 :     if (build_id != NULL || filesz == 0)
     272                 :            :       return;
     273                 :            : 
     274                 :            :     void *data;
     275                 :            :     size_t data_size;
     276         [ +  - ]:         16 :     if (read_portion (&data, &data_size, vaddr, filesz))
     277                 :            :       return;
     278                 :            : 
     279                 :            :     assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
     280                 :            : 
     281                 :            :     void *notes;
     282         [ +  + ]:         16 :     if (ehdr.e32.e_ident[EI_DATA] == MY_ELFDATA)
     283                 :         10 :       notes = data;
     284                 :            :     else
     285                 :            :       {
     286                 :          6 :         notes = malloc (filesz);
     287         [ +  - ]:          6 :         if (unlikely (notes == NULL))
     288                 :            :           return;
     289                 :          6 :         xlatefrom.d_type = xlateto.d_type = ELF_T_NHDR;
     290                 :          6 :         xlatefrom.d_buf = (void *) data;
     291                 :          6 :         xlatefrom.d_size = filesz;
     292                 :          6 :         xlateto.d_buf = notes;
     293                 :          6 :         xlateto.d_size = filesz;
     294         [ +  - ]:          6 :         if (elf32_xlatetom (&xlateto, &xlatefrom,
     295                 :            :                             ehdr.e32.e_ident[EI_DATA]) == NULL)
     296                 :            :           goto done;
     297                 :            :       }
     298                 :            : 
     299                 :         16 :     const GElf_Nhdr *nh = notes;
     300         [ +  - ]:         22 :     while ((const void *) nh < (const void *) notes + filesz)
     301                 :            :      {
     302                 :         22 :         const void *note_name = nh + 1;
     303                 :         22 :         const void *note_desc = note_name + NOTE_ALIGN (nh->n_namesz);
     304         [ +  - ]:         22 :         if (unlikely ((size_t) ((const void *) notes + filesz
     305                 :            :                                 - note_desc) < nh->n_descsz))
     306                 :            :           break;
     307                 :            : 
     308         [ +  + ]:         22 :         if (nh->n_type == NT_GNU_BUILD_ID
     309         [ +  - ]:         16 :             && nh->n_descsz > 0
     310         [ +  - ]:         16 :             && nh->n_namesz == sizeof "GNU"
     311         [ +  - ]:         16 :             && !memcmp (note_name, "GNU", sizeof "GNU"))
     312                 :            :           {
     313                 :         16 :             build_id_vaddr = note_desc - (const void *) notes + vaddr;
     314                 :         16 :             build_id_len = nh->n_descsz;
     315                 :         16 :             build_id = malloc (nh->n_descsz);
     316         [ +  - ]:         16 :             if (likely (build_id != NULL))
     317                 :         16 :               memcpy (build_id, note_desc, build_id_len);
     318                 :            :             break;
     319                 :            :           }
     320                 :            : 
     321                 :          6 :         nh = note_desc + NOTE_ALIGN (nh->n_descsz);
     322                 :            :       }
     323                 :            : 
     324                 :            :   done:
     325         [ +  + ]:         16 :     if (notes != data)
     326                 :          6 :       free (notes);
     327                 :         16 :     finish_portion (&data, &data_size);
     328                 :            :   }
     329                 :            : 
     330                 :            :   /* Consider each of the program headers we've read from the image.  */
     331                 :        114 :   inline void consider_phdr (GElf_Word type,
     332                 :            :                              GElf_Addr vaddr, GElf_Xword memsz,
     333                 :            :                              GElf_Off offset, GElf_Xword filesz,
     334                 :            :                              GElf_Xword align)
     335                 :            :   {
     336   [ +  +  +  + ]:        114 :     switch (type)
     337                 :            :       {
     338                 :            :       case PT_DYNAMIC:
     339                 :         15 :         dyn_vaddr = vaddr;
     340                 :         15 :         dyn_filesz = filesz;
     341                 :         15 :         break;
     342                 :            : 
     343                 :            :       case PT_NOTE:
     344                 :            :         /* We calculate from the p_offset of the note segment,
     345                 :            :            because we don't yet know the bias for its p_vaddr.  */
     346                 :         16 :         consider_notes (start + offset, filesz);
     347                 :         16 :         break;
     348                 :            : 
     349                 :            :       case PT_LOAD:
     350 [ -  + ][ #  # ]:         28 :         align = dwfl->segment_align > 1 ? dwfl->segment_align : align ?: 1;
     351                 :            : 
     352                 :         28 :         GElf_Addr vaddr_end = (vaddr + memsz + align - 1) & -align;
     353         [ +  + ]:         28 :         GElf_Addr filesz_vaddr = filesz < memsz ? vaddr + filesz : vaddr_end;
     354                 :         28 :         GElf_Off filesz_offset = filesz_vaddr - vaddr + offset;
     355                 :            : 
     356         [ +  + ]:         28 :         if (file_trimmed_end < offset + filesz)
     357                 :            :           {
     358                 :         26 :             file_trimmed_end = offset + filesz;
     359                 :            : 
     360                 :            :             /* Trim the last segment so we don't bother with zeros
     361                 :            :                in the last page that are off the end of the file.
     362                 :            :                However, if the extra bit in that page includes the
     363                 :            :                section headers, keep them.  */
     364 [ +  + ][ +  - ]:         26 :             if (shdrs_end <= filesz_offset && shdrs_end > file_trimmed_end)
     365                 :            :               {
     366                 :          6 :                 filesz += shdrs_end - file_trimmed_end;
     367                 :          6 :                 file_trimmed_end = shdrs_end;
     368                 :            :               }
     369                 :            :           }
     370                 :            : 
     371                 :         28 :         total_filesz += filesz;
     372                 :            : 
     373         [ +  + ]:         28 :         if (file_end < filesz_offset)
     374                 :            :           {
     375                 :         24 :             file_end = filesz_offset;
     376         [ +  + ]:         24 :             if (filesz_vaddr - start == filesz_offset)
     377                 :          9 :               contiguous = file_end;
     378                 :            :           }
     379                 :            : 
     380 [ +  + ][ +  - ]:         28 :         if (!found_bias && (offset & -align) == 0
     381         [ +  - ]:         16 :             && likely (filesz_offset >= phoff + phnum * phentsize))
     382                 :            :           {
     383                 :         16 :             bias = start - vaddr;
     384                 :         16 :             found_bias = true;
     385                 :            :           }
     386                 :            : 
     387         [ +  + ]:         28 :         if ((vaddr & -align) < module_start)
     388                 :            :           {
     389                 :         16 :             module_start = vaddr & -align;
     390                 :         16 :             module_address_sync = vaddr + memsz;
     391                 :            :           }
     392                 :            : 
     393         [ +  - ]:         28 :         if (module_end < vaddr_end)
     394                 :         28 :           module_end = vaddr_end;
     395                 :            :         break;
     396                 :            :       }
     397                 :        114 :   }
     398         [ +  + ]:         16 :   if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
     399                 :            :     {
     400         [ +  - ]:         12 :       if (elf32_xlatetom (&xlateto, &xlatefrom,
     401                 :         12 :                           ehdr.e32.e_ident[EI_DATA]) == NULL)
     402                 :          0 :         found_bias = false;     /* Trigger error check.  */
     403                 :            :       else
     404         [ +  + ]:        106 :         for (uint_fast16_t i = 0; i < phnum; ++i)
     405                 :         94 :           consider_phdr (phdrs.p32[i].p_type,
     406                 :        188 :                          phdrs.p32[i].p_vaddr, phdrs.p32[i].p_memsz,
     407                 :        188 :                          phdrs.p32[i].p_offset, phdrs.p32[i].p_filesz,
     408                 :         94 :                          phdrs.p32[i].p_align);
     409                 :            :     }
     410                 :            :   else
     411                 :            :     {
     412         [ +  - ]:          4 :       if (elf64_xlatetom (&xlateto, &xlatefrom,
     413                 :          4 :                           ehdr.e32.e_ident[EI_DATA]) == NULL)
     414                 :          0 :         found_bias = false;     /* Trigger error check.  */
     415                 :            :       else
     416         [ +  + ]:         24 :         for (uint_fast16_t i = 0; i < phnum; ++i)
     417                 :         20 :           consider_phdr (phdrs.p64[i].p_type,
     418                 :            :                          phdrs.p64[i].p_vaddr, phdrs.p64[i].p_memsz,
     419                 :            :                          phdrs.p64[i].p_offset, phdrs.p64[i].p_filesz,
     420                 :            :                          phdrs.p64[i].p_align);
     421                 :            :     }
     422                 :            : 
     423                 :         16 :   finish_portion (&ph_buffer, &ph_buffer_size);
     424                 :            : 
     425                 :            :   /* We must have seen the segment covering offset 0, or else the ELF
     426                 :            :      header we read at START was not produced by these program headers.  */
     427         [ -  + ]:         16 :   if (unlikely (!found_bias))
     428                 :          0 :     return finish ();
     429                 :            : 
     430                 :            :   /* Now we know enough to report a module for sure: its bounds.  */
     431                 :         16 :   module_start += bias;
     432                 :         16 :   module_end += bias;
     433                 :            : 
     434                 :         16 :   dyn_vaddr += bias;
     435                 :            : 
     436                 :            :   /* Our return value now says to skip the segments contained
     437                 :            :      within the module.  */
     438                 :         16 :   ndx = addr_segndx (dwfl, segment, module_end, true);
     439                 :            : 
     440                 :            :   /* Examine its .dynamic section to get more interesting details.
     441                 :            :      If it has DT_SONAME, we'll use that as the module name.
     442                 :            :      If it has a DT_DEBUG, then it's actually a PIE rather than a DSO.
     443                 :            :      We need its DT_STRTAB and DT_STRSZ to decipher DT_SONAME,
     444                 :            :      and they also tell us the essential portion of the file
     445                 :            :      for fetching symbols.  */
     446                 :         16 :   GElf_Addr soname_stroff = 0;
     447                 :         16 :   GElf_Addr dynstr_vaddr = 0;
     448                 :         16 :   GElf_Xword dynstrsz = 0;
     449                 :         16 :   bool execlike = false;
     450                 :        216 :   inline bool consider_dyn (GElf_Sxword tag, GElf_Xword val)
     451                 :            :   {
     452   [ +  +  +  +  :        216 :     switch (tag)
                      + ]
     453                 :            :       {
     454                 :            :       default:
     455                 :            :         return false;
     456                 :            : 
     457                 :            :       case DT_DEBUG:
     458                 :          3 :         execlike = true;
     459                 :          3 :         break;
     460                 :            : 
     461                 :            :       case DT_SONAME:
     462                 :         11 :         soname_stroff = val;
     463                 :         11 :         break;
     464                 :            : 
     465                 :            :       case DT_STRTAB:
     466                 :         14 :         dynstr_vaddr = val;
     467                 :         14 :         break;
     468                 :            : 
     469                 :            :       case DT_STRSZ:
     470                 :         14 :         dynstrsz = val;
     471                 :         14 :         break;
     472                 :            :       }
     473                 :            : 
     474 [ +  + ][ +  + ]:        216 :     return soname_stroff != 0 && dynstr_vaddr != 0 && dynstrsz != 0;
                 [ +  + ]
     475                 :            :   }
     476                 :            : 
     477                 :         32 :   const size_t dyn_entsize = (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32
     478         [ +  + ]:         16 :                               ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
     479                 :         16 :   void *dyn_data = NULL;
     480                 :         16 :   size_t dyn_data_size = 0;
     481 [ +  + ][ +  - ]:         16 :   if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0
     482         [ +  - ]:         15 :       && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz))
     483                 :            :     {
     484                 :         30 :       union
     485                 :            :       {
     486                 :         15 :         Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
     487                 :         15 :         Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
     488                 :         15 :       } dyn;
     489                 :            : 
     490                 :         15 :       xlatefrom.d_type = xlateto.d_type = ELF_T_DYN;
     491                 :         15 :       xlatefrom.d_buf = (void *) dyn_data;
     492                 :         15 :       xlatefrom.d_size = dyn_filesz;
     493                 :         15 :       xlateto.d_buf = &dyn;
     494                 :         15 :       xlateto.d_size = sizeof dyn;
     495                 :            : 
     496         [ +  + ]:         15 :       if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
     497                 :            :         {
     498         [ +  - ]:         12 :           if (elf32_xlatetom (&xlateto, &xlatefrom,
     499                 :         12 :                               ehdr.e32.e_ident[EI_DATA]) != NULL)
     500         [ +  + ]:        163 :             for (size_t i = 0; i < dyn_filesz / sizeof dyn.d32[0]; ++i)
     501         [ +  + ]:        161 :               if (consider_dyn (dyn.d32[i].d_tag, dyn.d32[i].d_un.d_val))
     502                 :            :                 break;
     503                 :            :         }
     504                 :            :       else
     505                 :            :         {
     506         [ +  - ]:          3 :           if (elf64_xlatetom (&xlateto, &xlatefrom,
     507                 :          3 :                               ehdr.e32.e_ident[EI_DATA]) != NULL)
     508         [ +  + ]:         70 :             for (size_t i = 0; i < dyn_filesz / sizeof dyn.d64[0]; ++i)
     509         [ +  + ]:         55 :               if (consider_dyn (dyn.d64[i].d_tag, dyn.d64[i].d_un.d_val))
     510                 :            :                 break;
     511                 :            :         }
     512                 :            :     }
     513                 :         16 :   finish_portion (&dyn_data, &dyn_data_size);
     514                 :            : 
     515                 :            :   /* We'll use the name passed in or a stupid default if not DT_SONAME.  */
     516         [ +  - ]:         16 :   if (name == NULL)
     517 [ +  + ][ +  - ]:         16 :     name = ehdr.e32.e_type == ET_EXEC ? "[exe]" : execlike ? "[pie]" : "[dso]";
     518                 :            : 
     519                 :         16 :   void *soname = NULL;
     520                 :         16 :   size_t soname_size = 0;
     521 [ +  + ][ +  - ]:         16 :   if (dynstrsz != 0 && dynstr_vaddr != 0)
     522                 :            :     {
     523                 :            :       /* We know the bounds of the .dynstr section.
     524                 :            : 
     525                 :            :          The DYNSTR_VADDR pointer comes from the .dynamic section
     526                 :            :          (DT_STRTAB, detected above).  Ordinarily the dynamic linker
     527                 :            :          will have adjusted this pointer in place so it's now an
     528                 :            :          absolute address.  But sometimes .dynamic is read-only (in
     529                 :            :          vDSOs and odd architectures), and sometimes the adjustment
     530                 :            :          just hasn't happened yet in the memory image we looked at.
     531                 :            :          So treat DYNSTR_VADDR as an absolute address if it falls
     532                 :            :          within the module bounds, or try applying the phdr bias
     533                 :            :          when that adjusts it to fall within the module bounds.  */
     534                 :            : 
     535 [ +  - ][ +  + ]:         14 :       if ((dynstr_vaddr < module_start || dynstr_vaddr >= module_end)
     536         [ +  - ]:          2 :           && dynstr_vaddr + bias >= module_start
     537         [ +  - ]:          2 :           && dynstr_vaddr + bias < module_end)
     538                 :          2 :         dynstr_vaddr += bias;
     539                 :            : 
     540         [ -  + ]:         14 :       if (unlikely (dynstr_vaddr + dynstrsz > module_end))
     541                 :          0 :         dynstrsz = 0;
     542                 :            : 
     543                 :            :       /* Try to get the DT_SONAME string.  */
     544 [ +  + ][ +  - ]:         14 :       if (soname_stroff != 0 && soname_stroff + 1 < dynstrsz
     545         [ +  + ]:         11 :           && ! read_portion (&soname, &soname_size,
     546                 :            :                              dynstr_vaddr + soname_stroff, 0))
     547                 :          7 :         name = soname;
     548                 :            :     }
     549                 :            : 
     550                 :            :   /* Now that we have chosen the module's name and bounds, report it.
     551                 :            :      If we found a build ID, report that too.  */
     552                 :            : 
     553                 :         16 :   Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, name,
     554                 :            :                                                  module_start, module_end);
     555 [ +  - ][ +  - ]:         16 :   if (likely (mod != NULL) && build_id != NULL
     556         [ -  + ]:         16 :       && unlikely (INTUSE(dwfl_module_report_build_id) (mod,
     557                 :            :                                                         build_id,
     558                 :            :                                                         build_id_len,
     559                 :            :                                                         build_id_vaddr)))
     560                 :            :     {
     561                 :          0 :       mod->gc = true;
     562                 :          0 :       mod = NULL;
     563                 :            :     }
     564                 :            : 
     565                 :            :   /* At this point we do not need BUILD_ID or NAME any more.
     566                 :            :      They have been copied.  */
     567                 :         16 :   free (build_id);
     568                 :         16 :   finish_portion (&soname, &soname_size);
     569                 :            : 
     570         [ -  + ]:         16 :   if (unlikely (mod == NULL))
     571                 :            :     {
     572                 :          0 :       ndx = -1;
     573                 :          0 :       return finish ();
     574                 :            :     }
     575                 :            : 
     576                 :            :   /* We have reported the module.  Now let the caller decide whether we
     577                 :            :      should read the whole thing in right now.  */
     578                 :            : 
     579                 :         16 :   const GElf_Off cost = (contiguous < file_trimmed_end ? total_filesz
     580         [ +  + ]:         16 :                          : buffer_available >= contiguous ? 0
     581         [ -  + ]:          5 :                          : contiguous - buffer_available);
     582         [ +  - ]:         14 :   const GElf_Off worthwhile = ((dynstr_vaddr == 0 || dynstrsz == 0) ? 0
     583         [ +  + ]:         30 :                                : dynstr_vaddr + dynstrsz - start);
     584                 :         16 :   const GElf_Off whole = MAX (file_trimmed_end, shdrs_end);
     585                 :            : 
     586                 :         16 :   Elf *elf = NULL;
     587         [ +  + ]:         16 :   if ((*read_eagerly) (MODCB_ARGS (mod), &buffer, &buffer_available,
     588                 :            :                        cost, worthwhile, whole, contiguous,
     589                 :            :                        read_eagerly_arg, &elf)
     590         [ -  + ]:          7 :       && elf == NULL)
     591                 :            :     {
     592                 :            :       /* The caller wants to read the whole file in right now, but hasn't
     593                 :            :          done it for us.  Fill in a local image of the virtual file.  */
     594                 :            : 
     595                 :          0 :       void *contents = calloc (1, file_trimmed_end);
     596         [ #  # ]:          0 :       if (unlikely (contents == NULL))
     597                 :          0 :         return finish ();
     598                 :            : 
     599                 :          0 :       inline void final_read (size_t offset, GElf_Addr vaddr, size_t size)
     600                 :            :       {
     601                 :          0 :         void *into = contents + offset;
     602                 :          0 :         size_t read_size = size;
     603                 :          0 :         (void) segment_read (addr_segndx (dwfl, segment, vaddr, false),
     604                 :            :                              &into, &read_size, vaddr, size);
     605                 :          0 :       }
     606                 :            : 
     607         [ #  # ]:          0 :       if (contiguous < file_trimmed_end)
     608                 :            :         {
     609                 :            :           /* We can't use the memory image verbatim as the file image.
     610                 :            :              So we'll be reading into a local image of the virtual file.  */
     611                 :            : 
     612                 :          0 :           inline void read_phdr (GElf_Word type, GElf_Addr vaddr,
     613                 :            :                                  GElf_Off offset, GElf_Xword filesz)
     614                 :            :           {
     615         [ #  # ]:          0 :             if (type == PT_LOAD)
     616                 :          0 :               final_read (offset, vaddr + bias, filesz);
     617                 :          0 :           }
     618                 :            : 
     619         [ #  # ]:          0 :           if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
     620         [ #  # ]:          0 :             for (uint_fast16_t i = 0; i < phnum; ++i)
     621                 :          0 :               read_phdr (phdrs.p32[i].p_type, phdrs.p32[i].p_vaddr,
     622                 :          0 :                          phdrs.p32[i].p_offset, phdrs.p32[i].p_filesz);
     623                 :            :           else
     624         [ #  # ]:          0 :             for (uint_fast16_t i = 0; i < phnum; ++i)
     625                 :          0 :               read_phdr (phdrs.p64[i].p_type, phdrs.p64[i].p_vaddr,
     626                 :            :                          phdrs.p64[i].p_offset, phdrs.p64[i].p_filesz);
     627                 :            :         }
     628                 :            :       else
     629                 :            :         {
     630                 :            :           /* The whole file sits contiguous in memory,
     631                 :            :              but the caller didn't want to just do it.  */
     632                 :            : 
     633                 :          0 :           const size_t have = MIN (buffer_available, file_trimmed_end);
     634                 :          0 :           memcpy (contents, buffer, have);
     635                 :            : 
     636         [ #  # ]:          0 :           if (have < file_trimmed_end)
     637                 :          0 :             final_read (have, start + have, file_trimmed_end - have);
     638                 :            :         }
     639                 :            : 
     640                 :          0 :       elf = elf_memory (contents, file_trimmed_end);
     641         [ #  # ]:          0 :       if (unlikely (elf == NULL))
     642                 :          0 :         free (contents);
     643                 :            :       else
     644                 :          0 :         elf->flags |= ELF_F_MALLOCED;
     645                 :            :     }
     646                 :            : 
     647         [ +  + ]:         16 :   if (elf != NULL)
     648                 :            :     {
     649                 :            :       /* Install the file in the module.  */
     650                 :          7 :       mod->main.elf = elf;
     651                 :          7 :       mod->main.vaddr = module_start - bias;
     652                 :          7 :       mod->main.address_sync = module_address_sync;
     653                 :          7 :       mod->main_bias = bias;
     654                 :            :     }
     655                 :            : 
     656                 :         36 :   return finish ();
     657                 :            : }

Generated by: LCOV version 1.9