]> git.ipfire.org Git - thirdparty/elfutils.git/blame - libelf/elf_getarsym.c
funcretval-struct
[thirdparty/elfutils.git] / libelf / elf_getarsym.c
CommitLineData
b08d5a8f 1/* Return symbol table of archive.
bfb9a752 2 Copyright (C) 1998-2000, 2002, 2005, 2009, 2012, 2014, 2015 Red Hat, Inc.
de2ed97f 3 This file is part of elfutils.
b08d5a8f
UD
4 Written by Ulrich Drepper <drepper@redhat.com>, 1998.
5
de2ed97f
MW
6 This file is free software; you can redistribute it and/or modify
7 it under the terms of either
b08d5a8f 8
de2ed97f
MW
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
361df7da
UD
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.
b08d5a8f 25
de2ed97f
MW
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/>. */
b08d5a8f
UD
29
30#ifdef HAVE_CONFIG_H
31# include <config.h>
32#endif
33
34#include <assert.h>
e5294612 35#include <errno.h>
e1873141 36#include <stdbool.h>
b08d5a8f
UD
37#include <stdint.h>
38#include <stdlib.h>
39#include <string.h>
b08d5a8f
UD
40
41#include <dl-hash.h>
42#include "libelfP.h"
43
44
e1873141
PM
45static int
46read_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)
99d9db00
RM
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);
e1873141
PM
59 else if ((size_t) pread_retry (elf->fildes, &u, w, *offp) != w)
60 return -1;
61
62 *offp += w;
63
0e18267a 64 if (BYTE_ORDER == LITTLE_ENDIAN)
e1873141
PM
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
b08d5a8f 72Elf_Arsym *
1ccdfb68 73elf_getarsym (Elf *elf, size_t *ptr)
b08d5a8f
UD
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. */
b4d6f0f8 98 rwlock_wrlock (elf->lock);
b08d5a8f
UD
99
100 /* In case we find no index remember this for the next call. */
101 elf->state.ar.ar_sym = (Elf_Arsym *) -1l;
102
bfb9a752
MW
103 /* We might have to allocate some temporary data for reading. */
104 void *temp_data = NULL;
105
b08d5a8f
UD
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);
e5294612
UD
111 if (pread_retry (elf->fildes, &elf->state.ar.ar_hdr,
112 sizeof (struct ar_hdr), elf->start_offset + SARMAG)
b08d5a8f
UD
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
e1873141
PM
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
b08d5a8f
UD
148 XXX This is not entirely true. There are some more forms.
149 Which of them shall we handle? */
e1873141
PM
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
b08d5a8f
UD
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 }
e1873141 162 int w = index64_p ? 8 : 4;
b08d5a8f
UD
163
164 /* We have an archive. The first word in there is the number of
165 entries in the table. */
7114c513 166 uint64_t n = 0;
e1873141
PM
167 size_t off = elf->start_offset + SARMAG + sizeof (struct ar_hdr);
168 if (read_number_entries (&n, elf, &off, index64_p) < 0)
b08d5a8f 169 {
e1873141
PM
170 /* Cannot read the number of entries. */
171 __libelf_seterrno (ELF_E_NO_INDEX);
172 goto out;
b08d5a8f 173 }
b08d5a8f
UD
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
4bb122a8
MW
182 if (index_size > elf->maximum_size
183 || elf->maximum_size - index_size < SARMAG + sizeof (struct ar_hdr)
720383c5
JJ
184#if SIZE_MAX <= 4294967295U
185 || n >= SIZE_MAX / sizeof (Elf_Arsym)
186#endif
16f08ebd 187 || n > index_size / w)
b08d5a8f
UD
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);
e0942709 197 elf->state.ar.ar_sym = malloc (ar_sym_len);
b08d5a8f
UD
198 if (elf->state.ar.ar_sym != NULL)
199 {
7eff36d5 200 void *file_data; /* unit32_t[n] or uint64_t[n] */
b08d5a8f 201 char *str_data;
e1873141 202 size_t sz = n * w;
b08d5a8f
UD
203
204 if (elf->map_address == NULL)
205 {
bfb9a752
MW
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;
b08d5a8f 213
e1873141 214 ar_sym_len += index_size - n * w;
e0942709 215 Elf_Arsym *newp = realloc (elf->state.ar.ar_sym, ar_sym_len);
b08d5a8f
UD
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. */
e1873141 228 if ((size_t) pread_retry (elf->fildes, file_data, sz, off) != sz
e5294612 229 || ((size_t) pread_retry (elf->fildes, new_str,
e1873141
PM
230 index_size - sz, off + sz)
231 != index_size - sz))
b08d5a8f
UD
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 {
e1873141 244 file_data = (void *) (elf->map_address + off);
6722a667
RM
245 if (!ALLOW_UNALIGNED
246 && ((uintptr_t) file_data & -(uintptr_t) n) != 0)
f78e8640
MW
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 }
e1873141 256 str_data = (char *) (elf->map_address + off + sz);
b08d5a8f
UD
257 }
258
259 /* Now we can build the data structure. */
260 Elf_Arsym *arsym = elf->state.ar.ar_sym;
7eff36d5
CHH
261 uint64_t (*u64)[n] = file_data;
262 uint32_t (*u32)[n] = file_data;
b08d5a8f
UD
263 for (size_t cnt = 0; cnt < n; ++cnt)
264 {
265 arsym[cnt].as_name = str_data;
e1873141
PM
266 if (index64_p)
267 {
7eff36d5 268 uint64_t tmp = (*u64)[cnt];
0e18267a 269 if (BYTE_ORDER == LITTLE_ENDIAN)
e1873141
PM
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 }
0e18267a 289 else if (BYTE_ORDER == LITTLE_ENDIAN)
7eff36d5 290 arsym[cnt].as_off = bswap_32 ((*u32)[cnt]);
b08d5a8f 291 else
7eff36d5 292 arsym[cnt].as_off = (*u32)[cnt];
e1873141 293
b08d5a8f 294 arsym[cnt].as_hash = _dl_elf_hash (str_data);
a24d52ac 295#if HAVE_DECL_RAWMEMCHR
b08d5a8f 296 str_data = rawmemchr (str_data, '\0') + 1;
a24d52ac
AO
297#else
298 char c;
299 do {
300 c = *str_data;
301 str_data++;
302 } while (c);
303#endif
b08d5a8f 304 }
e1873141 305
b08d5a8f
UD
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:
bfb9a752 318 free (temp_data);
b4d6f0f8 319 rwlock_unlock (elf->lock);
b08d5a8f
UD
320 }
321
322 if (ptr != NULL)
323 *ptr = elf->state.ar.ar_sym_num;
324
325 return result;
326}