LCOV - code coverage report
Current view: top level - elfutils/libelf - elf32_updatenull.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 116 141 82.3 %
Date: 2013-03-08 Functions: 4 4 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 109 143 76.2 %

           Branch data     Line data    Source code
       1                 :            : /* Update data structures for changes.
       2                 :            :    Copyright (C) 2000-2010 Red Hat, Inc.
       3                 :            :    This file is part of elfutils.
       4                 :            :    Written by Ulrich Drepper <drepper@redhat.com>, 2000.
       5                 :            : 
       6                 :            :    This file is free software; you can redistribute it and/or modify
       7                 :            :    it under the terms of either
       8                 :            : 
       9                 :            :      * the GNU Lesser General Public License as published by the Free
      10                 :            :        Software Foundation; either version 3 of the License, or (at
      11                 :            :        your option) any later version
      12                 :            : 
      13                 :            :    or
      14                 :            : 
      15                 :            :      * the GNU General Public License as published by the Free
      16                 :            :        Software Foundation; either version 2 of the License, or (at
      17                 :            :        your option) any later version
      18                 :            : 
      19                 :            :    or both in parallel, as here.
      20                 :            : 
      21                 :            :    elfutils is distributed in the hope that it will be useful, but
      22                 :            :    WITHOUT ANY WARRANTY; without even the implied warranty of
      23                 :            :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      24                 :            :    General Public License for more details.
      25                 :            : 
      26                 :            :    You should have received copies of the GNU General Public License and
      27                 :            :    the GNU Lesser General Public License along with this program.  If
      28                 :            :    not, see <http://www.gnu.org/licenses/>.  */
      29                 :            : 
      30                 :            : #ifdef HAVE_CONFIG_H
      31                 :            : # include <config.h>
      32                 :            : #endif
      33                 :            : 
      34                 :            : #include <assert.h>
      35                 :            : #include <endian.h>
      36                 :            : #include <libelf.h>
      37                 :            : #include <stdbool.h>
      38                 :            : #include <string.h>
      39                 :            : #include <sys/param.h>
      40                 :            : 
      41                 :            : #include "libelfP.h"
      42                 :            : #include "elf-knowledge.h"
      43                 :            : 
      44                 :            : #ifndef LIBELFBITS
      45                 :            : # define LIBELFBITS 32
      46                 :            : #endif
      47                 :            : 
      48                 :            : 
      49                 :            : 
      50                 :            : static int
      51                 :         70 : ELFW(default_ehdr,LIBELFBITS) (Elf *elf, ElfW2(LIBELFBITS,Ehdr) *ehdr,
      52                 :            :                                size_t shnum, int *change_bop)
      53                 :            : {
      54                 :            :   /* Always write the magic bytes.  */
      55         [ +  + ]:         70 :   if (memcmp (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0)
      56                 :            :     {
      57                 :          5 :       memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG);
      58                 :          5 :       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
      59                 :            :     }
      60                 :            : 
      61                 :            :   /* Always set the file class.  */
      62         [ +  + ]:         70 :   update_if_changed (ehdr->e_ident[EI_CLASS], ELFW(ELFCLASS,LIBELFBITS),
      63                 :            :                      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
      64                 :            : 
      65                 :            :   /* Set the data encoding if necessary.  */
      66         [ -  + ]:         70 :   if (unlikely (ehdr->e_ident[EI_DATA] == ELFDATANONE))
      67                 :            :     {
      68                 :          0 :       ehdr->e_ident[EI_DATA] =
      69                 :            :         BYTE_ORDER == BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB;
      70                 :          0 :       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
      71                 :            :     }
      72         [ -  + ]:         70 :   else if (unlikely (ehdr->e_ident[EI_DATA] >= ELFDATANUM))
      73                 :            :     {
      74                 :          0 :       __libelf_seterrno (ELF_E_DATA_ENCODING);
      75                 :            :       return 1;
      76                 :            :     }
      77                 :            :   else
      78                 :         70 :     *change_bop = ((BYTE_ORDER == LITTLE_ENDIAN
      79                 :            :                     && ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
      80                 :         70 :                    || (BYTE_ORDER == BIG_ENDIAN
      81                 :            :                        && ehdr->e_ident[EI_DATA] != ELFDATA2MSB));
      82                 :            : 
      83                 :            :   /* Unconditionally overwrite the ELF version.  */
      84         [ +  + ]:         70 :   update_if_changed (ehdr->e_ident[EI_VERSION], EV_CURRENT,
      85                 :            :                      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
      86                 :            : 
      87         [ +  - ]:         70 :   if (unlikely (ehdr->e_version == EV_NONE)
      88         [ -  + ]:         70 :       || unlikely (ehdr->e_version >= EV_NUM))
      89                 :            :     {
      90                 :          0 :       __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
      91                 :            :       return 1;
      92                 :            :     }
      93                 :            : 
      94         [ +  + ]:         70 :   if (unlikely (shnum >= SHN_LORESERVE))
      95                 :            :     {
      96         [ -  + ]:          3 :       update_if_changed (ehdr->e_shnum, 0,
      97                 :            :                          elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
      98                 :            :     }
      99                 :            :   else
     100         [ +  + ]:         67 :     update_if_changed (ehdr->e_shnum, shnum,
     101                 :            :                        elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
     102                 :            : 
     103         [ +  + ]:         70 :   if (unlikely (ehdr->e_ehsize != elf_typesize (LIBELFBITS, ELF_T_EHDR, 1)))
     104                 :            :     {
     105                 :         53 :       ehdr->e_ehsize = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
     106                 :         70 :       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
     107                 :            :     }
     108                 :            : 
     109                 :            :   return 0;
     110                 :            : }
     111                 :            : 
     112                 :            : 
     113                 :            : off_t
     114                 :            : internal_function
     115                 :         70 : __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
     116                 :            : {
     117                 :            :   ElfW2(LIBELFBITS,Ehdr) *ehdr;
     118                 :         70 :   int changed = 0;
     119                 :         70 :   int ehdr_flags = 0;
     120                 :            : 
     121                 :         70 :   ehdr = __elfw2(LIBELFBITS,getehdr_wrlock) (elf);
     122                 :            : 
     123                 :            :   /* Set the default values.  */
     124         [ +  - ]:         70 :   if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0)
     125                 :            :     return -1;
     126                 :            : 
     127                 :            :   /* At least the ELF header is there.  */
     128                 :         70 :   off_t size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
     129                 :            : 
     130                 :            :   /* Set the program header position.  */
     131         [ +  + ]:         70 :   if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL
     132         [ -  + ]:         41 :       && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN
     133                 :         41 :           || ehdr->e_type == ET_CORE))
     134                 :          0 :     (void) __elfw2(LIBELFBITS,getphdr_wrlock) (elf);
     135         [ +  + ]:         70 :   if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL)
     136                 :            :     {
     137                 :            :       /* Only executables, shared objects, and core files have a program
     138                 :            :          header.  */
     139         [ -  + ]:         29 :       if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN
     140         [ #  # ]:          0 :           && unlikely (ehdr->e_type != ET_CORE))
     141                 :            :         {
     142                 :          0 :           __libelf_seterrno (ELF_E_INVALID_PHDR);
     143                 :            :           return -1;
     144                 :            :         }
     145                 :            : 
     146                 :            :       size_t phnum;
     147         [ +  - ]:         29 :       if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
     148                 :            :         return -1;
     149                 :            : 
     150         [ +  + ]:         29 :       if (elf->flags & ELF_F_LAYOUT)
     151                 :            :         {
     152                 :            :           /* The user is supposed to fill out e_phoff.  Use it and
     153                 :            :              e_phnum to determine the maximum extend.  */
     154                 :         16 :           size = MAX ((size_t) size,
     155                 :            :                       ehdr->e_phoff
     156                 :            :                       + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
     157                 :            :         }
     158                 :            :       else
     159                 :            :         {
     160         [ +  + ]:         13 :           update_if_changed (ehdr->e_phoff,
     161                 :            :                              elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
     162                 :            :                              ehdr_flags);
     163                 :            : 
     164                 :            :           /* We need no alignment here.  */
     165                 :         29 :           size += elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum);
     166                 :            :         }
     167                 :            :     }
     168                 :            : 
     169         [ +  + ]:         70 :   if (shnum > 0)
     170                 :            :     {
     171                 :            :       Elf_ScnList *list;
     172                 :         67 :       bool first = true;
     173                 :            : 
     174         [ -  + ]:         67 :       assert (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0);
     175                 :            : 
     176         [ +  + ]:         67 :       if (shnum >= SHN_LORESERVE)
     177                 :            :         {
     178                 :            :           /* We have to  fill in the number of sections in the header
     179                 :            :              of the zeroth section.  */
     180                 :          3 :           Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0];
     181                 :            : 
     182         [ +  - ]:          3 :           update_if_changed (scn0->shdr.ELFW(e,LIBELFBITS)->sh_size,
     183                 :            :                              shnum, scn0->shdr_flags);
     184                 :            :         }
     185                 :            : 
     186                 :            :       /* Go over all sections and find out how large they are.  */
     187                 :         67 :       list = &elf->state.ELFW(elf,LIBELFBITS).scns;
     188                 :            : 
     189                 :            :       /* Load the section headers if necessary.  This loads the
     190                 :            :          headers for all sections.  */
     191         [ +  + ]:         67 :       if (list->data[1].shdr.ELFW(e,LIBELFBITS) == NULL)
     192                 :         67 :         (void) __elfw2(LIBELFBITS,getshdr_wrlock) (&list->data[1]);
     193                 :            : 
     194                 :            :       do
     195                 :            :         {
     196         [ +  + ]:     199550 :           for (size_t cnt = first == true; cnt < list->cnt; ++cnt)
     197                 :            :             {
     198                 :     199378 :               Elf_Scn *scn = &list->data[cnt];
     199                 :     199378 :               ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
     200                 :     199378 :               off_t offset = 0;
     201                 :            : 
     202         [ -  + ]:     199378 :               assert (shdr != NULL);
     203                 :     199378 :               ElfW2(LIBELFBITS,Word) sh_entsize = shdr->sh_entsize;
     204         [ +  + ]:     199378 :               ElfW2(LIBELFBITS,Word) sh_align = shdr->sh_addralign ?: 1;
     205                 :            : 
     206                 :            :               /* Set the sh_entsize value if we can reliably detect it.  */
     207   [ +  +  +  +  :     199378 :               switch (shdr->sh_type)
          +  +  +  +  -  
                   -  + ]
     208                 :            :                 {
     209                 :            :                 case SHT_SYMTAB:
     210                 :         50 :                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
     211                 :         50 :                   break;
     212                 :            :                 case SHT_RELA:
     213                 :        122 :                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELA, 1);
     214                 :        122 :                   break;
     215                 :            :                 case SHT_GROUP:
     216                 :            :                   /* Only relocatable files can contain section groups.  */
     217         [ -  + ]:      22005 :                   if (ehdr->e_type != ET_REL)
     218                 :            :                     {
     219                 :          0 :                       __libelf_seterrno (ELF_E_GROUP_NOT_REL);
     220                 :          0 :                       return -1;
     221                 :            :                     }
     222                 :            :                   /* FALLTHROUGH */
     223                 :            :                 case SHT_SYMTAB_SHNDX:
     224                 :      22007 :                   sh_entsize = elf_typesize (32, ELF_T_WORD, 1);
     225                 :      22007 :                   break;
     226                 :            :                 case SHT_HASH:
     227 [ +  + ][ -  + ]:         14 :                   sh_entsize = SH_ENTSIZE_HASH (ehdr);
                 [ #  # ]
     228                 :         14 :                   break;
     229                 :            :                 case SHT_DYNAMIC:
     230                 :         18 :                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_DYN, 1);
     231                 :         18 :                   break;
     232                 :            :                 case SHT_REL:
     233                 :         43 :                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_REL, 1);
     234                 :         43 :                   break;
     235                 :            :                 case SHT_DYNSYM:
     236                 :         16 :                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
     237                 :         16 :                   break;
     238                 :            :                 case SHT_SUNW_move:
     239                 :          0 :                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_MOVE, 1);
     240                 :          0 :                   break;
     241                 :            :                 case SHT_SUNW_syminfo:
     242                 :          0 :                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYMINFO, 1);
     243                 :          0 :                   break;
     244                 :            :                 default:
     245                 :            :                   break;
     246                 :            :                 }
     247                 :            : 
     248                 :            :               /* If the section header contained the wrong entry size
     249                 :            :                  correct it and mark the header as modified.  */
     250         [ +  + ]:     199378 :               update_if_changed (shdr->sh_entsize, sh_entsize,
     251                 :            :                                  scn->shdr_flags);
     252                 :            : 
     253         [ +  + ]:     199378 :               if (scn->data_read == 0
     254         [ +  - ]:         12 :                   && __libelf_set_rawdata_wrlock (scn) != 0)
     255                 :            :                 /* Something went wrong.  The error value is already set.  */
     256                 :            :                 return -1;
     257                 :            : 
     258                 :            :               /* Iterate over all data blocks.  */
     259         [ +  + ]:     199378 :               if (list->data[cnt].data_list_rear != NULL)
     260                 :            :                 {
     261                 :     199364 :                   Elf_Data_List *dl = &scn->data_list;
     262                 :            : 
     263         [ +  + ]:     398730 :                   while (dl != NULL)
     264                 :            :                     {
     265                 :     199366 :                       Elf_Data *data = &dl->data.d;
     266 [ +  + ][ +  + ]:     199366 :                       if (dl == &scn->data_list && data->d_buf == NULL
     267         [ -  + ]:        344 :                           && scn->rawdata.d.d_buf != NULL)
     268                 :          0 :                         data = &scn->rawdata.d;
     269                 :            : 
     270         [ +  - ]:     199366 :                       if (unlikely (data->d_version == EV_NONE)
     271         [ -  + ]:     199366 :                           || unlikely (data->d_version >= EV_NUM))
     272                 :            :                         {
     273                 :          0 :                           __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
     274                 :          0 :                           return -1;
     275                 :            :                         }
     276                 :            : 
     277         [ -  + ]:     199366 :                       if (unlikely (! powerof2 (data->d_align)))
     278                 :            :                         {
     279                 :          0 :                           __libelf_seterrno (ELF_E_INVALID_ALIGN);
     280                 :          0 :                           return -1;
     281                 :            :                         }
     282                 :            : 
     283                 :     199366 :                       sh_align = MAX (sh_align, data->d_align);
     284                 :            : 
     285         [ +  + ]:     199366 :                       if (elf->flags & ELF_F_LAYOUT)
     286                 :            :                         {
     287                 :            :                           /* The user specified the offset and the size.
     288                 :            :                              All we have to do is check whether this block
     289                 :            :                              fits in the size specified for the section.  */
     290         [ -  + ]:        525 :                           if (unlikely ((GElf_Word) (data->d_off
     291                 :            :                                                      + data->d_size)
     292                 :            :                                         > shdr->sh_size))
     293                 :            :                             {
     294                 :          0 :                               __libelf_seterrno (ELF_E_SECTION_TOO_SMALL);
     295                 :          0 :                               return -1;
     296                 :            :                             }
     297                 :            :                         }
     298                 :            :                       else
     299                 :            :                         {
     300                 :            :                           /* Determine the padding.  */
     301                 :     397682 :                           offset = ((offset + data->d_align - 1)
     302                 :     198841 :                                     & ~(data->d_align - 1));
     303                 :            : 
     304         [ -  + ]:     198841 :                           update_if_changed (data->d_off, offset, changed);
     305                 :            : 
     306                 :     198841 :                           offset += data->d_size;
     307                 :            :                         }
     308                 :            : 
     309                 :            :                       /* Next data block.  */
     310                 :     199366 :                       dl = dl->next;
     311                 :            :                     }
     312                 :            :                 }
     313                 :            :               else
     314                 :            :                 /* Get the size of the section from the raw data.  If
     315                 :            :                    none is available the value is zero.  */
     316                 :         14 :                 offset += scn->rawdata.d.d_size;
     317                 :            : 
     318         [ +  + ]:     199378 :               if (elf->flags & ELF_F_LAYOUT)
     319                 :            :                 {
     320         [ +  + ]:        525 :                   size = MAX ((GElf_Word) size,
     321                 :            :                               shdr->sh_offset
     322                 :            :                               + (shdr->sh_type != SHT_NOBITS
     323                 :            :                                  ? shdr->sh_size : 0));
     324                 :            : 
     325                 :            :                   /* The alignment must be a power of two.  This is a
     326                 :            :                      requirement from the ELF specification.  Additionally
     327                 :            :                      we test for the alignment of the section being large
     328                 :            :                      enough for the largest alignment required by a data
     329                 :            :                      block.  */
     330         [ +  - ]:        525 :                   if (unlikely (! powerof2 (shdr->sh_addralign))
     331         [ -  + ]:        525 :                       || unlikely (shdr->sh_addralign < sh_align))
     332                 :            :                     {
     333                 :          0 :                       __libelf_seterrno (ELF_E_INVALID_ALIGN);
     334                 :          0 :                       return -1;
     335                 :            :                     }
     336                 :            :                 }
     337                 :            :               else
     338                 :            :                 {
     339                 :            :                   /* How much alignment do we need for this section.  */
     340         [ +  + ]:     198853 :                   update_if_changed (shdr->sh_addralign, sh_align,
     341                 :            :                                      scn->shdr_flags);
     342                 :            : 
     343                 :     198853 :                   size = (size + sh_align - 1) & ~(sh_align - 1);
     344                 :     198853 :                   int offset_changed = 0;
     345         [ +  + ]:     198853 :                   update_if_changed (shdr->sh_offset, (GElf_Word) size,
     346                 :            :                                      offset_changed);
     347                 :     198853 :                   changed |= offset_changed;
     348                 :            : 
     349 [ +  + ][ +  + ]:     198853 :                   if (offset_changed && scn->data_list_rear == NULL)
     350                 :            :                     {
     351                 :            :                       /* The position of the section in the file
     352                 :            :                          changed.  Create the section data list.  */
     353         [ +  - ]:          6 :                       if (__elf_getdata_rdlock (scn, NULL) == NULL)
     354                 :            :                         return -1;
     355                 :            :                     }
     356                 :            : 
     357                 :            :                   /* See whether the section size is correct.  */
     358         [ +  + ]:     198853 :                   update_if_changed (shdr->sh_size, (GElf_Word) offset,
     359                 :            :                                      changed);
     360                 :            : 
     361         [ +  + ]:     198853 :                   if (shdr->sh_type != SHT_NOBITS)
     362                 :     198558 :                     size += offset;
     363                 :            : 
     364                 :     198853 :                   scn->flags |= changed;
     365                 :            :                 }
     366                 :            : 
     367                 :            :               /* Check that the section size is actually a multiple of
     368                 :            :                  the entry size.  */
     369         [ +  + ]:     199378 :               if (shdr->sh_entsize != 0
     370         [ -  + ]:      22498 :                   && unlikely (shdr->sh_size % shdr->sh_entsize != 0)
     371         [ #  # ]:          0 :                   && (elf->flags & ELF_F_PERMISSIVE) == 0)
     372                 :            :                 {
     373                 :          0 :                   __libelf_seterrno (ELF_E_INVALID_SHENTSIZE);
     374                 :          0 :                   return -1;
     375                 :            :                 }
     376                 :            :             }
     377                 :            : 
     378 [ +  + ][ -  + ]:        172 :           assert (list->next == NULL || list->cnt == list->max);
     379                 :            : 
     380                 :        172 :           first = false;
     381                 :            :         }
     382         [ +  + ]:        172 :       while ((list = list->next) != NULL);
     383                 :            : 
     384                 :            :       /* Store section information.  */
     385         [ +  + ]:         67 :       if (elf->flags & ELF_F_LAYOUT)
     386                 :            :         {
     387                 :            :           /* The user is supposed to fill out e_shoff.  Use it and
     388                 :            :              e_shnum (or sh_size of the dummy, first section header)
     389                 :            :              to determine the maximum extend.  */
     390                 :         18 :           size = MAX ((GElf_Word) size,
     391                 :            :                       (ehdr->e_shoff
     392                 :            :                        + (elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum))));
     393                 :            :         }
     394                 :            :       else
     395                 :            :         {
     396                 :            :           /* Align for section header table.
     397                 :            : 
     398                 :            :              Yes, we use `sizeof' and not `__alignof__' since we do not
     399                 :            :              want to be surprised by architectures with less strict
     400                 :            :              alignment rules.  */
     401                 :            : #define SHDR_ALIGN sizeof (ElfW2(LIBELFBITS,Off))
     402                 :         49 :           size = (size + SHDR_ALIGN - 1) & ~(SHDR_ALIGN - 1);
     403                 :            : 
     404         [ +  + ]:         49 :           update_if_changed (ehdr->e_shoff, (GElf_Word) size, elf->flags);
     405         [ +  + ]:         49 :           update_if_changed (ehdr->e_shentsize,
     406                 :            :                              elf_typesize (LIBELFBITS, ELF_T_SHDR, 1),
     407                 :            :                              ehdr_flags);
     408                 :            : 
     409                 :            :           /* Account for the section header size.  */
     410                 :         49 :           size += elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum);
     411                 :            :         }
     412                 :            :     }
     413                 :            : 
     414                 :         70 :   elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ehdr_flags;
     415                 :            : 
     416                 :         70 :   return size;
     417                 :         45 : }

Generated by: LCOV version 1.9