LCOV - code coverage report
Current view: top level - libelf - elf32_updatefile.c (source / functions) Hit Total Coverage
Test: elfutils-0.189 Lines: 280 337 83.1 %
Date: 2023-11-03 00:03:04 Functions: 8 8 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 187 244 76.6 %

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

Generated by: LCOV version 1.16