bcf9344bd4fb25fd6a6481c9b3e8b369a3ca1e7a
[platform/upstream/elfutils.git] / src / arlib.c
1 /* Functions to handle creation of Linux archives.
2    Copyright (C) 2007-2012 Red Hat, Inc.
3    Written by Ulrich Drepper <drepper@redhat.com>, 2007.
4
5    Red Hat elfutils is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by the
7    Free Software Foundation; version 2 of the License.
8
9    Red Hat elfutils is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13
14    You should have received a copy of the GNU General Public License along
15    with Red Hat elfutils; if not, write to the Free Software Foundation,
16    Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
17
18    Red Hat elfutils is an included package of the Open Invention Network.
19    An included package of the Open Invention Network is a package for which
20    Open Invention Network licensees cross-license their patents.  No patent
21    license is granted, either expressly or impliedly, by designation as an
22    included package.  Should you wish to participate in the Open Invention
23    Network licensing program, please visit www.openinventionnetwork.com
24    <http://www.openinventionnetwork.com>.  */
25
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29
30 #include <assert.h>
31 #include <error.h>
32 #include <gelf.h>
33 #include <libintl.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <time.h>
37
38 #include <system.h>
39
40 #include "arlib.h"
41
42
43 /* The one symbol table we hanble.  */
44 struct arlib_symtab symtab;
45
46
47 /* Initialize ARLIB_SYMTAB structure.  */
48 void
49 arlib_init (void)
50 {
51 #define obstack_chunk_alloc xmalloc
52 #define obstack_chunk_free free
53   obstack_init (&symtab.symsoffob);
54   obstack_init (&symtab.symsnameob);
55   obstack_init (&symtab.longnamesob);
56
57   /* We add the archive header here as well, that avoids allocating
58      another memory block.  */
59   struct ar_hdr ar_hdr;
60   memcpy (ar_hdr.ar_name, "/               ", sizeof (ar_hdr.ar_name));
61   /* Using snprintf here has a problem: the call always wants to add a
62      NUL byte.  We could use a trick whereby we specify the target
63      buffer size longer than it is and this would not actually fail,
64      since all the fields are consecutive and we fill them in
65      sequence (i.e., the NUL byte gets overwritten).  But
66      _FORTIFY_SOURCE=2 would not let us play these games.  Therefore
67      we play it safe.  */
68   char tmpbuf[sizeof (ar_hdr.ar_date) + 1];
69   memcpy (ar_hdr.ar_date, tmpbuf,
70           snprintf (tmpbuf, sizeof (tmpbuf), "%-*lld",
71                     (int) sizeof (ar_hdr.ar_date),
72                     (arlib_deterministic_output ? 0
73                      : (long long int) time (NULL))));
74   assert ((sizeof (struct ar_hdr)  % sizeof (uint32_t)) == 0);
75
76   /* Note the string for the ar_uid and ar_gid cases is longer than
77      necessary.  This does not matter since we copy only as much as
78      necessary but it helps the compiler to use the same string for
79      the ar_mode case.  */
80   memcpy (ar_hdr.ar_uid, "0       ", sizeof (ar_hdr.ar_uid));
81   memcpy (ar_hdr.ar_gid, "0       ", sizeof (ar_hdr.ar_gid));
82   memcpy (ar_hdr.ar_mode, "0       ", sizeof (ar_hdr.ar_mode));
83   memcpy (ar_hdr.ar_fmag, ARFMAG, sizeof (ar_hdr.ar_fmag));
84
85   /* Add the archive header to the file content.  */
86   obstack_grow (&symtab.symsoffob, &ar_hdr, sizeof (ar_hdr));
87
88   /* The first word in the offset table specifies the size.  Create
89      such an entry now.  The real value will be filled-in later.  For
90      all supported platforms the following is true.  */
91   assert (sizeof (uint32_t) == sizeof (int));
92   obstack_int_grow (&symtab.symsoffob, 0);
93
94   /* The long name obstack also gets its archive header.  As above,
95      some of the input strings are longer than required but we only
96      copy the necessary part.  */
97   memcpy (ar_hdr.ar_name, "//              ", sizeof (ar_hdr.ar_name));
98   memcpy (ar_hdr.ar_date, "            ", sizeof (ar_hdr.ar_date));
99   memcpy (ar_hdr.ar_uid, "            ", sizeof (ar_hdr.ar_uid));
100   memcpy (ar_hdr.ar_gid, "            ", sizeof (ar_hdr.ar_gid));
101   memcpy (ar_hdr.ar_mode, "            ", sizeof (ar_hdr.ar_mode));
102   /* The ar_size field will be filled in later and ar_fmag is already OK.  */
103   obstack_grow (&symtab.longnamesob, &ar_hdr, sizeof (ar_hdr));
104
105   /* All other members are zero.  */
106   symtab.symsofflen = 0;
107   symtab.symsoff = NULL;
108   symtab.symsnamelen = 0;
109   symtab.symsname = NULL;
110 }
111
112
113 /* Finalize ARLIB_SYMTAB content.  */
114 void
115 arlib_finalize (void)
116 {
117   char tmpbuf[sizeof (((struct ar_hdr *) NULL)->ar_size) + 1];
118
119   symtab.longnameslen = obstack_object_size (&symtab.longnamesob);
120   if (symtab.longnameslen != sizeof (struct ar_hdr))
121     {
122       if ((symtab.longnameslen & 1) != 0)
123         {
124           /* Add one more byte to make length even.  */
125           obstack_grow (&symtab.longnamesob, "\n", 1);
126           ++symtab.longnameslen;
127         }
128
129       symtab.longnames = obstack_finish (&symtab.longnamesob);
130
131       memcpy (&((struct ar_hdr *) symtab.longnames)->ar_size, tmpbuf,
132               snprintf (tmpbuf, sizeof (tmpbuf), "%-*zu",
133                         (int) sizeof (((struct ar_hdr *) NULL)->ar_size),
134                         symtab.longnameslen - sizeof (struct ar_hdr)));
135     }
136
137   symtab.symsofflen = obstack_object_size (&symtab.symsoffob);
138   assert (symtab.symsofflen % sizeof (uint32_t) == 0);
139   if (symtab.symsofflen != 0)
140     {
141       symtab.symsoff = (uint32_t *) obstack_finish (&symtab.symsoffob);
142
143       /* Fill in the number of offsets now.  */
144       symtab.symsoff[AR_HDR_WORDS] = le_bswap_32 ((symtab.symsofflen
145                                                     - sizeof (struct ar_hdr))
146                                                    / sizeof (uint32_t) - 1);
147     }
148
149   symtab.symsnamelen = obstack_object_size (&symtab.symsnameob);
150   if ((symtab.symsnamelen & 1) != 0)
151     {
152       /* Add one more NUL byte to make length even.  */
153       obstack_grow (&symtab.symsnameob, "", 1);
154       ++symtab.symsnamelen;
155     }
156   symtab.symsname = obstack_finish (&symtab.symsnameob);
157
158   /* Determine correction for the offsets in the symbol table.   */
159   off_t disp = 0;
160   if (symtab.symsnamelen > 0)
161     disp = symtab.symsofflen + symtab.symsnamelen;
162   if (symtab.longnameslen > sizeof (struct ar_hdr))
163     disp += symtab.longnameslen;
164
165   if (disp != 0 && symtab.symsoff != NULL)
166     {
167       uint32_t nsyms = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS]);
168
169       for (uint32_t cnt = 1; cnt <= nsyms; ++cnt)
170         {
171           uint32_t val = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS + cnt]);
172           val += disp;
173           symtab.symsoff[AR_HDR_WORDS + cnt] = le_bswap_32 (val);
174         }
175     }
176
177   /* See comment for ar_date above.  */
178   memcpy (&((struct ar_hdr *) symtab.symsoff)->ar_size, tmpbuf,
179           snprintf (tmpbuf, sizeof (tmpbuf), "%-*zu",
180                     (int) sizeof (((struct ar_hdr *) NULL)->ar_size),
181                     symtab.symsofflen + symtab.symsnamelen
182                     - sizeof (struct ar_hdr)));
183 }
184
185
186 /* Free resources for ARLIB_SYMTAB.  */
187 void
188 arlib_fini (void)
189 {
190   obstack_free (&symtab.symsoffob, NULL);
191   obstack_free (&symtab.symsnameob, NULL);
192   obstack_free (&symtab.longnamesob, NULL);
193 }
194
195
196 /* Add name a file offset of a symbol.  */
197 void
198 arlib_add_symref (const char *symname, off_t symoff)
199 {
200   /* For all supported platforms the following is true.  */
201   assert (sizeof (uint32_t) == sizeof (int));
202   obstack_int_grow (&symtab.symsoffob, (int) le_bswap_32 (symoff));
203
204   size_t symname_len = strlen (symname) + 1;
205   obstack_grow (&symtab.symsnameob, symname, symname_len);
206 }
207
208
209 /* Add symbols from ELF with value OFFSET to the symbol table SYMTAB.  */
210 void
211 arlib_add_symbols (Elf *elf, const char *arfname, const char *membername,
212                    off_t off)
213 {
214   if (sizeof (off) > sizeof (uint32_t) && off > ~((uint32_t) 0))
215     /* The archive is too big.  */
216     error (EXIT_FAILURE, 0, gettext ("the archive '%s' is too large"),
217            arfname);
218
219   /* We only add symbol tables for ELF files.  It makes not much sense
220      to add symbols from executables but we do so for compatibility.
221      For DSOs and executables we use the dynamic symbol table, for
222      relocatable files all the DT_SYMTAB tables.  */
223   if (elf_kind (elf) != ELF_K_ELF)
224     return;
225
226   GElf_Ehdr ehdr_mem;
227   GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
228   if (ehdr == NULL)
229     error (EXIT_FAILURE, 0, gettext ("cannot read ELF header of %s(%s): %s"),
230            arfname, membername, elf_errmsg (-1));
231
232   GElf_Word symtype;
233   if (ehdr->e_type == ET_REL)
234     symtype = SHT_SYMTAB;
235   else if (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN)
236     symtype = SHT_DYNSYM;
237   else
238     /* We do not handle that type.  */
239     return;
240
241   /* Iterate over all sections.  */
242   Elf_Scn *scn = NULL;
243   while ((scn = elf_nextscn (elf, scn)) != NULL)
244     {
245       /* Get the section header.  */
246       GElf_Shdr shdr_mem;
247       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
248       if (shdr == NULL)
249         continue;
250
251       if (shdr->sh_type != symtype)
252         continue;
253
254       Elf_Data *data = elf_getdata (scn, NULL);
255       if (data == NULL)
256         continue;
257
258       int nsyms = shdr->sh_size / shdr->sh_entsize;
259       for (int ndx = shdr->sh_info; ndx < nsyms; ++ndx)
260         {
261           GElf_Sym sym_mem;
262           GElf_Sym *sym = gelf_getsym (data, ndx, &sym_mem);
263           if (sym == NULL)
264             continue;
265
266           /* Ignore undefined symbols.  */
267           if (sym->st_shndx == SHN_UNDEF)
268             continue;
269
270           /* Use this symbol.  */
271           const char *symname = elf_strptr (elf, shdr->sh_link, sym->st_name);
272           if (symname != NULL)
273             arlib_add_symref (symname, off);
274         }
275
276       /* Only relocatable files can have more than one symbol table.  */
277       if (ehdr->e_type != ET_REL)
278         break;
279     }
280 }