• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Return symbol table of archive.
2    Copyright (C) 1998, 1999, 2000, 2002, 2005 Red Hat, Inc.
3    This file is part of Red Hat elfutils.
4    Written by Ulrich Drepper <drepper@redhat.com>, 1998.
5 
6    Red Hat elfutils is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by the
8    Free Software Foundation; version 2 of the License.
9 
10    Red Hat elfutils is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License along
16    with Red Hat elfutils; if not, write to the Free Software Foundation,
17    Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
18 
19    In addition, as a special exception, Red Hat, Inc. gives You the
20    additional right to link the code of Red Hat elfutils with code licensed
21    under any Open Source Initiative certified open source license
22    (http://www.opensource.org/licenses/index.php) which requires the
23    distribution of source code with any binary distribution and to
24    distribute linked combinations of the two.  Non-GPL Code permitted under
25    this exception must only link to the code of Red Hat elfutils through
26    those well defined interfaces identified in the file named EXCEPTION
27    found in the source code files (the "Approved Interfaces").  The files
28    of Non-GPL Code may instantiate templates or use macros or inline
29    functions from the Approved Interfaces without causing the resulting
30    work to be covered by the GNU General Public License.  Only Red Hat,
31    Inc. may make changes or additions to the list of Approved Interfaces.
32    Red Hat's grant of this exception is conditioned upon your not adding
33    any new exceptions.  If you wish to add a new Approved Interface or
34    exception, please contact Red Hat.  You must obey the GNU General Public
35    License in all respects for all of the Red Hat elfutils code and other
36    code used in conjunction with Red Hat elfutils except the Non-GPL Code
37    covered by this exception.  If you modify this file, you may extend this
38    exception to your version of the file, but you are not obligated to do
39    so.  If you do not wish to provide this exception without modification,
40    you must delete this exception statement from your version and license
41    this file solely under the GPL without exception.
42 
43    Red Hat elfutils is an included package of the Open Invention Network.
44    An included package of the Open Invention Network is a package for which
45    Open Invention Network licensees cross-license their patents.  No patent
46    license is granted, either expressly or impliedly, by designation as an
47    included package.  Should you wish to participate in the Open Invention
48    Network licensing program, please visit www.openinventionnetwork.com
49    <http://www.openinventionnetwork.com>.  */
50 
51 #ifdef HAVE_CONFIG_H
52 # include <config.h>
53 #endif
54 
55 #include <assert.h>
56 #include <byteswap.h>
57 #include <endian.h>
58 #include <errno.h>
59 #include <stdint.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <unistd.h>
63 
64 #include <system.h>
65 #include <dl-hash.h>
66 #include "libelfP.h"
67 
68 
69 Elf_Arsym *
elf_getarsym(elf,ptr)70 elf_getarsym (elf, ptr)
71      Elf *elf;
72      size_t *ptr;
73 {
74   if (elf->kind != ELF_K_AR)
75     {
76       /* This is no archive.  */
77       __libelf_seterrno (ELF_E_NO_ARCHIVE);
78       return NULL;
79     }
80 
81   if (ptr != NULL)
82     /* In case of an error or when we know the value store the expected
83        value now.  Doing this allows us easier exits in an error case.  */
84     *ptr = elf->state.ar.ar_sym_num;
85 
86   if (elf->state.ar.ar_sym == (Elf_Arsym *) -1l)
87     {
88       /* There is no index.  */
89       __libelf_seterrno (ELF_E_NO_INDEX);
90       return NULL;
91     }
92 
93   Elf_Arsym *result = elf->state.ar.ar_sym;
94   if (result == NULL)
95     {
96       /* We have not yet read the index.  */
97       rwlock_wrlock (elf->lock);
98 
99       /* In case we find no index remember this for the next call.  */
100       elf->state.ar.ar_sym = (Elf_Arsym *) -1l;
101 
102       struct ar_hdr *index_hdr;
103       if (elf->map_address == NULL)
104 	{
105 	  /* We must read index from the file.  */
106 	  assert (elf->fildes != -1);
107 	  if (pread_retry (elf->fildes, &elf->state.ar.ar_hdr,
108 			   sizeof (struct ar_hdr), elf->start_offset + SARMAG)
109 	      != sizeof (struct ar_hdr))
110 	    {
111 	      /* It is not possible to read the index.  Maybe it does not
112 		 exist.  */
113 	      __libelf_seterrno (ELF_E_READ_ERROR);
114 	      goto out;
115 	    }
116 
117 	  index_hdr = &elf->state.ar.ar_hdr;
118 	}
119       else
120 	{
121 	  if (SARMAG + sizeof (struct ar_hdr) > elf->maximum_size)
122 	    {
123 	      /* There is no room for the full archive.  */
124 	      __libelf_seterrno (ELF_E_NO_INDEX);
125 	      goto out;
126 	    }
127 
128 	  index_hdr = (struct ar_hdr *) (elf->map_address
129 					 + elf->start_offset + SARMAG);
130 	}
131 
132       /* Now test whether this really is an archive.  */
133       if (memcmp (index_hdr->ar_fmag, ARFMAG, 2) != 0)
134 	{
135 	  /* Invalid magic bytes.  */
136 	  __libelf_seterrno (ELF_E_ARCHIVE_FMAG);
137 	  goto out;
138 	}
139 
140       /* Now test whether this is the index.  It is denoted by the
141 	 name being "/ ".
142 	 XXX This is not entirely true.  There are some more forms.
143 	 Which of them shall we handle?  */
144       if (memcmp (index_hdr->ar_name, "/               ", 16) != 0)
145 	{
146 	  /* If the index is not the first entry, there is no index.
147 
148 	     XXX Is this true?  */
149 	  __libelf_seterrno (ELF_E_NO_INDEX);
150 	  goto out;
151 	}
152 
153       /* We have an archive.  The first word in there is the number of
154 	 entries in the table.  */
155       uint32_t n;
156       if (elf->map_address == NULL)
157 	{
158 	  if (pread_retry (elf->fildes, &n, sizeof (n),
159 			   elf->start_offset + SARMAG + sizeof (struct ar_hdr))
160 	      != sizeof (n))
161 	    {
162 	      /* Cannot read the number of entries.  */
163 	      __libelf_seterrno (ELF_E_NO_INDEX);
164 	      goto out;
165 	    }
166 	}
167       else
168 	n = *(uint32_t *) (elf->map_address + elf->start_offset
169 			   + SARMAG + sizeof (struct ar_hdr));
170 
171       if (__BYTE_ORDER == __LITTLE_ENDIAN)
172 	n = bswap_32 (n);
173 
174       /* Now we can perform some first tests on whether all the data
175 	 needed for the index is available.  */
176       char tmpbuf[17];
177       memcpy (tmpbuf, index_hdr->ar_size, 10);
178       tmpbuf[10] = '\0';
179       size_t index_size = atol (tmpbuf);
180 
181       if (SARMAG + sizeof (struct ar_hdr) + index_size > elf->maximum_size
182 	  || n * sizeof (uint32_t) > index_size)
183 	{
184 	  /* This index table cannot be right since it does not fit into
185 	     the file.  */
186 	  __libelf_seterrno (ELF_E_NO_INDEX);
187 	  goto out;
188 	}
189 
190       /* Now we can allocate the arrays needed to store the index.  */
191       size_t ar_sym_len = (n + 1) * sizeof (Elf_Arsym);
192       elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len);
193       if (elf->state.ar.ar_sym != NULL)
194 	{
195 	  uint32_t *file_data;
196 	  char *str_data;
197 
198 	  if (elf->map_address == NULL)
199 	    {
200 	      file_data = (uint32_t *) alloca (n * sizeof (uint32_t));
201 
202 	      ar_sym_len += index_size - n * sizeof (uint32_t);
203 	      Elf_Arsym *newp = (Elf_Arsym *) realloc (elf->state.ar.ar_sym,
204 						       ar_sym_len);
205 	      if (newp == NULL)
206 		{
207 		  free (elf->state.ar.ar_sym);
208 		  elf->state.ar.ar_sym = NULL;
209 		  __libelf_seterrno (ELF_E_NOMEM);
210 		  goto out;
211 		}
212 	      elf->state.ar.ar_sym = newp;
213 
214 	      char *new_str = (char *) (elf->state.ar.ar_sym + n + 1);
215 
216 	      /* Now read the data from the file.  */
217 	      if ((size_t) pread_retry (elf->fildes, file_data,
218 					n * sizeof (uint32_t),
219 					elf->start_offset + SARMAG
220 					+ sizeof (struct ar_hdr)
221 					+ sizeof (uint32_t))
222 		  != n * sizeof (uint32_t)
223 		  || ((size_t) pread_retry (elf->fildes, new_str,
224 					    index_size - n * sizeof (uint32_t),
225 					    elf->start_offset
226 					    + SARMAG + sizeof (struct ar_hdr)
227 					    + (n + 1) * sizeof (uint32_t))
228 		      != index_size - n * sizeof (uint32_t)))
229 		{
230 		  /* We were not able to read the data.  */
231 		  free (elf->state.ar.ar_sym);
232 		  elf->state.ar.ar_sym = NULL;
233 		  __libelf_seterrno (ELF_E_NO_INDEX);
234 		  goto out;
235 		}
236 
237 	      str_data = (char *) new_str;
238 	    }
239 	  else
240 	    {
241 	      file_data = (uint32_t *) (elf->map_address + elf->start_offset
242 					+ SARMAG + sizeof (struct ar_hdr)
243 					+ sizeof (uint32_t));
244 	      str_data = (char *) &file_data[n];
245 	    }
246 
247 	  /* Now we can build the data structure.  */
248 	  Elf_Arsym *arsym = elf->state.ar.ar_sym;
249 	  for (size_t cnt = 0; cnt < n; ++cnt)
250 	    {
251 	      arsym[cnt].as_name = str_data;
252 	      if (__BYTE_ORDER == __LITTLE_ENDIAN)
253 		arsym[cnt].as_off = bswap_32 (file_data[cnt]);
254 	      else
255 		arsym[cnt].as_off = file_data[cnt];
256 	      arsym[cnt].as_hash = _dl_elf_hash (str_data);
257 	      str_data = rawmemchr (str_data, '\0') + 1;
258 	    }
259 	  /* At the end a special entry.  */
260 	  arsym[n].as_name = NULL;
261 	  arsym[n].as_off = 0;
262 	  arsym[n].as_hash = ~0UL;
263 
264 	  /* Tell the caller how many entries we have.  */
265 	  elf->state.ar.ar_sym_num = n + 1;
266 	}
267 
268       result = elf->state.ar.ar_sym;
269 
270     out:
271       rwlock_unlock (elf->lock);
272     }
273 
274   if (ptr != NULL)
275     *ptr = elf->state.ar.ar_sym_num;
276 
277   return result;
278 }
279