LCOV - code coverage report
Current view: top level - libelf - elf32_updatefile.c (source / functions) Hit Total Coverage
Test: elfutils-0.175 Lines: 258 301 85.7 %
Date: 2018-11-16 13:02:39 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    25199387 : compare_sections (const void *a, const void *b)
      54             : {
      55    25199387 :   const Elf_Scn **scna = (const Elf_Scn **) a;
      56    25199387 :   const Elf_Scn **scnb = (const Elf_Scn **) b;
      57             : 
      58    50398774 :   if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
      59    25199387 :       < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
      60             :     return -1;
      61             : 
      62        4211 :   if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
      63             :       > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
      64             :     return 1;
      65             : 
      66        7668 :   if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
      67        3834 :       < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
      68             :     return -1;
      69             : 
      70        2053 :   if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
      71             :       > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
      72             :     return 1;
      73             : 
      74         353 :   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         458 : sort_sections (Elf_Scn **scns, Elf_ScnList *list)
      92             : {
      93         458 :   Elf_Scn **scnp = scns;
      94             :   do
      95     3093437 :     for (size_t cnt = 0; cnt < list->cnt; ++cnt)
      96     3092114 :       *scnp++ = &list->data[cnt];
      97        1323 :   while ((list = list->next) != NULL);
      98             : 
      99         458 :   qsort (scns, scnp - scns, sizeof (*scns), compare_sections);
     100         458 : }
     101             : 
     102             : 
     103             : static inline void
     104         714 : fill_mmap (size_t offset, char *last_position, char *scn_start,
     105             :            char *const shdr_start, char *const shdr_end)
     106             : {
     107         714 :   size_t written = 0;
     108             : 
     109         714 :   if (last_position < shdr_start)
     110             :     {
     111         712 :       written = MIN (scn_start + offset - last_position,
     112             :                      shdr_start - last_position);
     113             : 
     114         712 :       memset (last_position, __libelf_fill_byte, written);
     115             :     }
     116             : 
     117         714 :   if (last_position + written != scn_start + offset
     118           8 :       && 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         714 : }
     125             : 
     126             : int
     127             : internal_function
     128         187 : __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
     129             : {
     130         187 :   bool previous_scn_changed = false;
     131             : 
     132             :   /* We need the ELF header several times.  */
     133         187 :   ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
     134             : 
     135             :   /* Write out the ELF header.  */
     136         187 :   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         185 :       assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
     141             :               == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
     142             : 
     143         185 :       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          56 :           (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr,
     156             :                    sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
     157             :         }
     158         129 :       else if (elf->map_address + elf->start_offset != ehdr)
     159         122 :         memcpy (elf->map_address + elf->start_offset, ehdr,
     160             :                 sizeof (ElfW2(LIBELFBITS,Ehdr)));
     161             : 
     162         185 :       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         185 :       previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
     167             :     }
     168             : 
     169             :   size_t phnum;
     170         187 :   if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
     171             :     return -1;
     172             : 
     173             :   /* Write out the program header table.  */
     174         187 :   if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
     175         152 :       && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
     176          76 :           & ELF_F_DIRTY))
     177             :     {
     178             :       /* If the type sizes should be different at some time we have to
     179             :          rewrite this code.  */
     180          76 :       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          76 :       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          76 :       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          28 :           (*fctp) (elf->map_address + elf->start_offset + ehdr->e_phoff,
     202          14 :                    elf->state.ELFW(elf,LIBELFBITS).phdr,
     203             :                    sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
     204             :         }
     205             :       else
     206         124 :         memmove (elf->map_address + elf->start_offset + ehdr->e_phoff,
     207          62 :                 elf->state.ELFW(elf,LIBELFBITS).phdr,
     208             :                 sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
     209             : 
     210          76 :       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          76 :       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         374 :   char *last_position = ((char *) elf->map_address + elf->start_offset
     220         187 :                          + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
     221             :                                 ehdr->e_phoff)
     222         187 :                          + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
     223             : 
     224             :   /* Write all the sections.  Well, only those which are modified.  */
     225         187 :   if (shnum > 0)
     226             :     {
     227         183 :       if (unlikely (shnum > SIZE_MAX / sizeof (Elf_Scn *)))
     228             :         return 1;
     229             : 
     230         183 :       Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
     231         183 :       Elf_Scn **scns = (Elf_Scn **) malloc (shnum * sizeof (Elf_Scn *));
     232         183 :       if (unlikely (scns == NULL))
     233             :         {
     234           0 :           __libelf_seterrno (ELF_E_NOMEM);
     235           0 :           return -1;
     236             :         }
     237         183 :       char *const shdr_start = ((char *) elf->map_address + elf->start_offset
     238         183 :                                 + ehdr->e_shoff);
     239         183 :       char *const shdr_end = shdr_start + 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         183 :       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      792321 :       for (size_t cnt = 0; cnt < shnum; ++cnt)
     255             :         {
     256      792138 :           Elf_Scn *scn = scns[cnt];
     257             : 
     258      792138 :           if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
     259      792028 :               && (scn->shdr_flags & ELF_F_MALLOCED) == 0
     260         105 :               && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
     261             :             {
     262          99 :               assert ((char *) elf->map_address + elf->start_offset
     263             :                       < (char *) scn->shdr.ELFW(e,LIBELFBITS));
     264          99 :               assert ((char *) scn->shdr.ELFW(e,LIBELFBITS)
     265             :                       < ((char *) elf->map_address + elf->start_offset
     266             :                          + elf->maximum_size));
     267             : 
     268          99 :               void *p = malloc (sizeof (ElfW2(LIBELFBITS,Shdr)));
     269          99 :               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         198 :                 = 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     1584276 :           if (((char *) elf->map_address + elf->start_offset
     287      792138 :                <= (char  *) scn->data_list.data.d.d_buf)
     288      524704 :               && ((char *) scn->data_list.data.d.d_buf
     289             :                   < ((char *) elf->map_address + elf->start_offset
     290      524704 :                      + elf->maximum_size))
     291          30 :               && (((char *) elf->map_address + elf->start_offset
     292          30 :                    + scn->shdr.ELFW(e,LIBELFBITS)->sh_offset)
     293             :                   > (char *) scn->data_list.data.d.d_buf))
     294             :             {
     295           1 :               void *p = malloc (scn->data_list.data.d.d_size);
     296           1 :               if (unlikely (p == NULL))
     297             :                 {
     298           0 :                   free (scns);
     299           0 :                   __libelf_seterrno (ELF_E_NOMEM);
     300           0 :                   return -1;
     301             :                 }
     302           1 :               scn->data_list.data.d.d_buf = scn->data_base
     303           2 :                 = 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      792138 :       for (size_t cnt = 0; cnt < shnum; ++cnt)
     311             :         {
     312      792138 :           Elf_Scn *scn = scns[cnt];
     313      792138 :           if (scn->index == 0)
     314             :             {
     315             :               /* The dummy section header entry.  It should not be
     316             :                  possible to mark this "section" as dirty.  */
     317         183 :               assert ((scn->flags & ELF_F_DIRTY) == 0);
     318         183 :               continue;
     319             :             }
     320             : 
     321      791955 :           ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
     322      791955 :           if (shdr->sh_type == SHT_NOBITS)
     323             :             goto next;
     324             : 
     325     1581798 :           char *scn_start = ((char *) elf->map_address
     326      790899 :                              + elf->start_offset + shdr->sh_offset);
     327      790899 :           Elf_Data_List *dl = &scn->data_list;
     328      790899 :           bool scn_changed = false;
     329             : 
     330      790899 :           if (scn->data_list_rear != NULL)
     331             :             do
     332             :               {
     333      790779 :                 assert (dl->data.d.d_off >= 0);
     334      790779 :                 assert ((GElf_Off) dl->data.d.d_off <= shdr->sh_size);
     335      790779 :                 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      790779 :                 if (scn_start + dl->data.d.d_off > last_position
     340         711 :                     && (dl->data.d.d_off == 0
     341           0 :                         || ((scn->flags | dl->flags | elf->flags)
     342           0 :                             & ELF_F_DIRTY) != 0))
     343             :                   {
     344         711 :                     fill_mmap (dl->data.d.d_off, last_position, scn_start,
     345             :                                shdr_start, shdr_end);
     346             :                   }
     347             : 
     348      790779 :                 last_position = scn_start + dl->data.d.d_off;
     349             : 
     350      790779 :                 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      790771 :                     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      262903 :                         (*fctp) (last_position, dl->data.d.d_buf,
     369             :                                  dl->data.d.d_size, 1);
     370             : 
     371      262903 :                         last_position += dl->data.d.d_size;
     372             :                       }
     373      527868 :                     else if (dl->data.d.d_size != 0)
     374             :                       {
     375     1055620 :                         memmove (last_position, dl->data.d.d_buf,
     376             :                                  dl->data.d.d_size);
     377      527810 :                         last_position += dl->data.d.d_size;
     378             :                       }
     379             : 
     380             :                     scn_changed = true;
     381             :                   }
     382             :                 else
     383           8 :                   last_position += dl->data.d.d_size;
     384             : 
     385      790779 :                 assert (scn_start + dl->data.d.d_off + dl->data.d.d_size
     386             :                         == last_position);
     387             : 
     388      790779 :                 dl->flags &= ~ELF_F_DIRTY;
     389             : 
     390      790779 :                 dl = dl->next;
     391             :               }
     392      790779 :             while (dl != NULL);
     393             :           else
     394             :             {
     395             :               /* If the previous section (or the ELF/program
     396             :                  header) changed we might have to fill the gap.  */
     397         148 :               if (scn_start > last_position && previous_scn_changed)
     398           3 :                 fill_mmap (0, last_position, scn_start,
     399             :                            shdr_start, shdr_end);
     400             : 
     401             :               /* We have to trust the existing section header information.  */
     402         148 :               last_position = scn_start + shdr->sh_size;
     403             :             }
     404             : 
     405             : 
     406             :           previous_scn_changed = scn_changed;
     407      793011 :         next:
     408      791955 :           scn->flags &= ~ELF_F_DIRTY;
     409             :         }
     410             : 
     411             :       /* Fill the gap between last section and section header table if
     412             :          necessary.  */
     413         183 :       if ((elf->flags & ELF_F_DIRTY)
     414         362 :           && last_position < ((char *) elf->map_address + elf->start_offset
     415         181 :                               + ehdr->e_shoff))
     416         152 :         memset (last_position, __libelf_fill_byte,
     417             :                 (char *) elf->map_address + elf->start_offset + ehdr->e_shoff
     418         152 :                 - last_position);
     419             : 
     420             :       /* Write the section header table entry if necessary.  */
     421      792138 :       for (size_t cnt = 0; cnt < shnum; ++cnt)
     422             :         {
     423      792138 :           Elf_Scn *scn = scns[cnt];
     424             : 
     425      792138 :           if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY)
     426             :             {
     427      792126 :               if (unlikely (change_bo))
     428      526388 :                 (*shdr_fctp) (&shdr_dest[scn->index],
     429      263194 :                               scn->shdr.ELFW(e,LIBELFBITS),
     430             :                               sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
     431             :               else
     432      528932 :                 memcpy (&shdr_dest[scn->index],
     433      528932 :                         scn->shdr.ELFW(e,LIBELFBITS),
     434             :                         sizeof (ElfW2(LIBELFBITS,Shdr)));
     435             : 
     436             :               /* If we previously made a copy of the section header
     437             :                  entry we now have to adjust the pointer again so
     438             :                  point to new place in the mapping.  */
     439      792126 :               if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
     440      792022 :                   && (scn->shdr_flags & ELF_F_MALLOCED) == 0
     441          99 :                   && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
     442             :                 {
     443          99 :                   free (scn->shdr.ELFW(e,LIBELFBITS));
     444          99 :                   scn->shdr.ELFW(e,LIBELFBITS) = &shdr_dest[scn->index];
     445             :                 }
     446             : 
     447      792126 :               scn->shdr_flags &= ~ELF_F_DIRTY;
     448             :             }
     449             :         }
     450         183 :       free (scns);
     451             :     }
     452             : 
     453             :   /* That was the last part.  Clear the overall flag.  */
     454         187 :   elf->flags &= ~ELF_F_DIRTY;
     455             : 
     456             :   /* Make sure the content hits the disk.  */
     457         374 :   char *msync_start = ((char *) elf->map_address
     458         187 :                        + (elf->start_offset & ~(sysconf (_SC_PAGESIZE) - 1)));
     459         374 :   char *msync_end = ((char *) elf->map_address
     460         187 :                      + elf->start_offset + ehdr->e_shoff
     461         187 :                      + ehdr->e_shentsize * shnum);
     462         187 :   (void) msync (msync_start, msync_end - msync_start, MS_SYNC);
     463             : 
     464         187 :   return 0;
     465             : }
     466             : 
     467             : 
     468             : /* Size of the buffer we use to generate the blocks of fill bytes.  */
     469             : #define FILLBUFSIZE     4096
     470             : 
     471             : /* If we have to convert the section buffer contents we have to use
     472             :    temporary buffer.  Only buffers up to MAX_TMPBUF bytes are allocated
     473             :    on the stack.  */
     474             : #define MAX_TMPBUF      32768
     475             : 
     476             : 
     477             : /* Helper function to write out fill bytes.  */
     478             : static int
     479        1553 : fill (int fd, off_t pos, size_t len, char *fillbuf, size_t *filledp)
     480             : {
     481        1553 :   size_t filled = *filledp;
     482        1553 :   size_t fill_len = MIN (len, FILLBUFSIZE);
     483             : 
     484        1553 :   if (unlikely (fill_len > filled) && filled < FILLBUFSIZE)
     485             :     {
     486             :       /* Initialize a few more bytes.  */
     487        1180 :       memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled);
     488         590 :       *filledp = filled = fill_len;
     489             :     }
     490             : 
     491             :   do
     492             :     {
     493             :       /* This many bytes we want to write in this round.  */
     494        1884 :       size_t n = MIN (filled, len);
     495             : 
     496        1884 :       if (unlikely ((size_t) pwrite_retry (fd, fillbuf, n, pos) != n))
     497             :         {
     498           0 :           __libelf_seterrno (ELF_E_WRITE_ERROR);
     499           0 :           return 1;
     500             :         }
     501             : 
     502        1884 :       pos += n;
     503        1884 :       len -= n;
     504             :     }
     505        1884 :   while (len > 0);
     506             : 
     507             :   return 0;
     508             : }
     509             : 
     510             : 
     511             : int
     512             : internal_function
     513         281 : __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
     514             : {
     515             :   char fillbuf[FILLBUFSIZE];
     516         281 :   size_t filled = 0;
     517         281 :   bool previous_scn_changed = false;
     518             : 
     519             :   /* We need the ELF header several times.  */
     520         281 :   ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
     521             : 
     522             :   /* Write out the ELF header.  */
     523         281 :   if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
     524             :     {
     525             :       ElfW2(LIBELFBITS,Ehdr) tmp_ehdr;
     526         279 :       ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr;
     527             : 
     528             :       /* If the type sizes should be different at some time we have to
     529             :          rewrite this code.  */
     530         279 :       assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
     531             :               == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
     532             : 
     533         279 :       if (unlikely (change_bo))
     534             :         {
     535             :           /* Today there is only one version of the ELF header.  */
     536             : #if EV_NUM != 2
     537             :           xfct_t fctp;
     538             :           fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR];
     539             : #else
     540             : # undef fctp
     541             : # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
     542             : #endif
     543             : 
     544             :           /* Write the converted ELF header in a temporary buffer.  */
     545         111 :           (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
     546             : 
     547             :           /* This is the buffer we want to write.  */
     548         111 :           out_ehdr = &tmp_ehdr;
     549             :         }
     550             : 
     551             :       /* Write out the ELF header.  */
     552         279 :       if (unlikely (pwrite_retry (elf->fildes, out_ehdr,
     553             :                                   sizeof (ElfW2(LIBELFBITS,Ehdr)), 0)
     554             :                     != sizeof (ElfW2(LIBELFBITS,Ehdr))))
     555             :         {
     556           0 :           __libelf_seterrno (ELF_E_WRITE_ERROR);
     557           0 :           return 1;
     558             :         }
     559             : 
     560         279 :       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
     561             : 
     562             :       /* We start writing sections after the ELF header only if there is
     563             :          no program header.  */
     564         279 :       previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
     565             :     }
     566             : 
     567             :   /* If the type sizes should be different at some time we have to
     568             :      rewrite this code.  */
     569         281 :   assert (sizeof (ElfW2(LIBELFBITS,Phdr))
     570             :           == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
     571             : 
     572             :   size_t phnum;
     573         281 :   if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
     574             :     return -1;
     575             : 
     576             :   /* Write out the program header table.  */
     577         281 :   if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
     578         422 :       && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
     579         211 :           & ELF_F_DIRTY))
     580             :     {
     581         211 :       ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL;
     582         211 :       ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
     583             : 
     584             :       /* Maybe the user wants a gap between the ELF header and the program
     585             :          header.  */
     586         211 :       if (ehdr->e_phoff > ehdr->e_ehsize
     587           0 :           && unlikely (fill (elf->fildes, ehdr->e_ehsize,
     588             :                              ehdr->e_phoff - ehdr->e_ehsize, fillbuf, &filled)
     589             :                        != 0))
     590             :         return 1;
     591             : 
     592         211 :       if (unlikely (change_bo))
     593             :         {
     594             :           /* Today there is only one version of the ELF header.  */
     595             : #if EV_NUM != 2
     596             :           xfct_t fctp;
     597             :           fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR];
     598             : #else
     599             : # undef fctp
     600             : # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
     601             : #endif
     602             : 
     603             :           /* Allocate sufficient memory.  */
     604          85 :           tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *)
     605          85 :             malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
     606          85 :           if (unlikely (tmp_phdr == NULL))
     607             :             {
     608           0 :               __libelf_seterrno (ELF_E_NOMEM);
     609           0 :               return 1;
     610             :             }
     611             : 
     612             :           /* Write the converted ELF header in a temporary buffer.  */
     613          85 :           (*fctp) (tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr,
     614             :                    sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
     615             : 
     616             :           /* This is the buffer we want to write.  */
     617          85 :           out_phdr = tmp_phdr;
     618             :         }
     619             : 
     620             :       /* Write out the ELF header.  */
     621         211 :       size_t phdr_size = sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum;
     622         211 :       if (unlikely ((size_t) pwrite_retry (elf->fildes, out_phdr,
     623             :                                            phdr_size, ehdr->e_phoff)
     624             :                     != phdr_size))
     625             :         {
     626           0 :           __libelf_seterrno (ELF_E_WRITE_ERROR);
     627           0 :           return 1;
     628             :         }
     629             : 
     630             :       /* This is a no-op we we have not allocated any memory.  */
     631         211 :       free (tmp_phdr);
     632             : 
     633         211 :       elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
     634             : 
     635             :       /* We modified the program header.  Maybe this created a gap so
     636             :          we have to write fill bytes, if necessary.  */
     637         211 :       previous_scn_changed = true;
     638             :     }
     639             : 
     640             :   /* From now on we have to keep track of the last position to eventually
     641             :      fill the gaps with the prescribed fill byte.  */
     642             :   off_t last_offset;
     643         281 :   if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
     644          70 :     last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
     645             :   else
     646         211 :     last_offset = (ehdr->e_phoff + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
     647             : 
     648             :   /* Write all the sections.  Well, only those which are modified.  */
     649         281 :   if (shnum > 0)
     650             :     {
     651         275 :       if (unlikely (shnum > SIZE_MAX / (sizeof (Elf_Scn *)
     652             :                                         + sizeof (ElfW2(LIBELFBITS,Shdr)))))
     653             :         return 1;
     654             : 
     655         275 :       off_t shdr_offset = elf->start_offset + ehdr->e_shoff;
     656             : #if EV_NUM != 2
     657             :       xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR];
     658             : #else
     659             : # undef shdr_fctp
     660             : # define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
     661             : #endif
     662             : 
     663             :       ElfW2(LIBELFBITS,Shdr) *shdr_data;
     664         275 :       ElfW2(LIBELFBITS,Shdr) *shdr_data_mem = NULL;
     665         275 :       if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
     666          20 :           || (elf->flags & ELF_F_DIRTY))
     667             :         {
     668         270 :           shdr_data_mem = (ElfW2(LIBELFBITS,Shdr) *)
     669         270 :             malloc (shnum * sizeof (ElfW2(LIBELFBITS,Shdr)));
     670         270 :           if (unlikely (shdr_data_mem == NULL))
     671             :             {
     672           0 :               __libelf_seterrno (ELF_E_NOMEM);
     673           0 :               return -1;
     674             :             }
     675             :           shdr_data = shdr_data_mem;
     676             :         }
     677             :       else
     678             :         shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
     679         275 :       int shdr_flags = elf->flags;
     680             : 
     681             :       /* Get all sections into the array and sort them.  */
     682         275 :       Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
     683         275 :       Elf_Scn **scns = (Elf_Scn **) malloc (shnum * sizeof (Elf_Scn *));
     684         275 :       if (unlikely (scns == NULL))
     685             :         {
     686           0 :           free (shdr_data_mem);
     687           0 :           __libelf_seterrno (ELF_E_NOMEM);
     688           0 :           return -1;
     689             :         }
     690         275 :       sort_sections (scns, list);
     691             : 
     692     2300251 :       for (size_t cnt = 0; cnt < shnum; ++cnt)
     693             :         {
     694     2299976 :           Elf_Scn *scn = scns[cnt];
     695     2299976 :           if (scn->index == 0)
     696             :             {
     697             :               /* The dummy section header entry.  It should not be
     698             :                  possible to mark this "section" as dirty.  */
     699         275 :               assert ((scn->flags & ELF_F_DIRTY) == 0);
     700             :               goto next;
     701             :             }
     702             : 
     703     2299701 :           ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
     704     2299701 :           if (shdr->sh_type == SHT_NOBITS)
     705             :             goto next;
     706             : 
     707     2299291 :           off_t scn_start = elf->start_offset + shdr->sh_offset;
     708     2299291 :           Elf_Data_List *dl = &scn->data_list;
     709     2299291 :           bool scn_changed = false;
     710             : 
     711     2299291 :           if (scn->data_list_rear != NULL)
     712             :             do
     713             :               {
     714             :                 /* If there is a gap, fill it.  */
     715     1774546 :                 if (scn_start + dl->data.d.d_off > last_offset
     716        1329 :                     && ((previous_scn_changed && dl->data.d.d_off == 0)
     717          18 :                         || ((scn->flags | dl->flags | elf->flags)
     718           9 :                             & ELF_F_DIRTY) != 0))
     719             :                   {
     720        1325 :                     if (unlikely (fill (elf->fildes, last_offset,
     721             :                                         (scn_start + dl->data.d.d_off)
     722             :                                         - last_offset, fillbuf,
     723             :                                         &filled) != 0))
     724             :                       {
     725           0 :                       fail_free:
     726           0 :                         free (shdr_data_mem);
     727           0 :                         free (scns);
     728           0 :                         return 1;
     729             :                       }
     730             :                   }
     731             : 
     732     1774546 :                 last_offset = scn_start + dl->data.d.d_off;
     733             : 
     734     1774546 :                 if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
     735             :                   {
     736             :                     char tmpbuf[MAX_TMPBUF];
     737     1774538 :                     void *buf = dl->data.d.d_buf;
     738             : 
     739             :                     /* Let it go backward if the sections use a bogus
     740             :                        layout with overlaps.  We'll overwrite the stupid
     741             :                        user's section data with the latest one, rather than
     742             :                        crashing.  */
     743             : 
     744     1774538 :                     if (unlikely (change_bo))
     745             :                       {
     746             : #if EV_NUM != 2
     747             :                         xfct_t fctp;
     748             :                         fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type];
     749             : #else
     750             : # undef fctp
     751             : # define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
     752             : #endif
     753             : 
     754      788152 :                         buf = tmpbuf;
     755      788152 :                         if (dl->data.d.d_size > MAX_TMPBUF)
     756             :                           {
     757           5 :                             buf = malloc (dl->data.d.d_size);
     758           5 :                             if (unlikely (buf == NULL))
     759             :                               {
     760           0 :                                 __libelf_seterrno (ELF_E_NOMEM);
     761           0 :                                 goto fail_free;
     762             :                               }
     763             :                           }
     764             : 
     765             :                         /* Do the real work.  */
     766      788152 :                         (*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1);
     767             :                       }
     768             : 
     769     1774538 :                     ssize_t n = pwrite_retry (elf->fildes, buf,
     770             :                                               dl->data.d.d_size,
     771             :                                               last_offset);
     772     1774538 :                     if (unlikely ((size_t) n != dl->data.d.d_size))
     773             :                       {
     774           0 :                         if (buf != dl->data.d.d_buf && buf != tmpbuf)
     775           0 :                           free (buf);
     776             : 
     777           0 :                         __libelf_seterrno (ELF_E_WRITE_ERROR);
     778           0 :                         goto fail_free;
     779             :                       }
     780             : 
     781     1774538 :                     if (buf != dl->data.d.d_buf && buf != tmpbuf)
     782           5 :                       free (buf);
     783             : 
     784     1774538 :                     scn_changed = true;
     785             :                   }
     786             : 
     787     1774546 :                 last_offset += dl->data.d.d_size;
     788             : 
     789     1774546 :                 dl->flags &= ~ELF_F_DIRTY;
     790             : 
     791     1774546 :                 dl = dl->next;
     792             :               }
     793     1774546 :             while (dl != NULL);
     794             :           else
     795             :             {
     796             :               /* If the previous section (or the ELF/program
     797             :                  header) changed we might have to fill the gap.  */
     798      524771 :               if (scn_start > last_offset && previous_scn_changed)
     799             :                 {
     800           6 :                   if (unlikely (fill (elf->fildes, last_offset,
     801             :                                       scn_start - last_offset, fillbuf,
     802             :                                       &filled) != 0))
     803             :                     goto fail_free;
     804             :                 }
     805             : 
     806      524771 :               last_offset = scn_start + shdr->sh_size;
     807             :             }
     808             : 
     809             :           previous_scn_changed = scn_changed;
     810     2300386 :         next:
     811             :           /* Collect the section header table information.  */
     812     2299976 :           if (unlikely (change_bo))
     813     2101480 :             (*shdr_fctp) (&shdr_data[scn->index],
     814     1050740 :                           scn->shdr.ELFW(e,LIBELFBITS),
     815             :                           sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
     816     1249236 :           else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
     817      918018 :                    || (elf->flags & ELF_F_DIRTY))
     818     1249081 :             memcpy (&shdr_data[scn->index], scn->shdr.ELFW(e,LIBELFBITS),
     819             :                     sizeof (ElfW2(LIBELFBITS,Shdr)));
     820             : 
     821     2299976 :           shdr_flags |= scn->shdr_flags;
     822     2299976 :           scn->shdr_flags &= ~ELF_F_DIRTY;
     823             :         }
     824             : 
     825             :       /* Fill the gap between last section and section header table if
     826             :          necessary.  */
     827         275 :       if ((elf->flags & ELF_F_DIRTY) && last_offset < shdr_offset
     828         222 :           && unlikely (fill (elf->fildes, last_offset,
     829             :                              shdr_offset - last_offset,
     830             :                              fillbuf, &filled) != 0))
     831             :         goto fail_free;
     832             : 
     833             :       /* Write out the section header table.  */
     834         275 :       if (shdr_flags & ELF_F_DIRTY
     835         273 :           && unlikely ((size_t) pwrite_retry (elf->fildes, shdr_data,
     836             :                                               sizeof (ElfW2(LIBELFBITS,Shdr))
     837             :                                               * shnum, shdr_offset)
     838             :                        != sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum))
     839             :         {
     840           0 :           __libelf_seterrno (ELF_E_WRITE_ERROR);
     841           0 :           goto fail_free;
     842             :         }
     843             : 
     844         275 :       free (shdr_data_mem);
     845         275 :       free (scns);
     846             :     }
     847             : 
     848             :   /* That was the last part.  Clear the overall flag.  */
     849         281 :   elf->flags &= ~ELF_F_DIRTY;
     850             : 
     851         281 :   return 0;
     852             : }

Generated by: LCOV version 1.13