1/* Return symbol table of archive.
2   Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc.
3   Written by Ulrich Drepper <drepper@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
34Elf_Arsym *
35elf_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