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 = (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 #if HAVE_DECL_RAWMEMCHR
301 str_data = rawmemchr (str_data, '\0') + 1;
302 #else
303 char c;
304 do {
305 c = *str_data;
306 str_data++;
307 } while (c);
308 #endif
309 }
310
311 /* At the end a special entry. */
312 arsym[n].as_name = NULL;
313 arsym[n].as_off = 0;
314 arsym[n].as_hash = ~0UL;
315
316 /* Tell the caller how many entries we have. */
317 elf->state.ar.ar_sym_num = n + 1;
318 }
319
320 result = elf->state.ar.ar_sym;
321
322 out:
323 free (temp_data);
324 rwlock_unlock (elf->lock);
325 }
326
327 if (ptr != NULL)
328 *ptr = elf->state.ar.ar_sym_num;
329
330 return result;
331 }
332