Home | History | Annotate | Download | only in libelf
      1 /* Return section header.
      2    Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
      3    Written by Ulrich Drepper <drepper (at) redhat.com>, 1998.
      4 
      5    This program is free software; you can redistribute it and/or modify
      6    it under the terms of the GNU General Public License as published by
      7    the Free Software Foundation, version 2.
      8 
      9    This program is distributed in the hope that it will be useful,
     10    but WITHOUT ANY WARRANTY; without even the implied warranty of
     11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12    GNU General Public License for more details.
     13 
     14    You should have received a copy of the GNU General Public License
     15    along with this program; if not, write to the Free Software Foundation,
     16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
     17 
     18 #ifdef HAVE_CONFIG_H
     19 # include <config.h>
     20 #endif
     21 
     22 #include <assert.h>
     23 #include <unistd.h>
     24 
     25 #include "libelfP.h"
     26 #include "common.h"
     27 
     28 #ifndef LIBELFBITS
     29 # define LIBELFBITS 32
     30 #endif
     31 
     32 
     33 ElfW2(LIBELFBITS,Shdr) *
     34 elfw2(LIBELFBITS,getshdr) (scn)
     35      Elf_Scn *scn;
     36 {
     37   ElfW2(LIBELFBITS,Shdr) *result;
     38 
     39   if (scn == NULL)
     40     return NULL;
     41 
     42   if (unlikely (scn->elf->state.elf.ehdr == NULL))
     43     {
     44       __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
     45       return NULL;
     46     }
     47 
     48   if (unlikely (scn->elf->class != ELFW(ELFCLASS,LIBELFBITS)))
     49     {
     50       __libelf_seterrno (ELF_E_INVALID_CLASS);
     51       return NULL;
     52     }
     53 
     54   result = scn->shdr.ELFW(e,LIBELFBITS);
     55   if (result == NULL)
     56     {
     57       /* Read the section header table.  */
     58       Elf *elf = scn->elf;
     59       ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
     60       size_t shnum;
     61       ElfW2(LIBELFBITS,Shdr) *shdr;
     62       size_t size;
     63       size_t cnt;
     64 
     65       rwlock_wrlock (elf->lock);
     66 
     67       /* Try again, maybe the data is there now.  */
     68       result = scn->shdr.ELFW(e,LIBELFBITS);
     69       if (result != NULL)
     70 	goto out;
     71 
     72       if (INTUSE (elf_getshnum) (elf, &shnum) != 0)
     73 	goto out;
     74       size = shnum * sizeof (ElfW2(LIBELFBITS,Shdr));
     75 
     76       /* Allocate memory for the program headers.  We know the number
     77 	 of entries from the ELF header.  */
     78       shdr = elf->state.ELFW(elf,LIBELFBITS).shdr =
     79 	(ElfW2(LIBELFBITS,Shdr) *) malloc (size);
     80       if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
     81 	{
     82 	  __libelf_seterrno (ELF_E_NOMEM);
     83 	  goto out;
     84 	}
     85       elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 1;
     86 
     87       if (elf->map_address != NULL)
     88 	{
     89 	  ElfW2(LIBELFBITS,Shdr) *notcvt;
     90 
     91 	  /* All the data is already mapped.  If we could use it
     92 	     directly this would already have happened.  */
     93 	  assert (ehdr->e_ident[EI_DATA] != MY_ELFDATA
     94 		  || (! ALLOW_UNALIGNED
     95 		      && (ehdr->e_shoff
     96 			  & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) != 0));
     97 
     98 	  /* Now copy the data and at the same time convert the byte
     99 	     order.  */
    100 	  if (ALLOW_UNALIGNED
    101 	      || (ehdr->e_shoff
    102 		  & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) == 0)
    103 	    notcvt = (ElfW2(LIBELFBITS,Shdr) *)
    104 	      ((char *) elf->map_address
    105 	       + elf->start_offset + ehdr->e_shoff);
    106 	  else
    107 	    {
    108 	      notcvt = (ElfW2(LIBELFBITS,Shdr) *) alloca (size);
    109 	      memcpy (notcvt, ((char *) elf->map_address
    110 			       + elf->start_offset + ehdr->e_shoff),
    111 		      size);
    112 	    }
    113 
    114 	  for (cnt = 0; cnt < shnum; ++cnt)
    115 	    {
    116 	      CONVERT_TO (shdr[cnt].sh_name, notcvt[cnt].sh_name);
    117 	      CONVERT_TO (shdr[cnt].sh_type, notcvt[cnt].sh_type);
    118 	      CONVERT_TO (shdr[cnt].sh_flags, notcvt[cnt].sh_flags);
    119 	      CONVERT_TO (shdr[cnt].sh_addr, notcvt[cnt].sh_addr);
    120 	      CONVERT_TO (shdr[cnt].sh_offset, notcvt[cnt].sh_offset);
    121 	      CONVERT_TO (shdr[cnt].sh_size, notcvt[cnt].sh_size);
    122 	      CONVERT_TO (shdr[cnt].sh_link, notcvt[cnt].sh_link);
    123 	      CONVERT_TO (shdr[cnt].sh_info, notcvt[cnt].sh_info);
    124 	      CONVERT_TO (shdr[cnt].sh_addralign, notcvt[cnt].sh_addralign);
    125 	      CONVERT_TO (shdr[cnt].sh_entsize, notcvt[cnt].sh_entsize);
    126 	    }
    127 	}
    128       else if (elf->fildes != -1)
    129 	{
    130 	  /* Read the header.  */
    131 	  if ((size_t) pread (elf->fildes,
    132 			      elf->state.ELFW(elf,LIBELFBITS).shdr, size,
    133 			      elf->start_offset + ehdr->e_shoff) != size)
    134 	    {
    135 	      /* Severe problems.  We cannot read the data.  */
    136 	      __libelf_seterrno (ELF_E_READ_ERROR);
    137 	      goto free_and_out;
    138 	    }
    139 
    140 	  /* If the byte order of the file is not the same as the one
    141 	     of the host convert the data now.  */
    142 	  if (ehdr->e_ident[EI_DATA] != MY_ELFDATA)
    143 	    for (cnt = 0; cnt < shnum; ++cnt)
    144 	      {
    145 		CONVERT (shdr[cnt].sh_name);
    146 		CONVERT (shdr[cnt].sh_type);
    147 		CONVERT (shdr[cnt].sh_flags);
    148 		CONVERT (shdr[cnt].sh_addr);
    149 		CONVERT (shdr[cnt].sh_offset);
    150 		CONVERT (shdr[cnt].sh_size);
    151 		CONVERT (shdr[cnt].sh_link);
    152 		CONVERT (shdr[cnt].sh_info);
    153 		CONVERT (shdr[cnt].sh_addralign);
    154 		CONVERT (shdr[cnt].sh_entsize);
    155 	      }
    156 	}
    157       else
    158 	{
    159 	  /* The file descriptor was already enabled and not all data was
    160 	     read.  Undo the allocation.  */
    161 	  __libelf_seterrno (ELF_E_FD_DISABLED);
    162 
    163 	free_and_out:
    164 	  free (shdr);
    165 	  elf->state.ELFW(elf,LIBELFBITS).shdr = NULL;
    166 	  elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 0;
    167 
    168 	  goto out;
    169 	}
    170 
    171       /* Set the pointers in the `scn's.  */
    172       for (cnt = 0; cnt < shnum; ++cnt)
    173 	elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shdr.ELFW(e,LIBELFBITS)
    174 	  = &elf->state.ELFW(elf,LIBELFBITS).shdr[cnt];
    175 
    176       result = scn->shdr.ELFW(e,LIBELFBITS);
    177       assert (result != NULL);
    178 
    179     out:
    180       rwlock_unlock (elf->lock);
    181     }
    182 
    183   return result;
    184 }
    185 INTDEF(elfw2(LIBELFBITS,getshdr))
    186