]>
Commit | Line | Data |
---|---|---|
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 |
45 | static int |
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) | |
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 | 72 | Elf_Arsym * |
1ccdfb68 | 73 | elf_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 | } |