Home | History | Annotate | Download | only in libelf
      1 /* Create new ELF program header table.
      2    Copyright (C) 1999-2010, 2014, 2015 Red Hat, Inc.
      3    This file is part of elfutils.
      4    Written by Ulrich Drepper <drepper (at) redhat.com>, 1998.
      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 <stdlib.h>
     36 #include <string.h>
     37 
     38 #include "libelfP.h"
     39 
     40 #ifndef LIBELFBITS
     41 # define LIBELFBITS 32
     42 #endif
     43 
     44 
     45 ElfW2(LIBELFBITS,Phdr) *
     46 elfw2(LIBELFBITS,newphdr) (Elf *elf, size_t count)
     47 {
     48   ElfW2(LIBELFBITS,Phdr) *result;
     49 
     50   if (elf == NULL)
     51     return NULL;
     52 
     53   if (unlikely (elf->kind != ELF_K_ELF))
     54     {
     55       __libelf_seterrno (ELF_E_INVALID_HANDLE);
     56       return NULL;
     57     }
     58 
     59   if (unlikely ((ElfW2(LIBELFBITS,Word)) count != count))
     60     {
     61       __libelf_seterrno (ELF_E_INVALID_OPERAND);
     62       return NULL;
     63     }
     64 
     65   rwlock_wrlock (elf->lock);
     66 
     67   if (elf->class == 0)
     68     elf->class = ELFW(ELFCLASS,LIBELFBITS);
     69   else if (unlikely (elf->class != ELFW(ELFCLASS,LIBELFBITS)))
     70     {
     71       __libelf_seterrno (ELF_E_INVALID_CLASS);
     72       result = NULL;
     73       goto out;
     74     }
     75 
     76   if (unlikely (elf->state.ELFW(elf,LIBELFBITS).ehdr == NULL))
     77     {
     78       __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
     79       result = NULL;
     80       goto out;
     81     }
     82 
     83   /* A COUNT of zero means remove existing table.  */
     84   if (count == 0)
     85     {
     86       /* Free the old program header.  */
     87       if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL)
     88 	{
     89 	  if (elf->state.ELFW(elf,LIBELFBITS).phdr_flags & ELF_F_MALLOCED)
     90 	    free (elf->state.ELFW(elf,LIBELFBITS).phdr);
     91 
     92 	  /* Set the pointer to NULL.  */
     93 	  elf->state.ELFW(elf,LIBELFBITS).phdr = NULL;
     94 	  /* Set the `e_phnum' member to the new value.  */
     95 	  elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = 0;
     96 	  /* Also clear any old PN_XNUM extended value.  */
     97 	  if (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0)
     98 	    elf->state.ELFW(elf,LIBELFBITS).scns.data[0]
     99 	      .shdr.ELFW(e,LIBELFBITS)->sh_info = 0;
    100 	  /* Also set the size.  */
    101 	  elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize =
    102 	    sizeof (ElfW2(LIBELFBITS,Phdr));
    103 
    104 	  elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_DIRTY;
    105 	  elf->flags |= ELF_F_DIRTY;
    106 	  __libelf_seterrno (ELF_E_NOERROR);
    107 	}
    108 
    109       result = NULL;
    110     }
    111   else if (elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum != count
    112 	   || count == PN_XNUM
    113 	   || elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
    114     {
    115       if (unlikely (count > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Phdr))))
    116 	{
    117 	  __libelf_seterrno (ELF_E_INVALID_INDEX);
    118 	  result = NULL;
    119 	  goto out;
    120 	}
    121 
    122       Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0];
    123       if (unlikely (count >= PN_XNUM && scn0->shdr.ELFW(e,LIBELFBITS) == NULL))
    124 	{
    125 	  /* Something is wrong with section zero, but we need it to write
    126 	     the extended phdr count.  */
    127 	  __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
    128 	  result = NULL;
    129 	  goto out;
    130 	}
    131 
    132       /* Allocate a new program header with the appropriate number of
    133 	 elements.  */
    134       result = (ElfW2(LIBELFBITS,Phdr) *)
    135 	realloc (elf->state.ELFW(elf,LIBELFBITS).phdr,
    136 		 count * sizeof (ElfW2(LIBELFBITS,Phdr)));
    137       if (result == NULL)
    138 	__libelf_seterrno (ELF_E_NOMEM);
    139       else
    140 	{
    141 	  /* Now set the result.  */
    142 	  elf->state.ELFW(elf,LIBELFBITS).phdr = result;
    143 	  if (count >= PN_XNUM)
    144 	    {
    145 	      /* We have to write COUNT into the zeroth section's sh_info.  */
    146 	      if (elf->state.ELFW(elf,LIBELFBITS).scns.cnt == 0)
    147 		{
    148 		  assert (elf->state.ELFW(elf,LIBELFBITS).scns.max > 0);
    149 		  elf->state.ELFW(elf,LIBELFBITS).scns.cnt = 1;
    150 		}
    151 	      scn0->shdr.ELFW(e,LIBELFBITS)->sh_info = count;
    152 	      scn0->shdr_flags |= ELF_F_DIRTY;
    153 	      elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = PN_XNUM;
    154 	    }
    155 	  else
    156 	    /* Set the `e_phnum' member to the new value.  */
    157 	    elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = count;
    158 	  /* Clear the whole memory.  */
    159 	  memset (result, '\0', count * sizeof (ElfW2(LIBELFBITS,Phdr)));
    160 	  /* Also set the size.  */
    161 	  elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize =
    162 	    elf_typesize (LIBELFBITS, ELF_T_PHDR, 1);
    163 	  /* Remember we allocated the array and mark the structure is
    164 	     modified.  */
    165 	  elf->state.ELFW(elf,LIBELFBITS).phdr_flags |=
    166 	    ELF_F_DIRTY | ELF_F_MALLOCED;
    167 	  /* We have to rewrite the entire file if the size of the
    168 	     program header is changed.  */
    169 	  elf->flags |= ELF_F_DIRTY;
    170 	}
    171     }
    172   else
    173     {
    174       /* We have the same number of entries.  Just clear the array.  */
    175       assert (elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize
    176 	      == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
    177 
    178       /* Mark the structure as modified.  */
    179       elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_DIRTY;
    180 
    181       result = elf->state.ELFW(elf,LIBELFBITS).phdr;
    182       memset (result, '\0', count * sizeof (ElfW2(LIBELFBITS,Phdr)));
    183     }
    184 
    185  out:
    186   rwlock_unlock (elf->lock);
    187 
    188   return result;
    189 }
    190 INTDEF(elfw2(LIBELFBITS,newphdr))
    191