LCOV - code coverage report
Current view: top level - elfutils/libelf - elf32_updatefile.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 226 261 86.6 %
Date: 2012-10-31 Functions: 8 8 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 137 210 65.2 %

           Branch data     Line data    Source code
       1                 :            : /* Write changed data structures.
       2                 :            :    Copyright (C) 2000-2010 Red Hat, Inc.
       3                 :            :    This file is part of elfutils.
       4                 :            :    Written by Ulrich Drepper <drepper@redhat.com>, 2000.
       5                 :            : 
       6                 :            :    This file is free software; you can redistribute it and/or modify
       7                 :            :    it under the terms of either
       8                 :            : 
       9                 :            :      * the GNU Lesser General Public License as published by the Free
      10                 :            :        Software Foundation; either version 3 of the License, or (at
      11                 :            :        your option) any later version
      12                 :            : 
      13                 :            :    or
      14                 :            : 
      15                 :            :      * the GNU General Public License as published by the Free
      16                 :            :        Software Foundation; either version 2 of the License, or (at
      17                 :            :        your option) any later version
      18                 :            : 
      19                 :            :    or both in parallel, as here.
      20                 :            : 
      21                 :            :    elfutils is distributed in the hope that it will be useful, but
      22                 :            :    WITHOUT ANY WARRANTY; without even the implied warranty of
      23                 :            :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      24                 :            :    General Public License for more details.
      25                 :            : 
      26                 :            :    You should have received copies of the GNU General Public License and
      27                 :            :    the GNU Lesser General Public License along with this program.  If
      28                 :            :    not, see <http://www.gnu.org/licenses/>.  */
      29                 :            : 
      30                 :            : #ifdef HAVE_CONFIG_H
      31                 :            : # include <config.h>
      32                 :            : #endif
      33                 :            : 
      34                 :            : #include <assert.h>
      35                 :            : #include <errno.h>
      36                 :            : #include <libelf.h>
      37                 :            : #include <stdbool.h>
      38                 :            : #include <stdlib.h>
      39                 :            : #include <string.h>
      40                 :            : #include <unistd.h>
      41                 :            : #include <sys/mman.h>
      42                 :            : #include <sys/param.h>
      43                 :            : 
      44                 :            : #include <system.h>
      45                 :            : #include "libelfP.h"
      46                 :            : 
      47                 :            : 
      48                 :            : #ifndef LIBELFBITS
      49                 :            : # define LIBELFBITS 32
      50                 :            : #endif
      51                 :            : 
      52                 :            : 
      53                 :            : static int
      54                 :    1583866 : compare_sections (const void *a, const void *b)
      55                 :            : {
      56                 :    1583866 :   const Elf_Scn **scna = (const Elf_Scn **) a;
      57                 :    1583866 :   const Elf_Scn **scnb = (const Elf_Scn **) b;
      58                 :            : 
      59         [ +  + ]:    1583866 :   if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
      60                 :    1583866 :       < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
      61                 :            :     return -1;
      62                 :            : 
      63         [ +  + ]:        915 :   if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
      64                 :            :       > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
      65                 :            :     return 1;
      66                 :            : 
      67         [ +  + ]:        842 :   if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
      68                 :        842 :       < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
      69                 :            :     return -1;
      70                 :            : 
      71         [ +  + ]:        446 :   if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
      72                 :            :       > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
      73                 :            :     return 1;
      74                 :            : 
      75         [ -  + ]:         51 :   if ((*scna)->index < (*scnb)->index)
      76                 :            :     return -1;
      77                 :            : 
      78         [ #  # ]:          0 :   if ((*scna)->index > (*scnb)->index)
      79                 :            :     return 1;
      80                 :            : 
      81                 :    1583866 :   return 0;
      82                 :            : }
      83                 :            : 
      84                 :            : 
      85                 :            : /* Insert the sections in the list into the provided array and sort
      86                 :            :    them according to their start offsets.  For sections with equal
      87                 :            :    start offsets, the size is used; for sections with equal start
      88                 :            :    offsets and sizes, the section index is used.  Sorting by size
      89                 :            :    ensures that zero-length sections are processed first, which
      90                 :            :    is what we want since they do not advance our file writing position.  */
      91                 :            : static void
      92                 :         64 : sort_sections (Elf_Scn **scns, Elf_ScnList *list)
      93                 :            : {
      94                 :         64 :   Elf_Scn **scnp = scns;
      95                 :            :   do
      96         [ +  + ]:     199603 :     for (size_t cnt = 0; cnt < list->cnt; ++cnt)
      97                 :     199434 :       *scnp++ = &list->data[cnt];
      98         [ +  + ]:        169 :   while ((list = list->next) != NULL);
      99                 :            : 
     100                 :         64 :   qsort (scns, scnp - scns, sizeof (*scns), compare_sections);
     101                 :         64 : }
     102                 :            : 
     103                 :            : 
     104                 :            : int
     105                 :            : internal_function
     106                 :         50 : __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
     107                 :            : {
     108                 :         50 :   bool previous_scn_changed = false;
     109                 :            : 
     110                 :            :   /* We need the ELF header several times.  */
     111                 :         50 :   ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
     112                 :            : 
     113                 :            :   /* Write out the ELF header.  */
     114         [ +  - ]:         50 :   if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
     115                 :            :     {
     116                 :            :       /* If the type sizes should be different at some time we have to
     117                 :            :          rewrite this code.  */
     118         [ -  + ]:         50 :       assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
     119                 :            :               == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
     120                 :            : 
     121         [ +  + ]:         50 :       if (unlikely (change_bo))
     122                 :            :         {
     123                 :            :           /* Today there is only one version of the ELF header.  */
     124                 :            : #if EV_NUM != 2
     125                 :            :           xfct_t fctp;
     126                 :            :           fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
     127                 :            : #else
     128                 :            : # undef fctp
     129                 :            : # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
     130                 :            : #endif
     131                 :            : 
     132                 :            :           /* Do the real work.  */
     133                 :         13 :           (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr,
     134                 :            :                    sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
     135                 :            :         }
     136                 :            :       else
     137                 :         37 :         memcpy (elf->map_address + elf->start_offset, ehdr,
     138                 :            :                 sizeof (ElfW2(LIBELFBITS,Ehdr)));
     139                 :            : 
     140                 :         50 :       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
     141                 :            : 
     142                 :            :       /* We start writing sections after the ELF header only if there is
     143                 :            :          no program header.  */
     144                 :         50 :       previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
     145                 :            :     }
     146                 :            : 
     147                 :            :   size_t phnum;
     148         [ +  - ]:         50 :   if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
     149                 :            :     return -1;
     150                 :            : 
     151                 :            :   /* Write out the program header table.  */
     152         [ +  + ]:         50 :   if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
     153         [ +  - ]:         12 :       && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
     154                 :         12 :           & ELF_F_DIRTY))
     155                 :            :     {
     156                 :            :       /* If the type sizes should be different at some time we have to
     157                 :            :          rewrite this code.  */
     158         [ -  + ]:         12 :       assert (sizeof (ElfW2(LIBELFBITS,Phdr))
     159                 :            :               == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
     160                 :            : 
     161                 :            :       /* Maybe the user wants a gap between the ELF header and the program
     162                 :            :          header.  */
     163         [ -  + ]:         12 :       if (ehdr->e_phoff > ehdr->e_ehsize)
     164                 :          0 :         memset (elf->map_address + elf->start_offset + ehdr->e_ehsize,
     165                 :          0 :                 __libelf_fill_byte, ehdr->e_phoff - ehdr->e_ehsize);
     166                 :            : 
     167         [ +  + ]:         12 :       if (unlikely (change_bo))
     168                 :            :         {
     169                 :            :           /* Today there is only one version of the ELF header.  */
     170                 :            : #if EV_NUM != 2
     171                 :            :           xfct_t fctp;
     172                 :            :           fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
     173                 :            : #else
     174                 :            : # undef fctp
     175                 :            : # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
     176                 :            : #endif
     177                 :            : 
     178                 :            :           /* Do the real work.  */
     179                 :          2 :           (*fctp) (elf->map_address + elf->start_offset + ehdr->e_phoff,
     180                 :          2 :                    elf->state.ELFW(elf,LIBELFBITS).phdr,
     181                 :            :                    sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
     182                 :            :         }
     183                 :            :       else
     184                 :         10 :         memcpy (elf->map_address + elf->start_offset + ehdr->e_phoff,
     185                 :         10 :                 elf->state.ELFW(elf,LIBELFBITS).phdr,
     186                 :            :                 sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
     187                 :            : 
     188                 :         12 :       elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
     189                 :            : 
     190                 :            :       /* We modified the program header.  Maybe this created a gap so
     191                 :            :          we have to write fill bytes, if necessary.  */
     192                 :         12 :       previous_scn_changed = true;
     193                 :            :     }
     194                 :            : 
     195                 :            :   /* From now on we have to keep track of the last position to eventually
     196                 :            :      fill the gaps with the prescribed fill byte.  */
     197                 :        100 :   char *last_position = ((char *) elf->map_address + elf->start_offset
     198                 :         50 :                          + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
     199                 :            :                                 ehdr->e_phoff)
     200                 :         50 :                          + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
     201                 :            : 
     202                 :            :   /* Write all the sections.  Well, only those which are modified.  */
     203         [ +  - ]:         50 :   if (shnum > 0)
     204                 :            :     {
     205                 :         50 :       Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
     206                 :         50 :       Elf_Scn **scns = (Elf_Scn **) alloca (shnum * sizeof (Elf_Scn *));
     207                 :         50 :       char *const shdr_start = ((char *) elf->map_address + elf->start_offset
     208                 :         50 :                                 + ehdr->e_shoff);
     209                 :         50 :       char *const shdr_end = shdr_start + ehdr->e_shnum * ehdr->e_shentsize;
     210                 :            : 
     211                 :            : #if EV_NUM != 2
     212                 :            :       xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
     213                 :            : #else
     214                 :            : # undef shdr_fctp
     215                 :            : # define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
     216                 :            : #endif
     217                 :            : #define shdr_dest ((ElfW2(LIBELFBITS,Shdr) *) shdr_start)
     218                 :            : 
     219                 :            :       /* Get all sections into the array and sort them.  */
     220                 :         50 :       sort_sections (scns, list);
     221                 :            : 
     222                 :            :       /* We possibly have to copy the section header data because moving
     223                 :            :          the sections might overwrite the data.  */
     224         [ +  + ]:     199114 :       for (size_t cnt = 0; cnt < shnum; ++cnt)
     225                 :            :         {
     226                 :     199064 :           Elf_Scn *scn = scns[cnt];
     227                 :            : 
     228         [ +  + ]:     199064 :           if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
     229         [ +  + ]:     199057 :               && (scn->shdr_flags & ELF_F_MALLOCED) == 0
     230         [ +  - ]:          7 :               && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
     231                 :            :             {
     232         [ -  + ]:          7 :               assert ((char *) elf->map_address + elf->start_offset
     233                 :            :                       < (char *) scn->shdr.ELFW(e,LIBELFBITS));
     234         [ -  + ]:          7 :               assert ((char *) scn->shdr.ELFW(e,LIBELFBITS)
     235                 :            :                       < ((char *) elf->map_address + elf->start_offset
     236                 :            :                          + elf->maximum_size));
     237                 :            : 
     238                 :          7 :               void *p = alloca (sizeof (ElfW2(LIBELFBITS,Shdr)));
     239                 :            :               scn->shdr.ELFW(e,LIBELFBITS)
     240                 :          7 :                 = memcpy (p, scn->shdr.ELFW(e,LIBELFBITS),
     241                 :            :                           sizeof (ElfW2(LIBELFBITS,Shdr)));
     242                 :            :             }
     243                 :            : 
     244                 :            :           /* If the file is mmaped and the original position of the
     245                 :            :              section in the file is lower than the new position we
     246                 :            :              need to save the section content since otherwise it is
     247                 :            :              overwritten before it can be copied.  If there are
     248                 :            :              multiple data segments in the list only the first can be
     249                 :            :              from the file.  */
     250         [ +  + ]:     199064 :           if (((char *) elf->map_address + elf->start_offset
     251                 :     199064 :                <= (char  *) scn->data_list.data.d.d_buf)
     252         [ +  + ]:          9 :               && ((char *) scn->data_list.data.d.d_buf
     253                 :            :                   < ((char *) elf->map_address + elf->start_offset
     254                 :          9 :                      + elf->maximum_size))
     255         [ -  + ]:          2 :               && (((char *) elf->map_address + elf->start_offset
     256                 :          2 :                    + scn->shdr.ELFW(e,LIBELFBITS)->sh_offset)
     257                 :            :                   > (char *) scn->data_list.data.d.d_buf))
     258                 :            :             {
     259                 :          0 :               void *p = malloc (scn->data_list.data.d.d_size);
     260         [ #  # ]:          0 :               if (p == NULL)
     261                 :            :                 {
     262                 :          0 :                   __libelf_seterrno (ELF_E_NOMEM);
     263                 :            :                   return -1;
     264                 :            :                 }
     265                 :          0 :               scn->data_list.data.d.d_buf = scn->data_base
     266                 :          0 :                 = memcpy (p, scn->data_list.data.d.d_buf,
     267                 :            :                           scn->data_list.data.d.d_size);
     268                 :            :             }
     269                 :            :         }
     270                 :            : 
     271                 :            :       /* Iterate over all the section in the order in which they
     272                 :            :          appear in the output file.  */
     273         [ +  + ]:     199114 :       for (size_t cnt = 0; cnt < shnum; ++cnt)
     274                 :            :         {
     275                 :     199064 :           Elf_Scn *scn = scns[cnt];
     276         [ +  + ]:     199064 :           if (scn->index == 0)
     277                 :            :             {
     278                 :            :               /* The dummy section header entry.  It should not be
     279                 :            :                  possible to mark this "section" as dirty.  */
     280         [ -  + ]:         50 :               assert ((scn->flags & ELF_F_DIRTY) == 0);
     281                 :         50 :               continue;
     282                 :            :             }
     283                 :            : 
     284                 :     199014 :           ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
     285         [ +  + ]:     199014 :           if (shdr->sh_type == SHT_NOBITS)
     286                 :            :             goto next;
     287                 :            : 
     288                 :     397426 :           char *scn_start = ((char *) elf->map_address
     289                 :     198713 :                              + elf->start_offset + shdr->sh_offset);
     290                 :     198713 :           Elf_Data_List *dl = &scn->data_list;
     291                 :     198713 :           bool scn_changed = false;
     292                 :            : 
     293                 :        194 :           void fill_mmap (size_t offset)
     294                 :            :           {
     295                 :        194 :             size_t written = 0;
     296                 :            : 
     297         [ +  - ]:        194 :             if (last_position < shdr_start)
     298                 :            :               {
     299                 :        194 :                 written = MIN (scn_start + offset - last_position,
     300                 :            :                                shdr_start - last_position);
     301                 :            : 
     302                 :        194 :                 memset (last_position, __libelf_fill_byte, written);
     303                 :            :               }
     304                 :            : 
     305         [ -  + ]:        194 :             if (last_position + written != scn_start + offset
     306         [ #  # ]:          0 :                 && shdr_end < scn_start + offset)
     307                 :            :               {
     308                 :          0 :                 char *fill_start = MAX (shdr_end, scn_start);
     309                 :          0 :                 memset (fill_start, __libelf_fill_byte,
     310                 :          0 :                         scn_start + offset - fill_start);
     311                 :            :               }
     312                 :        194 :           }
     313                 :            : 
     314         [ +  + ]:     198713 :           if (scn->data_list_rear != NULL)
     315                 :            :             do
     316                 :            :               {
     317         [ -  + ]:     198709 :                 assert (dl->data.d.d_off >= 0);
     318         [ -  + ]:     198709 :                 assert ((GElf_Off) dl->data.d.d_off <= shdr->sh_size);
     319         [ -  + ]:     198709 :                 assert (dl->data.d.d_size <= (shdr->sh_size
     320                 :            :                                               - (GElf_Off) dl->data.d.d_off));
     321                 :            : 
     322                 :            :                 /* If there is a gap, fill it.  */
     323         [ +  + ]:     198709 :                 if (scn_start + dl->data.d.d_off > last_position
     324         [ -  + ]:        194 :                     && (dl->data.d.d_off == 0
     325         [ #  # ]:          0 :                         || ((scn->flags | dl->flags | elf->flags)
     326                 :          0 :                             & ELF_F_DIRTY) != 0))
     327                 :            :                   {
     328                 :        194 :                     fill_mmap (dl->data.d.d_off);
     329                 :        194 :                     last_position = scn_start + dl->data.d.d_off;
     330                 :            :                   }
     331                 :            : 
     332         [ +  - ]:     198709 :                 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
     333                 :            :                   {
     334                 :            :                     /* Let it go backward if the sections use a bogus
     335                 :            :                        layout with overlaps.  We'll overwrite the stupid
     336                 :            :                        user's section data with the latest one, rather than
     337                 :            :                        crashing.  */
     338                 :            : 
     339                 :     198709 :                     last_position = scn_start + dl->data.d.d_off;
     340                 :            : 
     341         [ +  + ]:     198709 :                     if (unlikely (change_bo))
     342                 :            :                       {
     343                 :            : #if EV_NUM != 2
     344                 :            :                         xfct_t fctp;
     345                 :            :                         fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
     346                 :            : #else
     347                 :            : # undef fctp
     348                 :            : # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
     349                 :            : #endif
     350                 :            : 
     351                 :            :                         /* Do the real work.  */
     352                 :        200 :                         (*fctp) (last_position, dl->data.d.d_buf,
     353                 :            :                                  dl->data.d.d_size, 1);
     354                 :            : 
     355                 :        200 :                         last_position += dl->data.d.d_size;
     356                 :            :                       }
     357                 :            :                     else
     358                 :     198509 :                       last_position = mempcpy (last_position,
     359                 :            :                                                dl->data.d.d_buf,
     360                 :            :                                                dl->data.d.d_size);
     361                 :            : 
     362                 :            :                     scn_changed = true;
     363                 :            :                   }
     364                 :            :                 else
     365                 :          0 :                   last_position += dl->data.d.d_size;
     366                 :            : 
     367         [ -  + ]:     198709 :                 assert (scn_start + dl->data.d.d_off + dl->data.d.d_size
     368                 :            :                         == last_position);
     369                 :            : 
     370                 :     198709 :                 dl->flags &= ~ELF_F_DIRTY;
     371                 :            : 
     372                 :     198709 :                 dl = dl->next;
     373                 :            :               }
     374         [ +  + ]:     198709 :             while (dl != NULL);
     375                 :            :           else
     376                 :            :             {
     377                 :            :               /* If the previous section (or the ELF/program
     378                 :            :                  header) changed we might have to fill the gap.  */
     379 [ -  + ][ #  # ]:          6 :               if (scn_start > last_position && previous_scn_changed)
     380                 :          0 :                 fill_mmap (0);
     381                 :            : 
     382                 :            :               /* We have to trust the existing section header information.  */
     383                 :          6 :               last_position = scn_start + shdr->sh_size;
     384                 :            :             }
     385                 :            : 
     386                 :            : 
     387                 :     198713 :           previous_scn_changed = scn_changed;
     388                 :            :         next:
     389                 :     199014 :           scn->flags &= ~ELF_F_DIRTY;
     390                 :            :         }
     391                 :            : 
     392                 :            :       /* Fill the gap between last section and section header table if
     393                 :            :          necessary.  */
     394         [ +  - ]:         50 :       if ((elf->flags & ELF_F_DIRTY)
     395         [ +  + ]:         50 :           && last_position < ((char *) elf->map_address + elf->start_offset
     396                 :         50 :                               + ehdr->e_shoff))
     397                 :         50 :         memset (last_position, __libelf_fill_byte,
     398                 :            :                 (char *) elf->map_address + elf->start_offset + ehdr->e_shoff
     399                 :         47 :                 - last_position);
     400                 :            : 
     401                 :            :       /* Write the section header table entry if necessary.  */
     402         [ +  + ]:     199114 :       for (size_t cnt = 0; cnt < shnum; ++cnt)
     403                 :            :         {
     404                 :     199064 :           Elf_Scn *scn = scns[cnt];
     405                 :            : 
     406         [ +  - ]:     199064 :           if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY)
     407                 :            :             {
     408         [ +  + ]:     199064 :               if (unlikely (change_bo))
     409                 :        306 :                 (*shdr_fctp) (&shdr_dest[scn->index],
     410                 :        306 :                               scn->shdr.ELFW(e,LIBELFBITS),
     411                 :            :                               sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
     412                 :            :               else
     413                 :     198758 :                 memcpy (&shdr_dest[scn->index],
     414                 :     198758 :                         scn->shdr.ELFW(e,LIBELFBITS),
     415                 :            :                         sizeof (ElfW2(LIBELFBITS,Shdr)));
     416                 :            : 
     417                 :            :               /* If we previously made a copy of the section header
     418                 :            :                  entry we now have to adjust the pointer again so
     419                 :            :                  point to new place in the mapping.  */
     420         [ +  + ]:     199064 :               if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
     421         [ +  + ]:     199057 :                   && (scn->shdr_flags & ELF_F_MALLOCED) == 0)
     422                 :          7 :                 scn->shdr.ELFW(e,LIBELFBITS) = &shdr_dest[scn->index];
     423                 :            : 
     424                 :     199064 :               scn->shdr_flags &= ~ELF_F_DIRTY;
     425                 :            :             }
     426                 :            :         }
     427                 :            :     }
     428                 :            : 
     429                 :            :   /* That was the last part.  Clear the overall flag.  */
     430                 :         50 :   elf->flags &= ~ELF_F_DIRTY;
     431                 :            : 
     432                 :            :   /* Make sure the content hits the disk.  */
     433                 :        100 :   char *msync_start = ((char *) elf->map_address
     434                 :         50 :                        + (elf->start_offset & ~(sysconf (_SC_PAGESIZE) - 1)));
     435                 :        100 :   char *msync_end = ((char *) elf->map_address
     436                 :         50 :                      + elf->start_offset + ehdr->e_shoff
     437                 :         50 :                      + ehdr->e_shentsize * shnum);
     438                 :         50 :   (void) msync (msync_start, msync_end - msync_start, MS_SYNC);
     439                 :            : 
     440                 :            :   return 0;
     441                 :            : }
     442                 :            : 
     443                 :            : 
     444                 :            : /* Size of the buffer we use to generate the blocks of fill bytes.  */
     445                 :            : #define FILLBUFSIZE     4096
     446                 :            : 
     447                 :            : /* If we have to convert the section buffer contents we have to use
     448                 :            :    temporary buffer.  Only buffers up to MAX_TMPBUF bytes are allocated
     449                 :            :    on the stack.  */
     450                 :            : #define MAX_TMPBUF      32768
     451                 :            : 
     452                 :            : 
     453                 :            : /* Helper function to write out fill bytes.  */
     454                 :            : static int
     455                 :         68 : fill (int fd, off_t pos, size_t len, char *fillbuf, size_t *filledp)
     456                 :            : {
     457                 :         68 :   size_t filled = *filledp;
     458                 :         68 :   size_t fill_len = MIN (len, FILLBUFSIZE);
     459                 :            : 
     460 [ +  + ][ +  - ]:         68 :   if (unlikely (fill_len > filled) && filled < FILLBUFSIZE)
     461                 :            :     {
     462                 :            :       /* Initialize a few more bytes.  */
     463                 :         41 :       memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled);
     464                 :         68 :       *filledp = filled = fill_len;
     465                 :            :     }
     466                 :            : 
     467                 :            :   do
     468                 :            :     {
     469                 :            :       /* This many bytes we want to write in this round.  */
     470                 :         68 :       size_t n = MIN (filled, len);
     471                 :            : 
     472         [ -  + ]:         68 :       if (unlikely ((size_t) pwrite_retry (fd, fillbuf, n, pos) != n))
     473                 :            :         {
     474                 :          0 :           __libelf_seterrno (ELF_E_WRITE_ERROR);
     475                 :          0 :           return 1;
     476                 :            :         }
     477                 :            : 
     478                 :         68 :       pos += n;
     479                 :         68 :       len -= n;
     480                 :            :     }
     481         [ -  + ]:         68 :   while (len > 0);
     482                 :            : 
     483                 :            :   return 0;
     484                 :            : }
     485                 :            : 
     486                 :            : 
     487                 :            : int
     488                 :            : internal_function
     489                 :         16 : __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
     490                 :            : {
     491                 :            :   char fillbuf[FILLBUFSIZE];
     492                 :         16 :   size_t filled = 0;
     493                 :         16 :   bool previous_scn_changed = false;
     494                 :            : 
     495                 :            :   /* We need the ELF header several times.  */
     496                 :         16 :   ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
     497                 :            : 
     498                 :            :   /* Write out the ELF header.  */
     499         [ +  - ]:         16 :   if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
     500                 :            :     {
     501                 :            :       ElfW2(LIBELFBITS,Ehdr) tmp_ehdr;
     502                 :         16 :       ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr;
     503                 :            : 
     504                 :            :       /* If the type sizes should be different at some time we have to
     505                 :            :          rewrite this code.  */
     506         [ -  + ]:         16 :       assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
     507                 :            :               == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
     508                 :            : 
     509         [ +  + ]:         16 :       if (unlikely (change_bo))
     510                 :            :         {
     511                 :            :           /* Today there is only one version of the ELF header.  */
     512                 :            : #if EV_NUM != 2
     513                 :            :           xfct_t fctp;
     514                 :            :           fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
     515                 :            : #else
     516                 :            : # undef fctp
     517                 :            : # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
     518                 :            : #endif
     519                 :            : 
     520                 :            :           /* Write the converted ELF header in a temporary buffer.  */
     521                 :          3 :           (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
     522                 :            : 
     523                 :            :           /* This is the buffer we want to write.  */
     524                 :          3 :           out_ehdr = &tmp_ehdr;
     525                 :            :         }
     526                 :            : 
     527                 :            :       /* Write out the ELF header.  */
     528         [ -  + ]:         16 :       if (unlikely (pwrite_retry (elf->fildes, out_ehdr,
     529                 :            :                                   sizeof (ElfW2(LIBELFBITS,Ehdr)), 0)
     530                 :            :                     != sizeof (ElfW2(LIBELFBITS,Ehdr))))
     531                 :            :         {
     532                 :          0 :           __libelf_seterrno (ELF_E_WRITE_ERROR);
     533                 :            :           return 1;
     534                 :            :         }
     535                 :            : 
     536                 :         16 :       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
     537                 :            : 
     538                 :            :       /* We start writing sections after the ELF header only if there is
     539                 :            :          no program header.  */
     540                 :         16 :       previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
     541                 :            :     }
     542                 :            : 
     543                 :            :   /* If the type sizes should be different at some time we have to
     544                 :            :      rewrite this code.  */
     545         [ -  + ]:         16 :   assert (sizeof (ElfW2(LIBELFBITS,Phdr))
     546                 :            :           == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
     547                 :            : 
     548                 :            :   size_t phnum;
     549         [ +  - ]:         16 :   if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
     550                 :            :     return -1;
     551                 :            : 
     552                 :            :   /* Write out the program header table.  */
     553         [ +  + ]:         16 :   if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
     554         [ +  - ]:         13 :       && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
     555                 :         13 :           & ELF_F_DIRTY))
     556                 :            :     {
     557                 :         13 :       ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL;
     558                 :         13 :       ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
     559                 :            : 
     560                 :            :       /* Maybe the user wants a gap between the ELF header and the program
     561                 :            :          header.  */
     562         [ -  + ]:         13 :       if (ehdr->e_phoff > ehdr->e_ehsize
     563         [ #  # ]:          0 :           && unlikely (fill (elf->fildes, ehdr->e_ehsize,
     564                 :            :                              ehdr->e_phoff - ehdr->e_ehsize, fillbuf, &filled)
     565                 :            :                        != 0))
     566                 :            :         return 1;
     567                 :            : 
     568         [ +  + ]:         13 :       if (unlikely (change_bo))
     569                 :            :         {
     570                 :            :           /* Today there is only one version of the ELF header.  */
     571                 :            : #if EV_NUM != 2
     572                 :            :           xfct_t fctp;
     573                 :            :           fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
     574                 :            : #else
     575                 :            : # undef fctp
     576                 :            : # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
     577                 :            : #endif
     578                 :            : 
     579                 :            :           /* Allocate sufficient memory.  */
     580                 :          2 :           tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *)
     581                 :          2 :             malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
     582         [ -  + ]:          2 :           if (tmp_phdr == NULL)
     583                 :            :             {
     584                 :          0 :               __libelf_seterrno (ELF_E_NOMEM);
     585                 :            :               return 1;
     586                 :            :             }
     587                 :            : 
     588                 :            :           /* Write the converted ELF header in a temporary buffer.  */
     589                 :          2 :           (*fctp) (tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr,
     590                 :            :                    sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
     591                 :            : 
     592                 :            :           /* This is the buffer we want to write.  */
     593                 :          2 :           out_phdr = tmp_phdr;
     594                 :            :         }
     595                 :            : 
     596                 :            :       /* Write out the ELF header.  */
     597                 :         13 :       size_t phdr_size = sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum;
     598         [ -  + ]:         13 :       if (unlikely ((size_t) pwrite_retry (elf->fildes, out_phdr,
     599                 :            :                                            phdr_size, ehdr->e_phoff)
     600                 :            :                     != phdr_size))
     601                 :            :         {
     602                 :          0 :           __libelf_seterrno (ELF_E_WRITE_ERROR);
     603                 :            :           return 1;
     604                 :            :         }
     605                 :            : 
     606                 :            :       /* This is a no-op we we have not allocated any memory.  */
     607                 :         13 :       free (tmp_phdr);
     608                 :            : 
     609                 :         13 :       elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
     610                 :            : 
     611                 :            :       /* We modified the program header.  Maybe this created a gap so
     612                 :            :          we have to write fill bytes, if necessary.  */
     613                 :         13 :       previous_scn_changed = true;
     614                 :            :     }
     615                 :            : 
     616                 :            :   /* From now on we have to keep track of the last position to eventually
     617                 :            :      fill the gaps with the prescribed fill byte.  */
     618                 :            :   off_t last_offset;
     619         [ +  + ]:         16 :   if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
     620                 :          3 :     last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
     621                 :            :   else
     622                 :         13 :     last_offset = (ehdr->e_phoff + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
     623                 :            : 
     624                 :            :   /* Write all the sections.  Well, only those which are modified.  */
     625         [ +  + ]:         16 :   if (shnum > 0)
     626                 :            :     {
     627                 :         14 :       off_t shdr_offset = elf->start_offset + ehdr->e_shoff;
     628                 :            : #if EV_NUM != 2
     629                 :            :       xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
     630                 :            : #else
     631                 :            : # undef shdr_fctp
     632                 :            : # define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
     633                 :            : #endif
     634                 :            : 
     635                 :            :       ElfW2(LIBELFBITS,Shdr) *shdr_data;
     636 [ +  + ][ +  + ]:         14 :       if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
     637                 :         12 :         shdr_data = (ElfW2(LIBELFBITS,Shdr) *)
     638                 :         12 :           alloca (shnum * sizeof (ElfW2(LIBELFBITS,Shdr)));
     639                 :            :       else
     640                 :            :         shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
     641                 :         14 :       int shdr_flags = elf->flags;
     642                 :            : 
     643                 :            :       /* Get all sections into the array and sort them.  */
     644                 :         14 :       Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
     645                 :         14 :       Elf_Scn **scns = (Elf_Scn **) alloca (shnum * sizeof (Elf_Scn *));
     646                 :         14 :       sort_sections (scns, list);
     647                 :            : 
     648         [ +  + ]:        384 :       for (size_t cnt = 0; cnt < shnum; ++cnt)
     649                 :            :         {
     650                 :        370 :           Elf_Scn *scn = scns[cnt];
     651         [ +  + ]:        370 :           if (scn->index == 0)
     652                 :            :             {
     653                 :            :               /* The dummy section header entry.  It should not be
     654                 :            :                  possible to mark this "section" as dirty.  */
     655         [ -  + ]:         14 :               assert ((scn->flags & ELF_F_DIRTY) == 0);
     656                 :            :               goto next;
     657                 :            :             }
     658                 :            : 
     659                 :        356 :           ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
     660         [ +  + ]:        356 :           if (shdr->sh_type == SHT_NOBITS)
     661                 :            :             goto next;
     662                 :            : 
     663                 :        342 :           off_t scn_start = elf->start_offset + shdr->sh_offset;
     664                 :        342 :           Elf_Data_List *dl = &scn->data_list;
     665                 :        342 :           bool scn_changed = false;
     666                 :            : 
     667         [ +  - ]:        342 :           if (scn->data_list_rear != NULL)
     668                 :            :             do
     669                 :            :               {
     670                 :            :                 /* If there is a gap, fill it.  */
     671         [ +  + ]:        342 :                 if (scn_start + dl->data.d.d_off > last_offset
     672 [ +  - ][ -  + ]:         66 :                     && ((previous_scn_changed && dl->data.d.d_off == 0)
     673         [ #  # ]:          0 :                         || ((scn->flags | dl->flags | elf->flags)
     674                 :          0 :                             & ELF_F_DIRTY) != 0))
     675                 :            :                   {
     676         [ +  - ]:         66 :                     if (unlikely (fill (elf->fildes, last_offset,
     677                 :            :                                         (scn_start + dl->data.d.d_off)
     678                 :            :                                         - last_offset, fillbuf,
     679                 :            :                                         &filled) != 0))
     680                 :            :                       return 1;
     681                 :            :                   }
     682                 :            : 
     683         [ +  - ]:        342 :                 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
     684                 :            :                   {
     685                 :            :                     char tmpbuf[MAX_TMPBUF];
     686                 :        342 :                     void *buf = dl->data.d.d_buf;
     687                 :            : 
     688                 :            :                     /* Let it go backward if the sections use a bogus
     689                 :            :                        layout with overlaps.  We'll overwrite the stupid
     690                 :            :                        user's section data with the latest one, rather than
     691                 :            :                        crashing.  */
     692                 :            : 
     693                 :        342 :                     last_offset = scn_start + dl->data.d.d_off;
     694                 :            : 
     695         [ +  + ]:        342 :                     if (unlikely (change_bo))
     696                 :            :                       {
     697                 :            : #if EV_NUM != 2
     698                 :            :                         xfct_t fctp;
     699                 :            :                         fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
     700                 :            : #else
     701                 :            : # undef fctp
     702                 :            : # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
     703                 :            : #endif
     704                 :            : 
     705                 :         73 :                         buf = tmpbuf;
     706         [ -  + ]:         73 :                         if (dl->data.d.d_size > MAX_TMPBUF)
     707                 :            :                           {
     708                 :          0 :                             buf = malloc (dl->data.d.d_size);
     709         [ #  # ]:          0 :                             if (buf == NULL)
     710                 :            :                               {
     711                 :          0 :                                 __libelf_seterrno (ELF_E_NOMEM);
     712                 :            :                                 return 1;
     713                 :            :                               }
     714                 :            :                           }
     715                 :            : 
     716                 :            :                         /* Do the real work.  */
     717                 :         73 :                         (*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1);
     718                 :            :                       }
     719                 :            : 
     720                 :        342 :                     ssize_t n = pwrite_retry (elf->fildes, buf,
     721                 :            :                                               dl->data.d.d_size,
     722                 :            :                                               last_offset);
     723         [ -  + ]:        342 :                     if (unlikely ((size_t) n != dl->data.d.d_size))
     724                 :            :                       {
     725 [ #  # ][ #  # ]:          0 :                         if (buf != dl->data.d.d_buf && buf != tmpbuf)
     726                 :          0 :                           free (buf);
     727                 :            : 
     728                 :          0 :                         __libelf_seterrno (ELF_E_WRITE_ERROR);
     729                 :            :                         return 1;
     730                 :            :                       }
     731                 :            : 
     732 [ +  + ][ -  + ]:        342 :                     if (buf != dl->data.d.d_buf && buf != tmpbuf)
     733                 :          0 :                       free (buf);
     734                 :            : 
     735                 :        342 :                     scn_changed = true;
     736                 :            :                   }
     737                 :            : 
     738                 :        342 :                 last_offset += dl->data.d.d_size;
     739                 :            : 
     740                 :        342 :                 dl->flags &= ~ELF_F_DIRTY;
     741                 :            : 
     742                 :        342 :                 dl = dl->next;
     743                 :            :               }
     744         [ -  + ]:        342 :             while (dl != NULL);
     745                 :            :           else
     746                 :            :             {
     747                 :            :               /* If the previous section (or the ELF/program
     748                 :            :                  header) changed we might have to fill the gap.  */
     749         [ #  # ]:          0 :               if (scn_start > last_offset && previous_scn_changed)
     750                 :            :                 {
     751         [ #  # ]:          0 :                   if (unlikely (fill (elf->fildes, last_offset,
     752                 :            :                                       scn_start - last_offset, fillbuf,
     753                 :            :                                       &filled) != 0))
     754                 :            :                     return 1;
     755                 :            :                 }
     756                 :            : 
     757                 :          0 :               last_offset = scn_start + shdr->sh_size;
     758                 :            :             }
     759                 :            : 
     760                 :        342 :           previous_scn_changed = scn_changed;
     761                 :            :         next:
     762                 :            :           /* Collect the section header table information.  */
     763         [ +  + ]:        370 :           if (unlikely (change_bo))
     764                 :         80 :             (*shdr_fctp) (&shdr_data[scn->index],
     765                 :         80 :                           scn->shdr.ELFW(e,LIBELFBITS),
     766                 :            :                           sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
     767         [ +  + ]:        290 :           else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
     768                 :        217 :             memcpy (&shdr_data[scn->index], scn->shdr.ELFW(e,LIBELFBITS),
     769                 :            :                     sizeof (ElfW2(LIBELFBITS,Shdr)));
     770                 :            : 
     771                 :        370 :           shdr_flags |= scn->shdr_flags;
     772                 :        370 :           scn->shdr_flags &= ~ELF_F_DIRTY;
     773                 :            :         }
     774                 :            : 
     775                 :            :       /* Fill the gap between last section and section header table if
     776                 :            :          necessary.  */
     777 [ +  + ][ +  + ]:         14 :       if ((elf->flags & ELF_F_DIRTY) && last_offset < shdr_offset
     778         [ +  - ]:          2 :           && unlikely (fill (elf->fildes, last_offset,
     779                 :            :                              shdr_offset - last_offset,
     780                 :            :                              fillbuf, &filled) != 0))
     781                 :            :         return 1;
     782                 :            : 
     783                 :            :       /* Write out the section header table.  */
     784         [ +  - ]:         14 :       if (shdr_flags & ELF_F_DIRTY
     785         [ -  + ]:         14 :           && unlikely ((size_t) pwrite_retry (elf->fildes, shdr_data,
     786                 :            :                                               sizeof (ElfW2(LIBELFBITS,Shdr))
     787                 :            :                                               * shnum, shdr_offset)
     788                 :            :                        != sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum))
     789                 :            :         {
     790                 :          0 :           __libelf_seterrno (ELF_E_WRITE_ERROR);
     791                 :            :           return 1;
     792                 :            :         }
     793                 :            :     }
     794                 :            : 
     795                 :            :   /* That was the last part.  Clear the overall flag.  */
     796                 :         16 :   elf->flags &= ~ELF_F_DIRTY;
     797                 :            : 
     798                 :            :   return 0;
     799                 :            : }

Generated by: LCOV version 1.9