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