Line data Source code
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 3 : read_number_entries (uint64_t *nump, Elf *elf, size_t *offp, bool index64_p)
51 : {
52 3 : union u
53 : {
54 : uint64_t ret64;
55 : uint32_t ret32;
56 : } u;
57 :
58 3 : size_t w = index64_p ? 8 : 4;
59 3 : 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 2 : memcpy (&u, elf->map_address + *offp, sizeof u);
63 1 : else if ((size_t) pread_retry (elf->fildes, &u, w, *offp) != w)
64 : return -1;
65 :
66 3 : *offp += w;
67 :
68 3 : if (__BYTE_ORDER == __LITTLE_ENDIAN)
69 3 : *nump = index64_p ? bswap_64 (u.ret64) : bswap_32 (u.ret32);
70 : else
71 : *nump = index64_p ? u.ret64 : u.ret32;
72 :
73 3 : return 0;
74 : }
75 :
76 : Elf_Arsym *
77 3 : elf_getarsym (Elf *elf, size_t *ptr)
78 : {
79 3 : if (elf->kind != ELF_K_AR)
80 : {
81 : /* This is no archive. */
82 0 : __libelf_seterrno (ELF_E_NO_ARCHIVE);
83 0 : return NULL;
84 : }
85 :
86 3 : 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 3 : *ptr = elf->state.ar.ar_sym_num;
90 :
91 3 : if (elf->state.ar.ar_sym == (Elf_Arsym *) -1l)
92 : {
93 : /* There is no index. */
94 0 : __libelf_seterrno (ELF_E_NO_INDEX);
95 0 : return NULL;
96 : }
97 :
98 3 : Elf_Arsym *result = elf->state.ar.ar_sym;
99 3 : if (result == NULL)
100 : {
101 : /* We have not yet read the index. */
102 3 : rwlock_wrlock (elf->lock);
103 :
104 : /* In case we find no index remember this for the next call. */
105 3 : elf->state.ar.ar_sym = (Elf_Arsym *) -1l;
106 :
107 : /* We might have to allocate some temporary data for reading. */
108 3 : void *temp_data = NULL;
109 :
110 3 : struct ar_hdr *index_hdr;
111 3 : if (elf->map_address == NULL)
112 : {
113 : /* We must read index from the file. */
114 1 : assert (elf->fildes != -1);
115 1 : if (pread_retry (elf->fildes, &elf->state.ar.ar_hdr,
116 1 : 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 0 : __libelf_seterrno (ELF_E_READ_ERROR);
122 0 : goto out;
123 : }
124 :
125 : index_hdr = &elf->state.ar.ar_hdr;
126 : }
127 : else
128 : {
129 2 : if (SARMAG + sizeof (struct ar_hdr) > elf->maximum_size)
130 : {
131 : /* There is no room for the full archive. */
132 0 : __libelf_seterrno (ELF_E_NO_INDEX);
133 0 : goto out;
134 : }
135 :
136 4 : index_hdr = (struct ar_hdr *) (elf->map_address
137 2 : + elf->start_offset + SARMAG);
138 : }
139 :
140 : /* Now test whether this really is an archive. */
141 3 : if (memcmp (index_hdr->ar_fmag, ARFMAG, 2) != 0)
142 : {
143 : /* Invalid magic bytes. */
144 0 : __libelf_seterrno (ELF_E_ARCHIVE_FMAG);
145 0 : goto out;
146 : }
147 :
148 3 : 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 3 : if (memcmp (index_hdr->ar_name, "/ ", 16) == 0)
155 : index64_p = false;
156 1 : 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 0 : __libelf_seterrno (ELF_E_NO_INDEX);
164 0 : goto out;
165 : }
166 3 : 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 3 : uint64_t n = 0;
171 3 : size_t off = elf->start_offset + SARMAG + sizeof (struct ar_hdr);
172 3 : if (read_number_entries (&n, elf, &off, index64_p) < 0)
173 : {
174 : /* Cannot read the number of entries. */
175 0 : __libelf_seterrno (ELF_E_NO_INDEX);
176 0 : 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 3 : char tmpbuf[17];
182 3 : memcpy (tmpbuf, index_hdr->ar_size, 10);
183 3 : tmpbuf[10] = '\0';
184 3 : size_t index_size = atol (tmpbuf);
185 :
186 3 : if (index_size > elf->maximum_size
187 3 : || 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 3 : || n > index_size / w)
192 : {
193 : /* This index table cannot be right since it does not fit into
194 : the file. */
195 0 : __libelf_seterrno (ELF_E_NO_INDEX);
196 0 : goto out;
197 : }
198 :
199 : /* Now we can allocate the arrays needed to store the index. */
200 3 : size_t ar_sym_len = (n + 1) * sizeof (Elf_Arsym);
201 3 : elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len);
202 3 : if (elf->state.ar.ar_sym != NULL)
203 : {
204 3 : void *file_data; /* unit32_t[n] or uint64_t[n] */
205 3 : char *str_data;
206 3 : size_t sz = n * w;
207 :
208 3 : if (elf->map_address == NULL)
209 : {
210 1 : temp_data = malloc (sz);
211 1 : if (unlikely (temp_data == NULL))
212 : {
213 0 : __libelf_seterrno (ELF_E_NOMEM);
214 0 : goto out;
215 : }
216 1 : file_data = temp_data;
217 :
218 1 : ar_sym_len += index_size - n * w;
219 1 : Elf_Arsym *newp = (Elf_Arsym *) realloc (elf->state.ar.ar_sym,
220 : ar_sym_len);
221 1 : if (newp == NULL)
222 : {
223 0 : free (elf->state.ar.ar_sym);
224 0 : elf->state.ar.ar_sym = NULL;
225 0 : __libelf_seterrno (ELF_E_NOMEM);
226 0 : goto out;
227 : }
228 1 : elf->state.ar.ar_sym = newp;
229 :
230 1 : char *new_str = (char *) (elf->state.ar.ar_sym + n + 1);
231 :
232 : /* Now read the data from the file. */
233 1 : if ((size_t) pread_retry (elf->fildes, file_data, sz, off) != sz
234 2 : || ((size_t) pread_retry (elf->fildes, new_str,
235 1 : index_size - sz, off + sz)
236 1 : != index_size - sz))
237 : {
238 : /* We were not able to read the data. */
239 0 : free (elf->state.ar.ar_sym);
240 0 : elf->state.ar.ar_sym = NULL;
241 0 : __libelf_seterrno (ELF_E_NO_INDEX);
242 0 : goto out;
243 : }
244 :
245 : str_data = (char *) new_str;
246 : }
247 : else
248 : {
249 2 : file_data = (void *) (elf->map_address + off);
250 2 : 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 2 : str_data = (char *) (elf->map_address + off + sz);
262 : }
263 :
264 : /* Now we can build the data structure. */
265 3 : Elf_Arsym *arsym = elf->state.ar.ar_sym;
266 3 : uint64_t (*u64)[n] = file_data;
267 3 : uint32_t (*u32)[n] = file_data;
268 161 : for (size_t cnt = 0; cnt < n; ++cnt)
269 : {
270 158 : arsym[cnt].as_name = str_data;
271 158 : if (index64_p)
272 : {
273 6 : uint64_t tmp = (*u64)[cnt];
274 6 : if (__BYTE_ORDER == __LITTLE_ENDIAN)
275 6 : tmp = bswap_64 (tmp);
276 :
277 6 : arsym[cnt].as_off = tmp;
278 :
279 : /* Check whether 64-bit offset fits into 32-bit
280 : size_t. */
281 6 : 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 152 : else if (__BYTE_ORDER == __LITTLE_ENDIAN)
295 304 : arsym[cnt].as_off = bswap_32 ((*u32)[cnt]);
296 : else
297 : arsym[cnt].as_off = (*u32)[cnt];
298 :
299 158 : arsym[cnt].as_hash = _dl_elf_hash (str_data);
300 : #if HAVE_DECL_RAWMEMCHR
301 158 : 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 3 : arsym[n].as_name = NULL;
313 3 : arsym[n].as_off = 0;
314 3 : arsym[n].as_hash = ~0UL;
315 :
316 : /* Tell the caller how many entries we have. */
317 3 : elf->state.ar.ar_sym_num = n + 1;
318 : }
319 :
320 3 : result = elf->state.ar.ar_sym;
321 :
322 3 : out:
323 3 : free (temp_data);
324 3 : rwlock_unlock (elf->lock);
325 : }
326 :
327 3 : if (ptr != NULL)
328 3 : *ptr = elf->state.ar.ar_sym_num;
329 :
330 : return result;
331 : }
|