Imported Upstream version 0.155
[platform/upstream/elfutils.git] / libelf / elf_getarsym.c
1 /* Return symbol table of archive.
2    Copyright (C) 1998-2000, 2002, 2005, 2012 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
49 static int
50 read_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     u = *(union u *) (elf->map_address + *offp);
61   else if ((size_t) pread_retry (elf->fildes, &u, w, *offp) != w)
62     return -1;
63
64   *offp += w;
65
66   if (__BYTE_ORDER == __LITTLE_ENDIAN)
67     *nump = index64_p ? bswap_64 (u.ret64) : bswap_32 (u.ret32);
68   else
69     *nump = index64_p ? u.ret64 : u.ret32;
70
71   return 0;
72 }
73
74 Elf_Arsym *
75 elf_getarsym (elf, ptr)
76      Elf *elf;
77      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       struct ar_hdr *index_hdr;
108       if (elf->map_address == NULL)
109         {
110           /* We must read index from the file.  */
111           assert (elf->fildes != -1);
112           if (pread_retry (elf->fildes, &elf->state.ar.ar_hdr,
113                            sizeof (struct ar_hdr), elf->start_offset + SARMAG)
114               != sizeof (struct ar_hdr))
115             {
116               /* It is not possible to read the index.  Maybe it does not
117                  exist.  */
118               __libelf_seterrno (ELF_E_READ_ERROR);
119               goto out;
120             }
121
122           index_hdr = &elf->state.ar.ar_hdr;
123         }
124       else
125         {
126           if (SARMAG + sizeof (struct ar_hdr) > elf->maximum_size)
127             {
128               /* There is no room for the full archive.  */
129               __libelf_seterrno (ELF_E_NO_INDEX);
130               goto out;
131             }
132
133           index_hdr = (struct ar_hdr *) (elf->map_address
134                                          + elf->start_offset + SARMAG);
135         }
136
137       /* Now test whether this really is an archive.  */
138       if (memcmp (index_hdr->ar_fmag, ARFMAG, 2) != 0)
139         {
140           /* Invalid magic bytes.  */
141           __libelf_seterrno (ELF_E_ARCHIVE_FMAG);
142           goto out;
143         }
144
145       bool index64_p;
146       /* Now test whether this is the index.  If the name is "/", this
147          is 32-bit index, if it's "/SYM64/", it's 64-bit index.
148
149          XXX This is not entirely true.  There are some more forms.
150          Which of them shall we handle?  */
151       if (memcmp (index_hdr->ar_name, "/               ", 16) == 0)
152         index64_p = false;
153       else if (memcmp (index_hdr->ar_name, "/SYM64/         ", 16) == 0)
154         index64_p = true;
155       else
156         {
157           /* If the index is not the first entry, there is no index.
158
159              XXX Is this true?  */
160           __libelf_seterrno (ELF_E_NO_INDEX);
161           goto out;
162         }
163       int w = index64_p ? 8 : 4;
164
165       /* We have an archive.  The first word in there is the number of
166          entries in the table.  */
167       uint64_t n;
168       size_t off = elf->start_offset + SARMAG + sizeof (struct ar_hdr);
169       if (read_number_entries (&n, elf, &off, index64_p) < 0)
170         {
171           /* Cannot read the number of entries.  */
172           __libelf_seterrno (ELF_E_NO_INDEX);
173           goto out;
174         }
175
176       /* Now we can perform some first tests on whether all the data
177          needed for the index is available.  */
178       char tmpbuf[17];
179       memcpy (tmpbuf, index_hdr->ar_size, 10);
180       tmpbuf[10] = '\0';
181       size_t index_size = atol (tmpbuf);
182
183       if (SARMAG + sizeof (struct ar_hdr) + index_size > elf->maximum_size
184           || n * w > index_size)
185         {
186           /* This index table cannot be right since it does not fit into
187              the file.  */
188           __libelf_seterrno (ELF_E_NO_INDEX);
189           goto out;
190         }
191
192       /* Now we can allocate the arrays needed to store the index.  */
193       size_t ar_sym_len = (n + 1) * sizeof (Elf_Arsym);
194       elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len);
195       if (elf->state.ar.ar_sym != NULL)
196         {
197           union
198           {
199             uint32_t u32[n];
200             uint64_t u64[n];
201           } *file_data;
202           char *str_data;
203           size_t sz = n * w;
204
205           if (elf->map_address == NULL)
206             {
207               file_data = alloca (sz);
208
209               ar_sym_len += index_size - n * w;
210               Elf_Arsym *newp = (Elf_Arsym *) realloc (elf->state.ar.ar_sym,
211                                                        ar_sym_len);
212               if (newp == NULL)
213                 {
214                   free (elf->state.ar.ar_sym);
215                   elf->state.ar.ar_sym = NULL;
216                   __libelf_seterrno (ELF_E_NOMEM);
217                   goto out;
218                 }
219               elf->state.ar.ar_sym = newp;
220
221               char *new_str = (char *) (elf->state.ar.ar_sym + n + 1);
222
223               /* Now read the data from the file.  */
224               if ((size_t) pread_retry (elf->fildes, file_data, sz, off) != sz
225                   || ((size_t) pread_retry (elf->fildes, new_str,
226                                             index_size - sz, off + sz)
227                       != index_size - sz))
228                 {
229                   /* We were not able to read the data.  */
230                   free (elf->state.ar.ar_sym);
231                   elf->state.ar.ar_sym = NULL;
232                   __libelf_seterrno (ELF_E_NO_INDEX);
233                   goto out;
234                 }
235
236               str_data = (char *) new_str;
237             }
238           else
239             {
240               file_data = (void *) (elf->map_address + off);
241               str_data = (char *) (elf->map_address + off + sz);
242             }
243
244           /* Now we can build the data structure.  */
245           Elf_Arsym *arsym = elf->state.ar.ar_sym;
246           for (size_t cnt = 0; cnt < n; ++cnt)
247             {
248               arsym[cnt].as_name = str_data;
249               if (index64_p)
250                 {
251                   uint64_t tmp = file_data->u64[cnt];
252                   if (__BYTE_ORDER == __LITTLE_ENDIAN)
253                     tmp = bswap_64 (tmp);
254
255                   arsym[cnt].as_off = tmp;
256
257                   /* Check whether 64-bit offset fits into 32-bit
258                      size_t.  */
259                   if (sizeof (arsym[cnt].as_off) < 8
260                       && arsym[cnt].as_off != tmp)
261                     {
262                       if (elf->map_address == NULL)
263                         {
264                           free (elf->state.ar.ar_sym);
265                           elf->state.ar.ar_sym = NULL;
266                         }
267
268                       __libelf_seterrno (ELF_E_RANGE);
269                       goto out;
270                     }
271                 }
272               else if (__BYTE_ORDER == __LITTLE_ENDIAN)
273                 arsym[cnt].as_off = bswap_32 (file_data->u32[cnt]);
274               else
275                 arsym[cnt].as_off = file_data->u32[cnt];
276
277               arsym[cnt].as_hash = _dl_elf_hash (str_data);
278               str_data = rawmemchr (str_data, '\0') + 1;
279             }
280
281           /* At the end a special entry.  */
282           arsym[n].as_name = NULL;
283           arsym[n].as_off = 0;
284           arsym[n].as_hash = ~0UL;
285
286           /* Tell the caller how many entries we have.  */
287           elf->state.ar.ar_sym_num = n + 1;
288         }
289
290       result = elf->state.ar.ar_sym;
291
292     out:
293       rwlock_unlock (elf->lock);
294     }
295
296   if (ptr != NULL)
297     *ptr = elf->state.ar.ar_sym_num;
298
299   return result;
300 }