LCOV - code coverage report
Current view: top level - libelf - elf32_updatefile.c (source / functions) Hit Total Coverage
Test: elfutils-0.187 Lines: 280 337 83.1 %
Date: 2022-04-26 02:07:47 Functions: 8 8 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 187 246 76.0 %

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

Generated by: LCOV version 1.14