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@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
69Elf_Arsym *
70elf_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