Home | History | Annotate | Download | only in libelf
      1 /* Return section header.
      2    Copyright (C) 1998-2002, 2005, 2007, 2009, 2012, 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 <errno.h>
     36 #include <stdbool.h>
     37 #include <unistd.h>
     38 
     39 #include <system.h>
     40 #include "libelfP.h"
     41 #include "common.h"
     42 
     43 #ifndef LIBELFBITS
     44 # define LIBELFBITS 32
     45 #endif
     46 
     47 
     48 static ElfW2(LIBELFBITS,Shdr) *
     49 load_shdr_wrlock (Elf_Scn *scn)
     50 {
     51   ElfW2(LIBELFBITS,Shdr) *result;
     52 
     53   /* Read the section header table.  */
     54   Elf *elf = scn->elf;
     55   ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
     56 
     57   /* Try again, maybe the data is there now.  */
     58   result = scn->shdr.ELFW(e,LIBELFBITS);
     59   if (result != NULL)
     60     goto out;
     61 
     62   size_t shnum;
     63   if (__elf_getshdrnum_rdlock (elf, &shnum) != 0
     64       || shnum > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Shdr)))
     65     goto out;
     66   size_t size = shnum * sizeof (ElfW2(LIBELFBITS,Shdr));
     67 
     68   /* Allocate memory for the section headers.  We know the number
     69      of entries from the ELF header.  */
     70   ElfW2(LIBELFBITS,Shdr) *shdr = elf->state.ELFW(elf,LIBELFBITS).shdr =
     71     (ElfW2(LIBELFBITS,Shdr) *) malloc (size);
     72   if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
     73     {
     74       __libelf_seterrno (ELF_E_NOMEM);
     75       goto out;
     76     }
     77   elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 1;
     78 
     79   if (elf->map_address != NULL)
     80     {
     81       /* First see whether the information in the ELF header is
     82 	 valid and it does not ask for too much.  */
     83       if (unlikely (ehdr->e_shoff >= elf->maximum_size)
     84 	  || unlikely (elf->maximum_size - ehdr->e_shoff < size))
     85 	{
     86 	  /* Something is wrong.  */
     87 	  __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
     88 	  goto free_and_out;
     89 	}
     90 
     91       ElfW2(LIBELFBITS,Shdr) *notcvt;
     92 
     93       /* All the data is already mapped.  If we could use it
     94 	 directly this would already have happened.  Unless
     95 	 we allocated the memory ourselves and the ELF_F_MALLOCED
     96 	 flag is set.  */
     97       void *file_shdr = ((char *) elf->map_address
     98 			 + elf->start_offset + ehdr->e_shoff);
     99 
    100       assert ((elf->flags & ELF_F_MALLOCED)
    101 	      || ehdr->e_ident[EI_DATA] != MY_ELFDATA
    102 	      || elf->cmd == ELF_C_READ_MMAP
    103 	      || (! ALLOW_UNALIGNED
    104 		  && ((uintptr_t) file_shdr
    105 		      & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) != 0));
    106 
    107       /* Now copy the data and at the same time convert the byte order.  */
    108       if (ehdr->e_ident[EI_DATA] == MY_ELFDATA)
    109 	{
    110 	  assert ((elf->flags & ELF_F_MALLOCED)
    111 		  || elf->cmd == ELF_C_READ_MMAP
    112 		  || ! ALLOW_UNALIGNED);
    113 	  memcpy (shdr, file_shdr, size);
    114 	}
    115       else
    116 	{
    117 	  bool copy = ! (ALLOW_UNALIGNED
    118 			 || ((uintptr_t) file_shdr
    119 			     & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1))
    120 			     == 0);
    121 	  if (! copy)
    122 	    notcvt = (ElfW2(LIBELFBITS,Shdr) *)
    123 	      ((char *) elf->map_address
    124 	       + elf->start_offset + ehdr->e_shoff);
    125 	  else
    126 	    {
    127 	      notcvt = (ElfW2(LIBELFBITS,Shdr) *) malloc (size);
    128 	      if (unlikely (notcvt == NULL))
    129 		{
    130 		  __libelf_seterrno (ELF_E_NOMEM);
    131 		  goto out;
    132 		}
    133 	      memcpy (notcvt, ((char *) elf->map_address
    134 			       + elf->start_offset + ehdr->e_shoff),
    135 		      size);
    136 	    }
    137 
    138 	  for (size_t cnt = 0; cnt < shnum; ++cnt)
    139 	    {
    140 	      CONVERT_TO (shdr[cnt].sh_name, notcvt[cnt].sh_name);
    141 	      CONVERT_TO (shdr[cnt].sh_type, notcvt[cnt].sh_type);
    142 	      CONVERT_TO (shdr[cnt].sh_flags, notcvt[cnt].sh_flags);
    143 	      CONVERT_TO (shdr[cnt].sh_addr, notcvt[cnt].sh_addr);
    144 	      CONVERT_TO (shdr[cnt].sh_offset, notcvt[cnt].sh_offset);
    145 	      CONVERT_TO (shdr[cnt].sh_size, notcvt[cnt].sh_size);
    146 	      CONVERT_TO (shdr[cnt].sh_link, notcvt[cnt].sh_link);
    147 	      CONVERT_TO (shdr[cnt].sh_info, notcvt[cnt].sh_info);
    148 	      CONVERT_TO (shdr[cnt].sh_addralign,
    149 			  notcvt[cnt].sh_addralign);
    150 	      CONVERT_TO (shdr[cnt].sh_entsize, notcvt[cnt].sh_entsize);
    151 
    152 	      /* If this is a section with an extended index add a
    153 		 reference in the section which uses the extended
    154 		 index.  */
    155 	      if (shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
    156 		  && shdr[cnt].sh_link < shnum)
    157 		elf->state.ELFW(elf,LIBELFBITS).scns.data[shdr[cnt].sh_link].shndx_index
    158 		  = cnt;
    159 
    160 	      /* Set the own shndx_index field in case it has not yet
    161 		 been set.  */
    162 	      if (elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index == 0)
    163 		elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index
    164 		  = -1;
    165 	    }
    166 
    167 	  if (copy)
    168 	    free (notcvt);
    169 	}
    170     }
    171   else if (likely (elf->fildes != -1))
    172     {
    173       /* Read the header.  */
    174       ssize_t n = pread_retry (elf->fildes,
    175 			       elf->state.ELFW(elf,LIBELFBITS).shdr, size,
    176 			       elf->start_offset + ehdr->e_shoff);
    177       if (unlikely ((size_t) n != size))
    178 	{
    179 	  /* Severe problems.  We cannot read the data.  */
    180 	  __libelf_seterrno (ELF_E_READ_ERROR);
    181 	  goto free_and_out;
    182 	}
    183 
    184       /* If the byte order of the file is not the same as the one
    185 	 of the host convert the data now.  */
    186       if (ehdr->e_ident[EI_DATA] != MY_ELFDATA)
    187 	for (size_t cnt = 0; cnt < shnum; ++cnt)
    188 	  {
    189 	    CONVERT (shdr[cnt].sh_name);
    190 	    CONVERT (shdr[cnt].sh_type);
    191 	    CONVERT (shdr[cnt].sh_flags);
    192 	    CONVERT (shdr[cnt].sh_addr);
    193 	    CONVERT (shdr[cnt].sh_offset);
    194 	    CONVERT (shdr[cnt].sh_size);
    195 	    CONVERT (shdr[cnt].sh_link);
    196 	    CONVERT (shdr[cnt].sh_info);
    197 	    CONVERT (shdr[cnt].sh_addralign);
    198 	    CONVERT (shdr[cnt].sh_entsize);
    199 	  }
    200     }
    201   else
    202     {
    203       /* The file descriptor was already enabled and not all data was
    204 	 read.  Undo the allocation.  */
    205       __libelf_seterrno (ELF_E_FD_DISABLED);
    206 
    207     free_and_out:
    208       free (shdr);
    209       elf->state.ELFW(elf,LIBELFBITS).shdr = NULL;
    210       elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 0;
    211 
    212       goto out;
    213     }
    214 
    215   /* Set the pointers in the `scn's.  */
    216   for (size_t cnt = 0; cnt < shnum; ++cnt)
    217     elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shdr.ELFW(e,LIBELFBITS)
    218       = &elf->state.ELFW(elf,LIBELFBITS).shdr[cnt];
    219 
    220   result = scn->shdr.ELFW(e,LIBELFBITS);
    221   assert (result != NULL);
    222 
    223 out:
    224   return result;
    225 }
    226 
    227 static bool
    228 scn_valid (Elf_Scn *scn)
    229 {
    230   if (scn == NULL)
    231     return false;
    232 
    233   if (unlikely (scn->elf->state.elf.ehdr == NULL))
    234     {
    235       __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
    236       return false;
    237     }
    238 
    239   if (unlikely (scn->elf->class != ELFW(ELFCLASS,LIBELFBITS)))
    240     {
    241       __libelf_seterrno (ELF_E_INVALID_CLASS);
    242       return false;
    243     }
    244 
    245   return true;
    246 }
    247 
    248 ElfW2(LIBELFBITS,Shdr) *
    249 internal_function
    250 __elfw2(LIBELFBITS,getshdr_rdlock) (Elf_Scn *scn)
    251 {
    252   ElfW2(LIBELFBITS,Shdr) *result;
    253 
    254   if (!scn_valid (scn))
    255     return NULL;
    256 
    257   result = scn->shdr.ELFW(e,LIBELFBITS);
    258   if (result == NULL)
    259     {
    260       rwlock_unlock (scn->elf->lock);
    261       rwlock_wrlock (scn->elf->lock);
    262       result = scn->shdr.ELFW(e,LIBELFBITS);
    263       if (result == NULL)
    264 	result = load_shdr_wrlock (scn);
    265     }
    266 
    267   return result;
    268 }
    269 
    270 ElfW2(LIBELFBITS,Shdr) *
    271 internal_function
    272 __elfw2(LIBELFBITS,getshdr_wrlock) (Elf_Scn *scn)
    273 {
    274   ElfW2(LIBELFBITS,Shdr) *result;
    275 
    276   if (!scn_valid (scn))
    277     return NULL;
    278 
    279   result = scn->shdr.ELFW(e,LIBELFBITS);
    280   if (result == NULL)
    281     result = load_shdr_wrlock (scn);
    282 
    283   return result;
    284 }
    285 
    286 ElfW2(LIBELFBITS,Shdr) *
    287 elfw2(LIBELFBITS,getshdr) (Elf_Scn *scn)
    288 {
    289   ElfW2(LIBELFBITS,Shdr) *result;
    290 
    291   if (!scn_valid (scn))
    292     return NULL;
    293 
    294   rwlock_rdlock (scn->elf->lock);
    295   result = __elfw2(LIBELFBITS,getshdr_rdlock) (scn);
    296   rwlock_unlock (scn->elf->lock);
    297 
    298   return result;
    299 }
    300