packaging: update homepage url
[platform/upstream/elfutils.git] / libelf / elf_getarsym.c
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
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 *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 }