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