Branch data Line data Source code
1 : : /* Return symbol table of archive.
2 : : Copyright (C) 1998-2000, 2002, 2005, 2012 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 : : 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 : : if (__BYTE_ORDER == __LITTLE_ENDIAN)
69 [ + + ]: 4 : *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 *
77 : 3 : elf_getarsym (elf, ptr)
78 : : Elf *elf;
79 : : size_t *ptr;
80 : : {
81 [ - + ]: 3 : if (elf->kind != ELF_K_AR)
82 : : {
83 : : /* This is no archive. */
84 : 0 : __libelf_seterrno (ELF_E_NO_ARCHIVE);
85 : 0 : return NULL;
86 : : }
87 : :
88 [ + - ]: 3 : if (ptr != NULL)
89 : : /* In case of an error or when we know the value store the expected
90 : : value now. Doing this allows us easier exits in an error case. */
91 : 3 : *ptr = elf->state.ar.ar_sym_num;
92 : :
93 [ - + ]: 3 : if (elf->state.ar.ar_sym == (Elf_Arsym *) -1l)
94 : : {
95 : : /* There is no index. */
96 : 0 : __libelf_seterrno (ELF_E_NO_INDEX);
97 : 0 : return NULL;
98 : : }
99 : :
100 : 3 : Elf_Arsym *result = elf->state.ar.ar_sym;
101 [ + - ]: 3 : if (result == NULL)
102 : : {
103 : : /* We have not yet read the index. */
104 : : rwlock_wrlock (elf->lock);
105 : :
106 : : /* In case we find no index remember this for the next call. */
107 : 3 : elf->state.ar.ar_sym = (Elf_Arsym *) -1l;
108 : :
109 : : struct ar_hdr *index_hdr;
110 [ + + ]: 3 : if (elf->map_address == NULL)
111 : : {
112 : : /* We must read index from the file. */
113 [ - + ]: 1 : assert (elf->fildes != -1);
114 [ - + ]: 1 : if (pread_retry (elf->fildes, &elf->state.ar.ar_hdr,
115 : 1 : sizeof (struct ar_hdr), elf->start_offset + SARMAG)
116 : : != sizeof (struct ar_hdr))
117 : : {
118 : : /* It is not possible to read the index. Maybe it does not
119 : : exist. */
120 : 0 : __libelf_seterrno (ELF_E_READ_ERROR);
121 : 0 : goto out;
122 : : }
123 : :
124 : : index_hdr = &elf->state.ar.ar_hdr;
125 : : }
126 : : else
127 : : {
128 [ - + ]: 2 : if (SARMAG + sizeof (struct ar_hdr) > elf->maximum_size)
129 : : {
130 : : /* There is no room for the full archive. */
131 : 0 : __libelf_seterrno (ELF_E_NO_INDEX);
132 : 0 : goto out;
133 : : }
134 : :
135 : 2 : index_hdr = (struct ar_hdr *) (elf->map_address
136 : 2 : + elf->start_offset + SARMAG);
137 : : }
138 : :
139 : : /* Now test whether this really is an archive. */
140 [ - + ]: 3 : if (memcmp (index_hdr->ar_fmag, ARFMAG, 2) != 0)
141 : : {
142 : : /* Invalid magic bytes. */
143 : 0 : __libelf_seterrno (ELF_E_ARCHIVE_FMAG);
144 : 0 : goto out;
145 : : }
146 : :
147 : : bool index64_p;
148 : : /* Now test whether this is the index. If the name is "/", this
149 : : is 32-bit index, if it's "/SYM64/", it's 64-bit index.
150 : :
151 : : XXX This is not entirely true. There are some more forms.
152 : : Which of them shall we handle? */
153 [ + + ]: 3 : if (memcmp (index_hdr->ar_name, "/ ", 16) == 0)
154 : : index64_p = false;
155 [ - + ]: 1 : else if (memcmp (index_hdr->ar_name, "/SYM64/ ", 16) == 0)
156 : : index64_p = true;
157 : : else
158 : : {
159 : : /* If the index is not the first entry, there is no index.
160 : :
161 : : XXX Is this true? */
162 : 0 : __libelf_seterrno (ELF_E_NO_INDEX);
163 : 0 : goto out;
164 : : }
165 [ + + ]: 3 : int w = index64_p ? 8 : 4;
166 : :
167 : : /* We have an archive. The first word in there is the number of
168 : : entries in the table. */
169 : : uint64_t n;
170 : 3 : size_t off = elf->start_offset + SARMAG + sizeof (struct ar_hdr);
171 [ - + ]: 3 : if (read_number_entries (&n, elf, &off, index64_p) < 0)
172 : : {
173 : : /* Cannot read the number of entries. */
174 : 0 : __libelf_seterrno (ELF_E_NO_INDEX);
175 : 0 : goto out;
176 : : }
177 : :
178 : : /* Now we can perform some first tests on whether all the data
179 : : needed for the index is available. */
180 : : char tmpbuf[17];
181 : 3 : memcpy (tmpbuf, index_hdr->ar_size, 10);
182 : 3 : tmpbuf[10] = '\0';
183 : 3 : size_t index_size = atol (tmpbuf);
184 : :
185 [ + - ]: 3 : if (SARMAG + sizeof (struct ar_hdr) + index_size > elf->maximum_size
186 [ - + ]: 3 : || n * w > index_size)
187 : : {
188 : : /* This index table cannot be right since it does not fit into
189 : : the file. */
190 : 0 : __libelf_seterrno (ELF_E_NO_INDEX);
191 : 0 : goto out;
192 : : }
193 : :
194 : : /* Now we can allocate the arrays needed to store the index. */
195 : 3 : size_t ar_sym_len = (n + 1) * sizeof (Elf_Arsym);
196 : 3 : elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len);
197 [ + - ]: 3 : if (elf->state.ar.ar_sym != NULL)
198 : : {
199 : 9 : union
200 : : {
201 : 3 : uint32_t u32[n];
202 : 3 : uint64_t u64[n];
203 : : } *file_data;
204 : : char *str_data;
205 : 3 : size_t sz = n * w;
206 : :
207 [ + + ]: 3 : if (elf->map_address == NULL)
208 : : {
209 : 1 : file_data = alloca (sz);
210 : :
211 : 1 : ar_sym_len += index_size - n * w;
212 : 1 : Elf_Arsym *newp = (Elf_Arsym *) realloc (elf->state.ar.ar_sym,
213 : : ar_sym_len);
214 [ - + ]: 1 : if (newp == NULL)
215 : : {
216 : 0 : free (elf->state.ar.ar_sym);
217 : 0 : elf->state.ar.ar_sym = NULL;
218 : 0 : __libelf_seterrno (ELF_E_NOMEM);
219 : 0 : goto out;
220 : : }
221 : 1 : elf->state.ar.ar_sym = newp;
222 : :
223 : 1 : char *new_str = (char *) (elf->state.ar.ar_sym + n + 1);
224 : :
225 : : /* Now read the data from the file. */
226 [ + - ]: 1 : if ((size_t) pread_retry (elf->fildes, file_data, sz, off) != sz
227 [ - + ]: 1 : || ((size_t) pread_retry (elf->fildes, new_str,
228 : 1 : index_size - sz, off + sz)
229 : : != index_size - sz))
230 : : {
231 : : /* We were not able to read the data. */
232 : 0 : free (elf->state.ar.ar_sym);
233 : 0 : elf->state.ar.ar_sym = NULL;
234 : 0 : __libelf_seterrno (ELF_E_NO_INDEX);
235 : 0 : goto out;
236 : : }
237 : :
238 : : str_data = (char *) new_str;
239 : : }
240 : : else
241 : : {
242 : 2 : file_data = (void *) (elf->map_address + off);
243 : : if (!ALLOW_UNALIGNED
244 : : && ((uintptr_t) file_data & -(uintptr_t) n) != 0)
245 : : file_data = memcpy (alloca (sz), elf->map_address + off, sz);
246 : 2 : str_data = (char *) (elf->map_address + off + sz);
247 : : }
248 : :
249 : : /* Now we can build the data structure. */
250 : 3 : Elf_Arsym *arsym = elf->state.ar.ar_sym;
251 [ + + ]: 152 : for (size_t cnt = 0; cnt < n; ++cnt)
252 : : {
253 : 149 : arsym[cnt].as_name = str_data;
254 [ + + ]: 149 : if (index64_p)
255 : : {
256 : 6 : uint64_t tmp = file_data->u64[cnt];
257 : : if (__BYTE_ORDER == __LITTLE_ENDIAN)
258 : 6 : tmp = bswap_64 (tmp);
259 : :
260 : 6 : arsym[cnt].as_off = tmp;
261 : :
262 : : /* Check whether 64-bit offset fits into 32-bit
263 : : size_t. */
264 : : if (sizeof (arsym[cnt].as_off) < 8
265 : : && arsym[cnt].as_off != tmp)
266 : : {
267 : : if (elf->map_address == NULL)
268 : : {
269 : : free (elf->state.ar.ar_sym);
270 : : elf->state.ar.ar_sym = NULL;
271 : : }
272 : :
273 : : __libelf_seterrno (ELF_E_RANGE);
274 : : goto out;
275 : : }
276 : : }
277 : : else if (__BYTE_ORDER == __LITTLE_ENDIAN)
278 : 143 : arsym[cnt].as_off = bswap_32 (file_data->u32[cnt]);
279 : : else
280 : : arsym[cnt].as_off = file_data->u32[cnt];
281 : :
282 : 149 : arsym[cnt].as_hash = _dl_elf_hash (str_data);
283 : 149 : str_data = rawmemchr (str_data, '\0') + 1;
284 : : }
285 : :
286 : : /* At the end a special entry. */
287 : 3 : arsym[n].as_name = NULL;
288 : 3 : arsym[n].as_off = 0;
289 : 3 : arsym[n].as_hash = ~0UL;
290 : :
291 : : /* Tell the caller how many entries we have. */
292 : 3 : elf->state.ar.ar_sym_num = n + 1;
293 : : }
294 : :
295 : 3 : result = elf->state.ar.ar_sym;
296 : :
297 : : out:
298 : : rwlock_unlock (elf->lock);
299 : : }
300 : :
301 [ + - ]: 3 : if (ptr != NULL)
302 : 3 : *ptr = elf->state.ar.ar_sym_num;
303 : :
304 : 3 : return result;
305 : 6 : }
|