e6ecaadc724b9a8da1b507b83c30b3d5002b828d
[platform/upstream/elfutils.git] / libelf / elf_getarsym.c
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 *
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 }