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
read_number_entries(uint64_t * nump,Elf * elf,size_t * offp,bool index64_p)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 *
elf_getarsym(Elf * elf,size_t * ptr)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 = 0;
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 = 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 = realloc (elf->state.ar.ar_sym, ar_sym_len);
220 if (newp == NULL)
221 {
222 free (elf->state.ar.ar_sym);
223 elf->state.ar.ar_sym = NULL;
224 __libelf_seterrno (ELF_E_NOMEM);
225 goto out;
226 }
227 elf->state.ar.ar_sym = newp;
228
229 char *new_str = (char *) (elf->state.ar.ar_sym + n + 1);
230
231 /* Now read the data from the file. */
232 if ((size_t) pread_retry (elf->fildes, file_data, sz, off) != sz
233 || ((size_t) pread_retry (elf->fildes, new_str,
234 index_size - sz, off + sz)
235 != index_size - sz))
236 {
237 /* We were not able to read the data. */
238 free (elf->state.ar.ar_sym);
239 elf->state.ar.ar_sym = NULL;
240 __libelf_seterrno (ELF_E_NO_INDEX);
241 goto out;
242 }
243
244 str_data = (char *) new_str;
245 }
246 else
247 {
248 file_data = (void *) (elf->map_address + off);
249 if (!ALLOW_UNALIGNED
250 && ((uintptr_t) file_data & -(uintptr_t) n) != 0)
251 {
252 temp_data = malloc (sz);
253 if (unlikely (temp_data == NULL))
254 {
255 __libelf_seterrno (ELF_E_NOMEM);
256 goto out;
257 }
258 file_data = memcpy (temp_data, elf->map_address + off, sz);
259 }
260 str_data = (char *) (elf->map_address + off + sz);
261 }
262
263 /* Now we can build the data structure. */
264 Elf_Arsym *arsym = elf->state.ar.ar_sym;
265 uint64_t (*u64)[n] = file_data;
266 uint32_t (*u32)[n] = file_data;
267 for (size_t cnt = 0; cnt < n; ++cnt)
268 {
269 arsym[cnt].as_name = str_data;
270 if (index64_p)
271 {
272 uint64_t tmp = (*u64)[cnt];
273 if (__BYTE_ORDER == __LITTLE_ENDIAN)
274 tmp = bswap_64 (tmp);
275
276 arsym[cnt].as_off = tmp;
277
278 /* Check whether 64-bit offset fits into 32-bit
279 size_t. */
280 if (sizeof (arsym[cnt].as_off) < 8
281 && arsym[cnt].as_off != tmp)
282 {
283 if (elf->map_address == NULL)
284 {
285 free (elf->state.ar.ar_sym);
286 elf->state.ar.ar_sym = NULL;
287 }
288
289 __libelf_seterrno (ELF_E_RANGE);
290 goto out;
291 }
292 }
293 else if (__BYTE_ORDER == __LITTLE_ENDIAN)
294 arsym[cnt].as_off = bswap_32 ((*u32)[cnt]);
295 else
296 arsym[cnt].as_off = (*u32)[cnt];
297
298 arsym[cnt].as_hash = _dl_elf_hash (str_data);
299 #if HAVE_DECL_RAWMEMCHR
300 str_data = rawmemchr (str_data, '\0') + 1;
301 #else
302 char c;
303 do {
304 c = *str_data;
305 str_data++;
306 } while (c);
307 #endif
308 }
309
310 /* At the end a special entry. */
311 arsym[n].as_name = NULL;
312 arsym[n].as_off = 0;
313 arsym[n].as_hash = ~0UL;
314
315 /* Tell the caller how many entries we have. */
316 elf->state.ar.ar_sym_num = n + 1;
317 }
318
319 result = elf->state.ar.ar_sym;
320
321 out:
322 free (temp_data);
323 rwlock_unlock (elf->lock);
324 }
325
326 if (ptr != NULL)
327 *ptr = elf->state.ar.ar_sym_num;
328
329 return result;
330 }
331