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