LCOV - code coverage report
Current view: top level - libelf - elf32_updatefile.c (source / functions) Hit Total Coverage
Test: elfutils-0.173 Lines: 246 300 82.0 %
Date: 2018-06-29 23:49:12 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13