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@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
49static int
50read_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
76Elf_Arsym *
77elf_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