Home | History | Annotate | Download | only in libelf
      1 /* Return the next data element from the section after possibly converting it.
      2    Copyright (C) 1998-2005, 2006, 2007 Red Hat, Inc.
      3    This file is part of Red Hat elfutils.
      4    Written by Ulrich Drepper <drepper (at) redhat.com>, 1998.
      5 
      6    Red Hat elfutils is free software; you can redistribute it and/or modify
      7    it under the terms of the GNU General Public License as published by the
      8    Free Software Foundation; version 2 of the License.
      9 
     10    Red Hat elfutils is distributed in the hope that it will be useful, but
     11    WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13    General Public License for more details.
     14 
     15    You should have received a copy of the GNU General Public License along
     16    with Red Hat elfutils; if not, write to the Free Software Foundation,
     17    Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
     18 
     19    In addition, as a special exception, Red Hat, Inc. gives You the
     20    additional right to link the code of Red Hat elfutils with code licensed
     21    under any Open Source Initiative certified open source license
     22    (http://www.opensource.org/licenses/index.php) which requires the
     23    distribution of source code with any binary distribution and to
     24    distribute linked combinations of the two.  Non-GPL Code permitted under
     25    this exception must only link to the code of Red Hat elfutils through
     26    those well defined interfaces identified in the file named EXCEPTION
     27    found in the source code files (the "Approved Interfaces").  The files
     28    of Non-GPL Code may instantiate templates or use macros or inline
     29    functions from the Approved Interfaces without causing the resulting
     30    work to be covered by the GNU General Public License.  Only Red Hat,
     31    Inc. may make changes or additions to the list of Approved Interfaces.
     32    Red Hat's grant of this exception is conditioned upon your not adding
     33    any new exceptions.  If you wish to add a new Approved Interface or
     34    exception, please contact Red Hat.  You must obey the GNU General Public
     35    License in all respects for all of the Red Hat elfutils code and other
     36    code used in conjunction with Red Hat elfutils except the Non-GPL Code
     37    covered by this exception.  If you modify this file, you may extend this
     38    exception to your version of the file, but you are not obligated to do
     39    so.  If you do not wish to provide this exception without modification,
     40    you must delete this exception statement from your version and license
     41    this file solely under the GPL without exception.
     42 
     43    Red Hat elfutils is an included package of the Open Invention Network.
     44    An included package of the Open Invention Network is a package for which
     45    Open Invention Network licensees cross-license their patents.  No patent
     46    license is granted, either expressly or impliedly, by designation as an
     47    included package.  Should you wish to participate in the Open Invention
     48    Network licensing program, please visit www.openinventionnetwork.com
     49    <http://www.openinventionnetwork.com>.  */
     50 
     51 #ifdef HAVE_CONFIG_H
     52 # include <config.h>
     53 #endif
     54 
     55 #include <errno.h>
     56 #include <stddef.h>
     57 #include <string.h>
     58 #include <unistd.h>
     59 
     60 #include "libelfP.h"
     61 #include <system.h>
     62 #include "common.h"
     63 #include "elf-knowledge.h"
     64 
     65 
     66 #define TYPEIDX(Sh_Type) \
     67   (Sh_Type >= SHT_NULL && Sh_Type < SHT_NUM				      \
     68    ? Sh_Type								      \
     69    : (Sh_Type >= SHT_GNU_HASH && Sh_Type <= SHT_HISUNW			      \
     70       ? SHT_NUM + Sh_Type - SHT_GNU_HASH				      \
     71       : 0))
     72 
     73 /* Associate section types with libelf types.  */
     74 static const Elf_Type shtype_map[EV_NUM - 1][TYPEIDX (SHT_HISUNW) + 1] =
     75   {
     76     [EV_CURRENT - 1] =
     77     {
     78       [SHT_SYMTAB] = ELF_T_SYM,
     79       [SHT_RELA] = ELF_T_RELA,
     80       [SHT_HASH] = ELF_T_WORD,
     81       [SHT_DYNAMIC] = ELF_T_DYN,
     82       [SHT_REL] = ELF_T_REL,
     83       [SHT_DYNSYM] = ELF_T_SYM,
     84       [SHT_INIT_ARRAY] = ELF_T_ADDR,
     85       [SHT_FINI_ARRAY] = ELF_T_ADDR,
     86       [SHT_PREINIT_ARRAY] = ELF_T_ADDR,
     87       [SHT_GROUP] = ELF_T_WORD,
     88       [SHT_SYMTAB_SHNDX] = ELF_T_WORD,
     89       [SHT_NOTE] = ELF_T_NHDR,
     90       [TYPEIDX (SHT_GNU_verdef)] = ELF_T_VDEF,
     91       [TYPEIDX (SHT_GNU_verneed)] = ELF_T_VNEED,
     92       [TYPEIDX (SHT_GNU_versym)] = ELF_T_HALF,
     93       [TYPEIDX (SHT_SUNW_syminfo)] = ELF_T_SYMINFO,
     94       [TYPEIDX (SHT_SUNW_move)] = ELF_T_MOVE,
     95       [TYPEIDX (SHT_GNU_LIBLIST)] = ELF_T_LIB,
     96       [TYPEIDX (SHT_GNU_HASH)] = ELF_T_GNUHASH,
     97     }
     98   };
     99 
    100 #if !ALLOW_UNALIGNED
    101 /* Associate libelf types with their internal alignment requirements.  */
    102 const uint_fast8_t __libelf_type_aligns[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] =
    103   {
    104 # define TYPE_ALIGNS(Bits)						      \
    105     {									      \
    106       [ELF_T_ADDR] = __alignof__ (ElfW2(Bits,Addr)),			      \
    107       [ELF_T_HALF] = __alignof__ (ElfW2(Bits,Half)),			      \
    108       [ELF_T_WORD] = __alignof__ (ElfW2(Bits,Word)),			      \
    109       [ELF_T_SYM] = __alignof__ (ElfW2(Bits,Sym)),			      \
    110       [ELF_T_SYMINFO] = __alignof__ (ElfW2(Bits,Syminfo)),		      \
    111       [ELF_T_REL] = __alignof__ (ElfW2(Bits,Rel)),			      \
    112       [ELF_T_RELA] = __alignof__ (ElfW2(Bits,Rela)),			      \
    113       [ELF_T_DYN] = __alignof__ (ElfW2(Bits,Dyn)),			      \
    114       [ELF_T_VDEF] = __alignof__ (ElfW2(Bits,Verdef)),			      \
    115       [ELF_T_VDAUX] = __alignof__ (ElfW2(Bits,Verdaux)),		      \
    116       [ELF_T_VNEED] = __alignof__ (ElfW2(Bits,Verneed)),		      \
    117       [ELF_T_VNAUX] = __alignof__ (ElfW2(Bits,Vernaux)),		      \
    118       [ELF_T_MOVE] = __alignof__ (ElfW2(Bits,Move)),			      \
    119       [ELF_T_LIB] = __alignof__ (ElfW2(Bits,Lib)),			      \
    120       [ELF_T_NHDR] = __alignof__ (ElfW2(Bits,Nhdr)),			      \
    121     }
    122     [EV_CURRENT - 1] =
    123     {
    124       [ELFCLASS32 - 1] = TYPE_ALIGNS (32),
    125       [ELFCLASS64 - 1] = TYPE_ALIGNS (64),
    126     }
    127 # undef TYPE_ALIGNS
    128   };
    129 #endif
    130 
    131 
    132 /* Convert the data in the current section.  */
    133 static void
    134 convert_data (Elf_Scn *scn, int version __attribute__ ((unused)), int eclass,
    135 	      int data, size_t size, Elf_Type type)
    136 {
    137   const size_t align = __libelf_type_align (eclass, type);
    138 
    139   if (data == MY_ELFDATA)
    140     {
    141       if (((((size_t) (char *) scn->rawdata_base)) & (align - 1)) == 0)
    142 	/* No need to copy, we can use the raw data.  */
    143 	scn->data_base = scn->rawdata_base;
    144       else
    145 	{
    146 	  scn->data_base = (char *) malloc (size);
    147 	  if (scn->data_base == NULL)
    148 	    {
    149 	      __libelf_seterrno (ELF_E_NOMEM);
    150 	      return;
    151 	    }
    152 
    153 	  /* The copy will be appropriately aligned for direct access.  */
    154 	  memcpy (scn->data_base, scn->rawdata_base, size);
    155 	}
    156     }
    157   else
    158     {
    159       xfct_t fp;
    160 
    161       scn->data_base = (char *) malloc (size);
    162       if (scn->data_base == NULL)
    163 	{
    164 	  __libelf_seterrno (ELF_E_NOMEM);
    165 	  return;
    166 	}
    167 
    168       /* Get the conversion function.  */
    169 #if EV_NUM != 2
    170       fp = __elf_xfctstom[version - 1][__libelf_version - 1][eclass - 1][type];
    171 #else
    172       fp = __elf_xfctstom[0][0][eclass - 1][type];
    173 #endif
    174 
    175       fp (scn->data_base, scn->rawdata_base, size, 0);
    176     }
    177 
    178   scn->data_list.data.d.d_buf = scn->data_base;
    179   scn->data_list.data.d.d_size = size;
    180   scn->data_list.data.d.d_type = type;
    181   scn->data_list.data.d.d_off = scn->rawdata.d.d_off;
    182   scn->data_list.data.d.d_align = scn->rawdata.d.d_align;
    183   scn->data_list.data.d.d_version = scn->rawdata.d.d_version;
    184 
    185   scn->data_list.data.s = scn;
    186 }
    187 
    188 
    189 /* Store the information for the raw data in the `rawdata' element.  */
    190 int
    191 internal_function
    192 __libelf_set_rawdata_wrlock (Elf_Scn *scn)
    193 {
    194   size_t offset;
    195   size_t size;
    196   size_t align;
    197   int type;
    198   Elf *elf = scn->elf;
    199 
    200   if (elf->class == ELFCLASS32)
    201     {
    202       Elf32_Shdr *shdr
    203 	= scn->shdr.e32 ?: __elf32_getshdr_wrlock (scn);
    204 
    205       if (shdr == NULL)
    206 	/* Something went terribly wrong.  */
    207 	return 1;
    208 
    209       offset = shdr->sh_offset;
    210       size = shdr->sh_size;
    211       type = shdr->sh_type;
    212       align = shdr->sh_addralign;
    213     }
    214   else
    215     {
    216       Elf64_Shdr *shdr
    217 	= scn->shdr.e64 ?: __elf64_getshdr_wrlock (scn);
    218 
    219       if (shdr == NULL)
    220 	/* Something went terribly wrong.  */
    221 	return 1;
    222 
    223       offset = shdr->sh_offset;
    224       size = shdr->sh_size;
    225       type = shdr->sh_type;
    226       align = shdr->sh_addralign;
    227     }
    228 
    229   /* If the section has no data (for whatever reason), leave the `d_buf'
    230      pointer NULL.  */
    231   if (size != 0 && type != SHT_NOBITS)
    232     {
    233       /* First a test whether the section is valid at all.  */
    234       size_t entsize;
    235 
    236       if (type == SHT_HASH)
    237 	{
    238 	  GElf_Ehdr ehdr_mem;
    239 	  GElf_Ehdr *ehdr = __gelf_getehdr_rdlock (elf, &ehdr_mem);
    240 	  entsize = SH_ENTSIZE_HASH (ehdr);
    241 	}
    242       else
    243 	{
    244 	  Elf_Type t = shtype_map[LIBELF_EV_IDX][TYPEIDX (type)];
    245 	  if (t == ELF_T_VDEF || t == ELF_T_NHDR
    246 	      || (t == ELF_T_GNUHASH && elf->class == ELFCLASS64))
    247 	    entsize = 1;
    248 	  else
    249 	    entsize = __libelf_type_sizes[LIBELF_EV_IDX][elf->class - 1][t];
    250 	}
    251 
    252       /* We assume it is an array of bytes if it is none of the structured
    253 	 sections we know of.  */
    254       if (entsize == 0)
    255 	entsize = 1;
    256 
    257       if (unlikely (size % entsize != 0))
    258 	{
    259 	  __libelf_seterrno (ELF_E_INVALID_DATA);
    260 	  return 1;
    261 	}
    262 
    263       /* We can use the mapped or loaded data if available.  */
    264       if (elf->map_address != NULL)
    265 	{
    266 	  /* First see whether the information in the section header is
    267 	     valid and it does not ask for too much.  */
    268 	  if (unlikely (offset + size > elf->maximum_size))
    269 	    {
    270 	      /* Something is wrong.  */
    271 	      __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
    272 	      return 1;
    273 	    }
    274 
    275 	  scn->rawdata_base = scn->rawdata.d.d_buf
    276 	    = (char *) elf->map_address + elf->start_offset + offset;
    277 	}
    278       else if (likely (elf->fildes != -1))
    279 	{
    280 	  /* We have to read the data from the file.  Allocate the needed
    281 	     memory.  */
    282 	  scn->rawdata_base = scn->rawdata.d.d_buf
    283 	    = (char *) malloc (size);
    284 	  if (scn->rawdata.d.d_buf == NULL)
    285 	    {
    286 	      __libelf_seterrno (ELF_E_NOMEM);
    287 	      return 1;
    288 	    }
    289 
    290 	  ssize_t n = pread_retry (elf->fildes, scn->rawdata.d.d_buf, size,
    291 				   elf->start_offset + offset);
    292 	  if (unlikely ((size_t) n != size))
    293 	    {
    294 	      /* Cannot read the data.  */
    295 	      free (scn->rawdata.d.d_buf);
    296 	      scn->rawdata_base = scn->rawdata.d.d_buf = NULL;
    297 	      __libelf_seterrno (ELF_E_READ_ERROR);
    298 	      return 1;
    299 	    }
    300 	}
    301       else
    302 	{
    303 	  /* The file descriptor is already closed, we cannot get the data
    304 	     anymore.  */
    305 	  __libelf_seterrno (ELF_E_FD_DISABLED);
    306 	  return 1;
    307 	}
    308     }
    309 
    310   scn->rawdata.d.d_size = size;
    311   /* Some broken ELF ABI for 64-bit machines use the wrong hash table
    312      entry size.  See elf-knowledge.h for more information.  */
    313   if (type == SHT_HASH && elf->class == ELFCLASS64)
    314     {
    315       GElf_Ehdr ehdr_mem;
    316       GElf_Ehdr *ehdr = __gelf_getehdr_rdlock (elf, &ehdr_mem);
    317       scn->rawdata.d.d_type
    318 	= (SH_ENTSIZE_HASH (ehdr) == 4 ? ELF_T_WORD : ELF_T_XWORD);
    319     }
    320   else
    321     scn->rawdata.d.d_type = shtype_map[LIBELF_EV_IDX][TYPEIDX (type)];
    322   scn->rawdata.d.d_off = 0;
    323   scn->rawdata.d.d_align = align;
    324   if (elf->class == ELFCLASS32
    325       || (offsetof (struct Elf, state.elf32.ehdr)
    326 	  == offsetof (struct Elf, state.elf64.ehdr)))
    327     scn->rawdata.d.d_version =
    328       elf->state.elf32.ehdr->e_ident[EI_VERSION];
    329   else
    330     scn->rawdata.d.d_version =
    331       elf->state.elf64.ehdr->e_ident[EI_VERSION];
    332 
    333   scn->rawdata.s = scn;
    334 
    335   scn->data_read = 1;
    336 
    337   /* We actually read data from the file.  At least we tried.  */
    338   scn->flags |= ELF_F_FILEDATA;
    339 
    340   return 0;
    341 }
    342 
    343 int
    344 internal_function
    345 __libelf_set_rawdata (Elf_Scn *scn)
    346 {
    347   int result;
    348 
    349   if (scn == NULL)
    350     return 1;
    351 
    352   rwlock_wrlock (scn->elf->lock);
    353   result = __libelf_set_rawdata_wrlock (scn);
    354   rwlock_unlock (scn->elf->lock);
    355 
    356   return result;
    357 }
    358 
    359 Elf_Data *
    360 internal_function
    361 __elf_getdata_rdlock (scn, data)
    362      Elf_Scn *scn;
    363      Elf_Data *data;
    364 {
    365   Elf_Data *result = NULL;
    366   Elf *elf;
    367   int locked = 0;
    368 
    369   if (scn == NULL)
    370     return NULL;
    371 
    372   if (unlikely (scn->elf->kind != ELF_K_ELF))
    373     {
    374       __libelf_seterrno (ELF_E_INVALID_HANDLE);
    375       return NULL;
    376     }
    377 
    378   /* We will need this multiple times later on.  */
    379   elf = scn->elf;
    380 
    381   /* If `data' is not NULL this means we are not addressing the initial
    382      data in the file.  But this also means this data is already read
    383      (since otherwise it is not possible to have a valid `data' pointer)
    384      and all the data structures are initialized as well.  In this case
    385      we can simply walk the list of data records.  */
    386   if (data != NULL)
    387     {
    388       Elf_Data_List *runp;
    389 
    390       /* It is not possible that if DATA is not NULL the first entry is
    391 	 returned.  But this also means that there must be a first data
    392 	 entry.  */
    393       if (scn->data_list_rear == NULL
    394 	  /* The section the reference data is for must match the section
    395 	     parameter.  */
    396 	  || unlikely (((Elf_Data_Scn *) data)->s != scn))
    397 	{
    398 	  __libelf_seterrno (ELF_E_DATA_MISMATCH);
    399 	  goto out;
    400 	}
    401 
    402       /* We start searching with the first entry.  */
    403       runp = &scn->data_list;
    404 
    405       while (1)
    406 	{
    407 	  /* If `data' does not match any known record punt.  */
    408 	  if (runp == NULL)
    409 	    {
    410 	      __libelf_seterrno (ELF_E_DATA_MISMATCH);
    411 	      goto out;
    412 	    }
    413 
    414 	  if (&runp->data.d == data)
    415 	    /* Found the entry.  */
    416 	    break;
    417 
    418 	  runp = runp->next;
    419 	}
    420 
    421       /* Return the data for the next data record.  */
    422       result = runp->next ? &runp->next->data.d : NULL;
    423       goto out;
    424     }
    425 
    426   /* If the data for this section was not yet initialized do it now.  */
    427   if (scn->data_read == 0)
    428     {
    429       /* We cannot acquire a write lock while we are holding a read
    430          lock.  Therefore give up the read lock and then get the write
    431          lock.  But this means that the data could meanwhile be
    432          modified, therefore start the tests again.  */
    433       rwlock_unlock (elf->lock);
    434       rwlock_wrlock (elf->lock);
    435       locked = 1;
    436 
    437       /* Read the data from the file.  There is always a file (or
    438 	 memory region) associated with this descriptor since
    439 	 otherwise the `data_read' flag would be set.  */
    440       if (scn->data_read == 0 && __libelf_set_rawdata_wrlock (scn) != 0)
    441 	/* Something went wrong.  The error value is already set.  */
    442 	goto out;
    443     }
    444 
    445   /* At this point we know the raw data is available.  But it might be
    446      empty in case the section has size zero (for whatever reason).
    447      Now create the converted data in case this is necessary.  */
    448   if (scn->data_list_rear == NULL)
    449     {
    450       if (scn->rawdata.d.d_buf != NULL && scn->rawdata.d.d_size > 0)
    451 	{
    452 	  if (!locked)
    453 	    {
    454 	      rwlock_unlock (elf->lock);
    455 	      rwlock_wrlock (elf->lock);
    456 	      if (scn->data_list_rear != NULL)
    457 		goto pass;
    458 	    }
    459 
    460 	  /* Convert according to the version and the type.   */
    461 	  convert_data (scn, __libelf_version, elf->class,
    462 			(elf->class == ELFCLASS32
    463 			 || (offsetof (struct Elf, state.elf32.ehdr)
    464 			     == offsetof (struct Elf, state.elf64.ehdr))
    465 			 ? elf->state.elf32.ehdr->e_ident[EI_DATA]
    466 			 : elf->state.elf64.ehdr->e_ident[EI_DATA]),
    467 			scn->rawdata.d.d_size, scn->rawdata.d.d_type);
    468 	}
    469       else
    470 	{
    471 	  /* This is an empty or NOBITS section.  There is no buffer but
    472 	     the size information etc is important.  */
    473 	  scn->data_list.data.d = scn->rawdata.d;
    474 	  scn->data_list.data.s = scn;
    475 	}
    476 
    477       scn->data_list_rear = &scn->data_list;
    478     }
    479 
    480   /* If no data is present we cannot return any.  */
    481   if (scn->data_list_rear != NULL)
    482   pass:
    483     /* Return the first data element in the list.  */
    484     result = &scn->data_list.data.d;
    485 
    486  out:
    487   return result;
    488 }
    489 
    490 Elf_Data *
    491 elf_getdata (scn, data)
    492      Elf_Scn *scn;
    493      Elf_Data *data;
    494 {
    495   Elf_Data *result;
    496 
    497   if (scn == NULL)
    498     return NULL;
    499 
    500   rwlock_rdlock (scn->elf->lock);
    501   result = __elf_getdata_rdlock (scn, data);
    502   rwlock_unlock (scn->elf->lock);
    503 
    504   return result;
    505 }
    506 INTDEF(elf_getdata)
    507