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