Home | History | Annotate | Download | only in libelf
      1 /* Return symbol table of archive.
      2    Copyright (C) 1998, 1999, 2000, 2002, 2005 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 <assert.h>
     56 #include <byteswap.h>
     57 #include <endian.h>
     58 #include <errno.h>
     59 #include <stdint.h>
     60 #include <stdlib.h>
     61 #include <string.h>
     62 #include <unistd.h>
     63 
     64 #include <system.h>
     65 #include <dl-hash.h>
     66 #include "libelfP.h"
     67 
     68 
     69 Elf_Arsym *
     70 elf_getarsym (elf, ptr)
     71      Elf *elf;
     72      size_t *ptr;
     73 {
     74   if (elf->kind != ELF_K_AR)
     75     {
     76       /* This is no archive.  */
     77       __libelf_seterrno (ELF_E_NO_ARCHIVE);
     78       return NULL;
     79     }
     80 
     81   if (ptr != NULL)
     82     /* In case of an error or when we know the value store the expected
     83        value now.  Doing this allows us easier exits in an error case.  */
     84     *ptr = elf->state.ar.ar_sym_num;
     85 
     86   if (elf->state.ar.ar_sym == (Elf_Arsym *) -1l)
     87     {
     88       /* There is no index.  */
     89       __libelf_seterrno (ELF_E_NO_INDEX);
     90       return NULL;
     91     }
     92 
     93   Elf_Arsym *result = elf->state.ar.ar_sym;
     94   if (result == NULL)
     95     {
     96       /* We have not yet read the index.  */
     97       rwlock_wrlock (elf->lock);
     98 
     99       /* In case we find no index remember this for the next call.  */
    100       elf->state.ar.ar_sym = (Elf_Arsym *) -1l;
    101 
    102       struct ar_hdr *index_hdr;
    103       if (elf->map_address == NULL)
    104 	{
    105 	  /* We must read index from the file.  */
    106 	  assert (elf->fildes != -1);
    107 	  if (pread_retry (elf->fildes, &elf->state.ar.ar_hdr,
    108 			   sizeof (struct ar_hdr), elf->start_offset + SARMAG)
    109 	      != sizeof (struct ar_hdr))
    110 	    {
    111 	      /* It is not possible to read the index.  Maybe it does not
    112 		 exist.  */
    113 	      __libelf_seterrno (ELF_E_READ_ERROR);
    114 	      goto out;
    115 	    }
    116 
    117 	  index_hdr = &elf->state.ar.ar_hdr;
    118 	}
    119       else
    120 	{
    121 	  if (SARMAG + sizeof (struct ar_hdr) > elf->maximum_size)
    122 	    {
    123 	      /* There is no room for the full archive.  */
    124 	      __libelf_seterrno (ELF_E_NO_INDEX);
    125 	      goto out;
    126 	    }
    127 
    128 	  index_hdr = (struct ar_hdr *) (elf->map_address
    129 					 + elf->start_offset + SARMAG);
    130 	}
    131 
    132       /* Now test whether this really is an archive.  */
    133       if (memcmp (index_hdr->ar_fmag, ARFMAG, 2) != 0)
    134 	{
    135 	  /* Invalid magic bytes.  */
    136 	  __libelf_seterrno (ELF_E_ARCHIVE_FMAG);
    137 	  goto out;
    138 	}
    139 
    140       /* Now test whether this is the index.  It is denoted by the
    141 	 name being "/ ".
    142 	 XXX This is not entirely true.  There are some more forms.
    143 	 Which of them shall we handle?  */
    144       if (memcmp (index_hdr->ar_name, "/               ", 16) != 0)
    145 	{
    146 	  /* If the index is not the first entry, there is no index.
    147 
    148 	     XXX Is this true?  */
    149 	  __libelf_seterrno (ELF_E_NO_INDEX);
    150 	  goto out;
    151 	}
    152 
    153       /* We have an archive.  The first word in there is the number of
    154 	 entries in the table.  */
    155       uint32_t n;
    156       if (elf->map_address == NULL)
    157 	{
    158 	  if (pread_retry (elf->fildes, &n, sizeof (n),
    159 			   elf->start_offset + SARMAG + sizeof (struct ar_hdr))
    160 	      != sizeof (n))
    161 	    {
    162 	      /* Cannot read the number of entries.  */
    163 	      __libelf_seterrno (ELF_E_NO_INDEX);
    164 	      goto out;
    165 	    }
    166 	}
    167       else
    168 	n = *(uint32_t *) (elf->map_address + elf->start_offset
    169 			   + SARMAG + sizeof (struct ar_hdr));
    170 
    171       if (__BYTE_ORDER == __LITTLE_ENDIAN)
    172 	n = bswap_32 (n);
    173 
    174       /* Now we can perform some first tests on whether all the data
    175 	 needed for the index is available.  */
    176       char tmpbuf[17];
    177       memcpy (tmpbuf, index_hdr->ar_size, 10);
    178       tmpbuf[10] = '\0';
    179       size_t index_size = atol (tmpbuf);
    180 
    181       if (SARMAG + sizeof (struct ar_hdr) + index_size > elf->maximum_size
    182 	  || n * sizeof (uint32_t) > index_size)
    183 	{
    184 	  /* This index table cannot be right since it does not fit into
    185 	     the file.  */
    186 	  __libelf_seterrno (ELF_E_NO_INDEX);
    187 	  goto out;
    188 	}
    189 
    190       /* Now we can allocate the arrays needed to store the index.  */
    191       size_t ar_sym_len = (n + 1) * sizeof (Elf_Arsym);
    192       elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len);
    193       if (elf->state.ar.ar_sym != NULL)
    194 	{
    195 	  uint32_t *file_data;
    196 	  char *str_data;
    197 
    198 	  if (elf->map_address == NULL)
    199 	    {
    200 	      file_data = (uint32_t *) alloca (n * sizeof (uint32_t));
    201 
    202 	      ar_sym_len += index_size - n * sizeof (uint32_t);
    203 	      Elf_Arsym *newp = (Elf_Arsym *) realloc (elf->state.ar.ar_sym,
    204 						       ar_sym_len);
    205 	      if (newp == NULL)
    206 		{
    207 		  free (elf->state.ar.ar_sym);
    208 		  elf->state.ar.ar_sym = NULL;
    209 		  __libelf_seterrno (ELF_E_NOMEM);
    210 		  goto out;
    211 		}
    212 	      elf->state.ar.ar_sym = newp;
    213 
    214 	      char *new_str = (char *) (elf->state.ar.ar_sym + n + 1);
    215 
    216 	      /* Now read the data from the file.  */
    217 	      if ((size_t) pread_retry (elf->fildes, file_data,
    218 					n * sizeof (uint32_t),
    219 					elf->start_offset + SARMAG
    220 					+ sizeof (struct ar_hdr)
    221 					+ sizeof (uint32_t))
    222 		  != n * sizeof (uint32_t)
    223 		  || ((size_t) pread_retry (elf->fildes, new_str,
    224 					    index_size - n * sizeof (uint32_t),
    225 					    elf->start_offset
    226 					    + SARMAG + sizeof (struct ar_hdr)
    227 					    + (n + 1) * sizeof (uint32_t))
    228 		      != index_size - n * sizeof (uint32_t)))
    229 		{
    230 		  /* We were not able to read the data.  */
    231 		  free (elf->state.ar.ar_sym);
    232 		  elf->state.ar.ar_sym = NULL;
    233 		  __libelf_seterrno (ELF_E_NO_INDEX);
    234 		  goto out;
    235 		}
    236 
    237 	      str_data = (char *) new_str;
    238 	    }
    239 	  else
    240 	    {
    241 	      file_data = (uint32_t *) (elf->map_address + elf->start_offset
    242 					+ SARMAG + sizeof (struct ar_hdr)
    243 					+ sizeof (uint32_t));
    244 	      str_data = (char *) &file_data[n];
    245 	    }
    246 
    247 	  /* Now we can build the data structure.  */
    248 	  Elf_Arsym *arsym = elf->state.ar.ar_sym;
    249 	  for (size_t cnt = 0; cnt < n; ++cnt)
    250 	    {
    251 	      arsym[cnt].as_name = str_data;
    252 	      if (__BYTE_ORDER == __LITTLE_ENDIAN)
    253 		arsym[cnt].as_off = bswap_32 (file_data[cnt]);
    254 	      else
    255 		arsym[cnt].as_off = file_data[cnt];
    256 	      arsym[cnt].as_hash = _dl_elf_hash (str_data);
    257 	      str_data = rawmemchr (str_data, '\0') + 1;
    258 	    }
    259 	  /* At the end a special entry.  */
    260 	  arsym[n].as_name = NULL;
    261 	  arsym[n].as_off = 0;
    262 	  arsym[n].as_hash = ~0UL;
    263 
    264 	  /* Tell the caller how many entries we have.  */
    265 	  elf->state.ar.ar_sym_num = n + 1;
    266 	}
    267 
    268       result = elf->state.ar.ar_sym;
    269 
    270     out:
    271       rwlock_unlock (elf->lock);
    272     }
    273 
    274   if (ptr != NULL)
    275     *ptr = elf->state.ar.ar_sym_num;
    276 
    277   return result;
    278 }
    279