blob: 9e0f4c2bbf54f677dfe34ffc00344a1eacf43529 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Return symbol table of archive.
Petr Machatae1873142012-08-01 21:37:52 +02002 Copyright (C) 1998-2000, 2002, 2005, 2012 Red Hat, Inc.
Mark Wielaardde2ed972012-06-05 17:15:16 +02003 This file is part of elfutils.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004 Written by Ulrich Drepper <drepper@redhat.com>, 1998.
5
Mark Wielaardde2ed972012-06-05 17:15:16 +02006 This file is free software; you can redistribute it and/or modify
7 it under the terms of either
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00008
Mark Wielaardde2ed972012-06-05 17:15:16 +02009 * 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
Ulrich Drepper361df7d2006-04-04 21:38:57 +000022 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.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000025
Mark Wielaardde2ed972012-06-05 17:15:16 +020026 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/>. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000029
30#ifdef HAVE_CONFIG_H
31# include <config.h>
32#endif
33
34#include <assert.h>
35#include <byteswap.h>
36#include <endian.h>
Ulrich Dreppere5294612005-08-15 22:19:26 +000037#include <errno.h>
Petr Machatae1873142012-08-01 21:37:52 +020038#include <stdbool.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000039#include <stdint.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43
Ulrich Drepperfbe998a2005-08-29 16:27:10 +000044#include <system.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000045#include <dl-hash.h>
46#include "libelfP.h"
47
48
Petr Machatae1873142012-08-01 21:37:52 +020049static int
50read_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 size_t w = index64_p ? 8 : 4;
59 if (elf->map_address != NULL)
60 u = *(union u *) (elf->map_address + *offp);
61 else if ((size_t) pread_retry (elf->fildes, &u, w, *offp) != w)
62 return -1;
63
64 *offp += w;
65
66 if (__BYTE_ORDER == __LITTLE_ENDIAN)
67 *nump = index64_p ? bswap_64 (u.ret64) : bswap_32 (u.ret32);
68 else
69 *nump = index64_p ? u.ret64 : u.ret32;
70
71 return 0;
72}
73
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000074Elf_Arsym *
75elf_getarsym (elf, ptr)
76 Elf *elf;
77 size_t *ptr;
78{
79 if (elf->kind != ELF_K_AR)
80 {
81 /* This is no archive. */
82 __libelf_seterrno (ELF_E_NO_ARCHIVE);
83 return NULL;
84 }
85
86 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 *ptr = elf->state.ar.ar_sym_num;
90
91 if (elf->state.ar.ar_sym == (Elf_Arsym *) -1l)
92 {
93 /* There is no index. */
94 __libelf_seterrno (ELF_E_NO_INDEX);
95 return NULL;
96 }
97
98 Elf_Arsym *result = elf->state.ar.ar_sym;
99 if (result == NULL)
100 {
101 /* We have not yet read the index. */
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000102 rwlock_wrlock (elf->lock);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000103
104 /* In case we find no index remember this for the next call. */
105 elf->state.ar.ar_sym = (Elf_Arsym *) -1l;
106
107 struct ar_hdr *index_hdr;
108 if (elf->map_address == NULL)
109 {
110 /* We must read index from the file. */
111 assert (elf->fildes != -1);
Ulrich Dreppere5294612005-08-15 22:19:26 +0000112 if (pread_retry (elf->fildes, &elf->state.ar.ar_hdr,
113 sizeof (struct ar_hdr), elf->start_offset + SARMAG)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000114 != sizeof (struct ar_hdr))
115 {
116 /* It is not possible to read the index. Maybe it does not
117 exist. */
118 __libelf_seterrno (ELF_E_READ_ERROR);
119 goto out;
120 }
121
122 index_hdr = &elf->state.ar.ar_hdr;
123 }
124 else
125 {
126 if (SARMAG + sizeof (struct ar_hdr) > elf->maximum_size)
127 {
128 /* There is no room for the full archive. */
129 __libelf_seterrno (ELF_E_NO_INDEX);
130 goto out;
131 }
132
133 index_hdr = (struct ar_hdr *) (elf->map_address
134 + elf->start_offset + SARMAG);
135 }
136
137 /* Now test whether this really is an archive. */
138 if (memcmp (index_hdr->ar_fmag, ARFMAG, 2) != 0)
139 {
140 /* Invalid magic bytes. */
141 __libelf_seterrno (ELF_E_ARCHIVE_FMAG);
142 goto out;
143 }
144
Petr Machatae1873142012-08-01 21:37:52 +0200145 bool index64_p;
146 /* Now test whether this is the index. If the name is "/", this
147 is 32-bit index, if it's "/SYM64/", it's 64-bit index.
148
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000149 XXX This is not entirely true. There are some more forms.
150 Which of them shall we handle? */
Petr Machatae1873142012-08-01 21:37:52 +0200151 if (memcmp (index_hdr->ar_name, "/ ", 16) == 0)
152 index64_p = false;
153 else if (memcmp (index_hdr->ar_name, "/SYM64/ ", 16) == 0)
154 index64_p = true;
155 else
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000156 {
157 /* If the index is not the first entry, there is no index.
158
159 XXX Is this true? */
160 __libelf_seterrno (ELF_E_NO_INDEX);
161 goto out;
162 }
Petr Machatae1873142012-08-01 21:37:52 +0200163 int w = index64_p ? 8 : 4;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000164
165 /* We have an archive. The first word in there is the number of
166 entries in the table. */
Petr Machatae1873142012-08-01 21:37:52 +0200167 uint64_t n;
168 size_t off = elf->start_offset + SARMAG + sizeof (struct ar_hdr);
169 if (read_number_entries (&n, elf, &off, index64_p) < 0)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000170 {
Petr Machatae1873142012-08-01 21:37:52 +0200171 /* Cannot read the number of entries. */
172 __libelf_seterrno (ELF_E_NO_INDEX);
173 goto out;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000174 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000175
176 /* Now we can perform some first tests on whether all the data
177 needed for the index is available. */
178 char tmpbuf[17];
179 memcpy (tmpbuf, index_hdr->ar_size, 10);
180 tmpbuf[10] = '\0';
181 size_t index_size = atol (tmpbuf);
182
183 if (SARMAG + sizeof (struct ar_hdr) + index_size > elf->maximum_size
Petr Machatae1873142012-08-01 21:37:52 +0200184 || n * w > index_size)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000185 {
186 /* This index table cannot be right since it does not fit into
187 the file. */
188 __libelf_seterrno (ELF_E_NO_INDEX);
189 goto out;
190 }
191
192 /* Now we can allocate the arrays needed to store the index. */
193 size_t ar_sym_len = (n + 1) * sizeof (Elf_Arsym);
194 elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len);
195 if (elf->state.ar.ar_sym != NULL)
196 {
Petr Machatae1873142012-08-01 21:37:52 +0200197 union
198 {
199 uint32_t u32[n];
200 uint64_t u64[n];
201 } *file_data;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000202 char *str_data;
Petr Machatae1873142012-08-01 21:37:52 +0200203 size_t sz = n * w;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000204
205 if (elf->map_address == NULL)
206 {
Petr Machatae1873142012-08-01 21:37:52 +0200207 file_data = alloca (sz);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000208
Petr Machatae1873142012-08-01 21:37:52 +0200209 ar_sym_len += index_size - n * w;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000210 Elf_Arsym *newp = (Elf_Arsym *) realloc (elf->state.ar.ar_sym,
211 ar_sym_len);
212 if (newp == NULL)
213 {
214 free (elf->state.ar.ar_sym);
215 elf->state.ar.ar_sym = NULL;
216 __libelf_seterrno (ELF_E_NOMEM);
217 goto out;
218 }
219 elf->state.ar.ar_sym = newp;
220
221 char *new_str = (char *) (elf->state.ar.ar_sym + n + 1);
222
223 /* Now read the data from the file. */
Petr Machatae1873142012-08-01 21:37:52 +0200224 if ((size_t) pread_retry (elf->fildes, file_data, sz, off) != sz
Ulrich Dreppere5294612005-08-15 22:19:26 +0000225 || ((size_t) pread_retry (elf->fildes, new_str,
Petr Machatae1873142012-08-01 21:37:52 +0200226 index_size - sz, off + sz)
227 != index_size - sz))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000228 {
229 /* We were not able to read the data. */
230 free (elf->state.ar.ar_sym);
231 elf->state.ar.ar_sym = NULL;
232 __libelf_seterrno (ELF_E_NO_INDEX);
233 goto out;
234 }
235
236 str_data = (char *) new_str;
237 }
238 else
239 {
Petr Machatae1873142012-08-01 21:37:52 +0200240 file_data = (void *) (elf->map_address + off);
241 str_data = (char *) (elf->map_address + off + sz);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000242 }
243
244 /* Now we can build the data structure. */
245 Elf_Arsym *arsym = elf->state.ar.ar_sym;
246 for (size_t cnt = 0; cnt < n; ++cnt)
247 {
248 arsym[cnt].as_name = str_data;
Petr Machatae1873142012-08-01 21:37:52 +0200249 if (index64_p)
250 {
251 uint64_t tmp = file_data->u64[cnt];
252 if (__BYTE_ORDER == __LITTLE_ENDIAN)
253 tmp = bswap_64 (tmp);
254
255 arsym[cnt].as_off = tmp;
256
257 /* Check whether 64-bit offset fits into 32-bit
258 size_t. */
259 if (sizeof (arsym[cnt].as_off) < 8
260 && arsym[cnt].as_off != tmp)
261 {
262 if (elf->map_address == NULL)
263 {
264 free (elf->state.ar.ar_sym);
265 elf->state.ar.ar_sym = NULL;
266 }
267
268 __libelf_seterrno (ELF_E_RANGE);
269 goto out;
270 }
271 }
272 else if (__BYTE_ORDER == __LITTLE_ENDIAN)
273 arsym[cnt].as_off = bswap_32 (file_data->u32[cnt]);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000274 else
Petr Machatae1873142012-08-01 21:37:52 +0200275 arsym[cnt].as_off = file_data->u32[cnt];
276
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000277 arsym[cnt].as_hash = _dl_elf_hash (str_data);
278 str_data = rawmemchr (str_data, '\0') + 1;
279 }
Petr Machatae1873142012-08-01 21:37:52 +0200280
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000281 /* At the end a special entry. */
282 arsym[n].as_name = NULL;
283 arsym[n].as_off = 0;
284 arsym[n].as_hash = ~0UL;
285
286 /* Tell the caller how many entries we have. */
287 elf->state.ar.ar_sym_num = n + 1;
288 }
289
290 result = elf->state.ar.ar_sym;
291
292 out:
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000293 rwlock_unlock (elf->lock);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000294 }
295
296 if (ptr != NULL)
297 *ptr = elf->state.ar.ar_sym_num;
298
299 return result;
300}