Home | History | Annotate | Download | only in libelf
      1 /* Return symbol table of archive.
      2    Copyright (C) 1998-2000, 2002, 2005, 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 <byteswap.h>
     36 #include <endian.h>
     37 #include <errno.h>
     38 #include <stdbool.h>
     39 #include <stdint.h>
     40 #include <stdlib.h>
     41 #include <string.h>
     42 #include <unistd.h>
     43 
     44 #include <system.h>
     45 #include <dl-hash.h>
     46 #include "libelfP.h"
     47 
     48 
     49 static int
     50 read_number_entries (uint64_t *nump, Elf *elf, size_t *offp, bool index64_p)
     51 {
     52   union u
     53   {
     54     uint64_t ret64;
     55     uint32_t ret32;
     56   } u;
     57 
     58   size_t w = index64_p ? 8 : 4;
     59   if (elf->map_address != NULL)
     60     /* Use memcpy instead of pointer dereference so as not to assume the
     61        field is naturally aligned within the file.  */
     62     memcpy (&u, elf->map_address + *offp, sizeof u);
     63   else if ((size_t) pread_retry (elf->fildes, &u, w, *offp) != w)
     64     return -1;
     65 
     66   *offp += w;
     67 
     68   if (__BYTE_ORDER == __LITTLE_ENDIAN)
     69     *nump = index64_p ? bswap_64 (u.ret64) : bswap_32 (u.ret32);
     70   else
     71     *nump = index64_p ? u.ret64 : u.ret32;
     72 
     73   return 0;
     74 }
     75 
     76 Elf_Arsym *
     77 elf_getarsym (Elf *elf, size_t *ptr)
     78 {
     79   if (elf->kind != ELF_K_AR)
     80     {
     81       /* This is no archive.  */
     82       __libelf_seterrno (ELF_E_NO_ARCHIVE);
     83       return NULL;
     84     }
     85 
     86   if (ptr != NULL)
     87     /* In case of an error or when we know the value store the expected
     88        value now.  Doing this allows us easier exits in an error case.  */
     89     *ptr = elf->state.ar.ar_sym_num;
     90 
     91   if (elf->state.ar.ar_sym == (Elf_Arsym *) -1l)
     92     {
     93       /* There is no index.  */
     94       __libelf_seterrno (ELF_E_NO_INDEX);
     95       return NULL;
     96     }
     97 
     98   Elf_Arsym *result = elf->state.ar.ar_sym;
     99   if (result == NULL)
    100     {
    101       /* We have not yet read the index.  */
    102       rwlock_wrlock (elf->lock);
    103 
    104       /* In case we find no index remember this for the next call.  */
    105       elf->state.ar.ar_sym = (Elf_Arsym *) -1l;
    106 
    107       /* We might have to allocate some temporary data for reading.  */
    108       void *temp_data = NULL;
    109 
    110       struct ar_hdr *index_hdr;
    111       if (elf->map_address == NULL)
    112 	{
    113 	  /* We must read index from the file.  */
    114 	  assert (elf->fildes != -1);
    115 	  if (pread_retry (elf->fildes, &elf->state.ar.ar_hdr,
    116 			   sizeof (struct ar_hdr), elf->start_offset + SARMAG)
    117 	      != sizeof (struct ar_hdr))
    118 	    {
    119 	      /* It is not possible to read the index.  Maybe it does not
    120 		 exist.  */
    121 	      __libelf_seterrno (ELF_E_READ_ERROR);
    122 	      goto out;
    123 	    }
    124 
    125 	  index_hdr = &elf->state.ar.ar_hdr;
    126 	}
    127       else
    128 	{
    129 	  if (SARMAG + sizeof (struct ar_hdr) > elf->maximum_size)
    130 	    {
    131 	      /* There is no room for the full archive.  */
    132 	      __libelf_seterrno (ELF_E_NO_INDEX);
    133 	      goto out;
    134 	    }
    135 
    136 	  index_hdr = (struct ar_hdr *) (elf->map_address
    137 					 + elf->start_offset + SARMAG);
    138 	}
    139 
    140       /* Now test whether this really is an archive.  */
    141       if (memcmp (index_hdr->ar_fmag, ARFMAG, 2) != 0)
    142 	{
    143 	  /* Invalid magic bytes.  */
    144 	  __libelf_seterrno (ELF_E_ARCHIVE_FMAG);
    145 	  goto out;
    146 	}
    147 
    148       bool index64_p;
    149       /* Now test whether this is the index.  If the name is "/", this
    150 	 is 32-bit index, if it's "/SYM64/", it's 64-bit index.
    151 
    152 	 XXX This is not entirely true.  There are some more forms.
    153 	 Which of them shall we handle?  */
    154       if (memcmp (index_hdr->ar_name, "/               ", 16) == 0)
    155 	index64_p = false;
    156       else if (memcmp (index_hdr->ar_name, "/SYM64/         ", 16) == 0)
    157 	index64_p = true;
    158       else
    159 	{
    160 	  /* If the index is not the first entry, there is no index.
    161 
    162 	     XXX Is this true?  */
    163 	  __libelf_seterrno (ELF_E_NO_INDEX);
    164 	  goto out;
    165 	}
    166       int w = index64_p ? 8 : 4;
    167 
    168       /* We have an archive.  The first word in there is the number of
    169 	 entries in the table.  */
    170       uint64_t n;
    171       size_t off = elf->start_offset + SARMAG + sizeof (struct ar_hdr);
    172       if (read_number_entries (&n, elf, &off, index64_p) < 0)
    173 	{
    174 	  /* Cannot read the number of entries.  */
    175 	  __libelf_seterrno (ELF_E_NO_INDEX);
    176 	  goto out;
    177 	}
    178 
    179       /* Now we can perform some first tests on whether all the data
    180 	 needed for the index is available.  */
    181       char tmpbuf[17];
    182       memcpy (tmpbuf, index_hdr->ar_size, 10);
    183       tmpbuf[10] = '\0';
    184       size_t index_size = atol (tmpbuf);
    185 
    186       if (index_size > elf->maximum_size
    187 	  || elf->maximum_size - index_size < SARMAG + sizeof (struct ar_hdr)
    188 #if SIZE_MAX <= 4294967295U
    189 	  || n >= SIZE_MAX / sizeof (Elf_Arsym)
    190 #endif
    191 	  || n > index_size / w)
    192 	{
    193 	  /* This index table cannot be right since it does not fit into
    194 	     the file.  */
    195 	  __libelf_seterrno (ELF_E_NO_INDEX);
    196 	  goto out;
    197 	}
    198 
    199       /* Now we can allocate the arrays needed to store the index.  */
    200       size_t ar_sym_len = (n + 1) * sizeof (Elf_Arsym);
    201       elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len);
    202       if (elf->state.ar.ar_sym != NULL)
    203 	{
    204 	  void *file_data; /* unit32_t[n] or uint64_t[n] */
    205 	  char *str_data;
    206 	  size_t sz = n * w;
    207 
    208 	  if (elf->map_address == NULL)
    209 	    {
    210 	      temp_data = malloc (sz);
    211 	      if (unlikely (temp_data == NULL))
    212 		{
    213 		  __libelf_seterrno (ELF_E_NOMEM);
    214 		  goto out;
    215 		}
    216 	      file_data = temp_data;
    217 
    218 	      ar_sym_len += index_size - n * w;
    219 	      Elf_Arsym *newp = (Elf_Arsym *) realloc (elf->state.ar.ar_sym,
    220 						       ar_sym_len);
    221 	      if (newp == NULL)
    222 		{
    223 		  free (elf->state.ar.ar_sym);
    224 		  elf->state.ar.ar_sym = NULL;
    225 		  __libelf_seterrno (ELF_E_NOMEM);
    226 		  goto out;
    227 		}
    228 	      elf->state.ar.ar_sym = newp;
    229 
    230 	      char *new_str = (char *) (elf->state.ar.ar_sym + n + 1);
    231 
    232 	      /* Now read the data from the file.  */
    233 	      if ((size_t) pread_retry (elf->fildes, file_data, sz, off) != sz
    234 		  || ((size_t) pread_retry (elf->fildes, new_str,
    235 					    index_size - sz, off + sz)
    236 		      != index_size - sz))
    237 		{
    238 		  /* We were not able to read the data.  */
    239 		  free (elf->state.ar.ar_sym);
    240 		  elf->state.ar.ar_sym = NULL;
    241 		  __libelf_seterrno (ELF_E_NO_INDEX);
    242 		  goto out;
    243 		}
    244 
    245 	      str_data = (char *) new_str;
    246 	    }
    247 	  else
    248 	    {
    249 	      file_data = (void *) (elf->map_address + off);
    250 	      if (!ALLOW_UNALIGNED
    251 		  && ((uintptr_t) file_data & -(uintptr_t) n) != 0)
    252 		{
    253 		  temp_data = malloc (sz);
    254 		  if (unlikely (temp_data == NULL))
    255 		    {
    256 		      __libelf_seterrno (ELF_E_NOMEM);
    257 		      goto out;
    258 		    }
    259 		  file_data = memcpy (temp_data, elf->map_address + off, sz);
    260 		}
    261 	      str_data = (char *) (elf->map_address + off + sz);
    262 	    }
    263 
    264 	  /* Now we can build the data structure.  */
    265 	  Elf_Arsym *arsym = elf->state.ar.ar_sym;
    266 	  uint64_t (*u64)[n] = file_data;
    267 	  uint32_t (*u32)[n] = file_data;
    268 	  for (size_t cnt = 0; cnt < n; ++cnt)
    269 	    {
    270 	      arsym[cnt].as_name = str_data;
    271 	      if (index64_p)
    272 		{
    273 		  uint64_t tmp = (*u64)[cnt];
    274 		  if (__BYTE_ORDER == __LITTLE_ENDIAN)
    275 		    tmp = bswap_64 (tmp);
    276 
    277 		  arsym[cnt].as_off = tmp;
    278 
    279 		  /* Check whether 64-bit offset fits into 32-bit
    280 		     size_t.  */
    281 		  if (sizeof (arsym[cnt].as_off) < 8
    282 		      && arsym[cnt].as_off != tmp)
    283 		    {
    284 		      if (elf->map_address == NULL)
    285 			{
    286 			  free (elf->state.ar.ar_sym);
    287 			  elf->state.ar.ar_sym = NULL;
    288 			}
    289 
    290 		      __libelf_seterrno (ELF_E_RANGE);
    291 		      goto out;
    292 		    }
    293 		}
    294 	      else if (__BYTE_ORDER == __LITTLE_ENDIAN)
    295 		arsym[cnt].as_off = bswap_32 ((*u32)[cnt]);
    296 	      else
    297 		arsym[cnt].as_off = (*u32)[cnt];
    298 
    299 	      arsym[cnt].as_hash = _dl_elf_hash (str_data);
    300 	      str_data = rawmemchr (str_data, '\0') + 1;
    301 	    }
    302 
    303 	  /* At the end a special entry.  */
    304 	  arsym[n].as_name = NULL;
    305 	  arsym[n].as_off = 0;
    306 	  arsym[n].as_hash = ~0UL;
    307 
    308 	  /* Tell the caller how many entries we have.  */
    309 	  elf->state.ar.ar_sym_num = n + 1;
    310 	}
    311 
    312       result = elf->state.ar.ar_sym;
    313 
    314     out:
    315       free (temp_data);
    316       rwlock_unlock (elf->lock);
    317     }
    318 
    319   if (ptr != NULL)
    320     *ptr = elf->state.ar.ar_sym_num;
    321 
    322   return result;
    323 }
    324