• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <errno.h>
36 #include <stdbool.h>
37 #include <stdint.h>
38 #include <stdlib.h>
39 #include <string.h>
40 
41 #include <dl-hash.h>
42 #include "libelfP.h"
43 
44 
45 static int
read_number_entries(uint64_t * nump,Elf * elf,size_t * offp,bool index64_p)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)
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);
59   else if ((size_t) pread_retry (elf->fildes, &u, w, *offp) != w)
60     return -1;
61 
62   *offp += w;
63 
64   if (BYTE_ORDER == LITTLE_ENDIAN)
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 
72 Elf_Arsym *
elf_getarsym(Elf * elf,size_t * ptr)73 elf_getarsym (Elf *elf, size_t *ptr)
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.  */
98       rwlock_wrlock (elf->lock);
99 
100       /* In case we find no index remember this for the next call.  */
101       elf->state.ar.ar_sym = (Elf_Arsym *) -1l;
102 
103       /* We might have to allocate some temporary data for reading.  */
104       void *temp_data = NULL;
105 
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);
111 	  if (pread_retry (elf->fildes, &elf->state.ar.ar_hdr,
112 			   sizeof (struct ar_hdr), elf->start_offset + SARMAG)
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 
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 
148 	 XXX This is not entirely true.  There are some more forms.
149 	 Which of them shall we handle?  */
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
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 	}
162       int w = index64_p ? 8 : 4;
163 
164       /* We have an archive.  The first word in there is the number of
165 	 entries in the table.  */
166       uint64_t n = 0;
167       size_t off = elf->start_offset + SARMAG + sizeof (struct ar_hdr);
168       if (read_number_entries (&n, elf, &off, index64_p) < 0)
169 	{
170 	  /* Cannot read the number of entries.  */
171 	  __libelf_seterrno (ELF_E_NO_INDEX);
172 	  goto out;
173 	}
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 
182       if (index_size > elf->maximum_size
183 	  || elf->maximum_size - index_size < SARMAG + sizeof (struct ar_hdr)
184 #if SIZE_MAX <= 4294967295U
185 	  || n >= SIZE_MAX / sizeof (Elf_Arsym)
186 #endif
187 	  || n > index_size / w)
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);
197       elf->state.ar.ar_sym = malloc (ar_sym_len);
198       if (elf->state.ar.ar_sym != NULL)
199 	{
200 	  void *file_data; /* unit32_t[n] or uint64_t[n] */
201 	  char *str_data;
202 	  size_t sz = n * w;
203 
204 	  if (elf->map_address == NULL)
205 	    {
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;
213 
214 	      ar_sym_len += index_size - n * w;
215 	      Elf_Arsym *newp = realloc (elf->state.ar.ar_sym, ar_sym_len);
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.  */
228 	      if ((size_t) pread_retry (elf->fildes, file_data, sz, off) != sz
229 		  || ((size_t) pread_retry (elf->fildes, new_str,
230 					    index_size - sz, off + sz)
231 		      != index_size - sz))
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 	    {
244 	      file_data = (void *) (elf->map_address + off);
245 	      if (!ALLOW_UNALIGNED
246 		  && ((uintptr_t) file_data & -(uintptr_t) n) != 0)
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 		}
256 	      str_data = (char *) (elf->map_address + off + sz);
257 	    }
258 
259 	  /* Now we can build the data structure.  */
260 	  Elf_Arsym *arsym = elf->state.ar.ar_sym;
261 	  uint64_t (*u64)[n] = file_data;
262 	  uint32_t (*u32)[n] = file_data;
263 	  for (size_t cnt = 0; cnt < n; ++cnt)
264 	    {
265 	      arsym[cnt].as_name = str_data;
266 	      if (index64_p)
267 		{
268 		  uint64_t tmp = (*u64)[cnt];
269 		  if (BYTE_ORDER == LITTLE_ENDIAN)
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 		}
289 	      else if (BYTE_ORDER == LITTLE_ENDIAN)
290 		arsym[cnt].as_off = bswap_32 ((*u32)[cnt]);
291 	      else
292 		arsym[cnt].as_off = (*u32)[cnt];
293 
294 	      arsym[cnt].as_hash = _dl_elf_hash (str_data);
295 #if HAVE_DECL_RAWMEMCHR
296 	      str_data = rawmemchr (str_data, '\0') + 1;
297 #else
298 	      char c;
299 	      do {
300 		c = *str_data;
301 		str_data++;
302 	      } while (c);
303 #endif
304 	    }
305 
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:
318       free (temp_data);
319       rwlock_unlock (elf->lock);
320     }
321 
322   if (ptr != NULL)
323     *ptr = elf->state.ar.ar_sym_num;
324 
325   return result;
326 }
327