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