• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Functions to handle creation of Linux archives.
2    Copyright (C) 2007-2012, 2016 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 <gelf.h>
25 #include <inttypes.h>
26 #include <libintl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <time.h>
30 
31 #include <libeu.h>
32 
33 #include "system.h"
34 #include "arlib.h"
35 
36 
37 /* The one symbol table we hanble.  */
38 struct arlib_symtab symtab;
39 
40 
41 /* Initialize ARLIB_SYMTAB structure.  */
42 void
arlib_init(void)43 arlib_init (void)
44 {
45 #define obstack_chunk_alloc xmalloc
46 #define obstack_chunk_free free
47   obstack_init (&symtab.symsoffob);
48   obstack_init (&symtab.symsnameob);
49   obstack_init (&symtab.longnamesob);
50 
51   /* We add the archive header here as well, that avoids allocating
52      another memory block.  */
53   struct ar_hdr ar_hdr;
54   memcpy (ar_hdr.ar_name, "/               ", sizeof (ar_hdr.ar_name));
55   /* Using snprintf here has a problem: the call always wants to add a
56      NUL byte.  We could use a trick whereby we specify the target
57      buffer size longer than it is and this would not actually fail,
58      since all the fields are consecutive and we fill them in
59      sequence (i.e., the NUL byte gets overwritten).  But
60      _FORTIFY_SOURCE=2 would not let us play these games.  Therefore
61      we play it safe.  */
62   char tmpbuf[sizeof (ar_hdr.ar_date) + 1];
63   int s = snprintf (tmpbuf, sizeof (tmpbuf), "%-*lld",
64 		    (int) sizeof (ar_hdr.ar_date),
65                     (arlib_deterministic_output ? 0
66                      : (long long int) time (NULL)));
67   memcpy (ar_hdr.ar_date, tmpbuf, s);
68   assert ((sizeof (struct ar_hdr)  % sizeof (uint32_t)) == 0);
69 
70   /* Note the string for the ar_uid and ar_gid cases is longer than
71      necessary.  This does not matter since we copy only as much as
72      necessary but it helps the compiler to use the same string for
73      the ar_mode case.  */
74   memcpy (ar_hdr.ar_uid, "0       ", sizeof (ar_hdr.ar_uid));
75   memcpy (ar_hdr.ar_gid, "0       ", sizeof (ar_hdr.ar_gid));
76   memcpy (ar_hdr.ar_mode, "0       ", sizeof (ar_hdr.ar_mode));
77   memcpy (ar_hdr.ar_fmag, ARFMAG, sizeof (ar_hdr.ar_fmag));
78 
79   /* Add the archive header to the file content.  */
80   obstack_grow (&symtab.symsoffob, &ar_hdr, sizeof (ar_hdr));
81 
82   /* The first word in the offset table specifies the size.  Create
83      such an entry now.  The real value will be filled-in later.  For
84      all supported platforms the following is true.  */
85   assert (sizeof (uint32_t) == sizeof (int));
86   obstack_int_grow (&symtab.symsoffob, 0);
87 
88   /* The long name obstack also gets its archive header.  As above,
89      some of the input strings are longer than required but we only
90      copy the necessary part.  */
91   memcpy (ar_hdr.ar_name, "//              ", sizeof (ar_hdr.ar_name));
92   memcpy (ar_hdr.ar_date, "            ", sizeof (ar_hdr.ar_date));
93   memcpy (ar_hdr.ar_uid, "            ", sizeof (ar_hdr.ar_uid));
94   memcpy (ar_hdr.ar_gid, "            ", sizeof (ar_hdr.ar_gid));
95   memcpy (ar_hdr.ar_mode, "            ", sizeof (ar_hdr.ar_mode));
96   /* The ar_size field will be filled in later and ar_fmag is already OK.  */
97   obstack_grow (&symtab.longnamesob, &ar_hdr, sizeof (ar_hdr));
98 
99   /* All other members are zero.  */
100   symtab.symsofflen = 0;
101   symtab.symsoff = NULL;
102   symtab.symsnamelen = 0;
103   symtab.symsname = NULL;
104 }
105 
106 
107 /* Finalize ARLIB_SYMTAB content.  */
108 void
arlib_finalize(void)109 arlib_finalize (void)
110 {
111   /* Note that the size is stored as decimal string in 10 chars,
112      without zero terminator (we add + 1 here only so snprintf can
113      put it at the end, we then don't use it when we memcpy it).  */
114   char tmpbuf[sizeof (((struct ar_hdr *) NULL)->ar_size) + 1];
115 
116   symtab.longnameslen = obstack_object_size (&symtab.longnamesob);
117   if (symtab.longnameslen != sizeof (struct ar_hdr))
118     {
119       if ((symtab.longnameslen & 1) != 0)
120 	{
121 	  /* Add one more byte to make length even.  */
122 	  obstack_grow (&symtab.longnamesob, "\n", 1);
123 	  ++symtab.longnameslen;
124 	}
125 
126       symtab.longnames = obstack_finish (&symtab.longnamesob);
127 
128       int s = snprintf (tmpbuf, sizeof (tmpbuf), "%-*" PRIu32 "",
129 			(int) sizeof (((struct ar_hdr *) NULL)->ar_size),
130 			(uint32_t) (symtab.longnameslen - sizeof (struct ar_hdr)));
131       memcpy (&((struct ar_hdr *) symtab.longnames)->ar_size, tmpbuf, s);
132     }
133 
134   symtab.symsofflen = obstack_object_size (&symtab.symsoffob);
135   assert (symtab.symsofflen % sizeof (uint32_t) == 0);
136   if (symtab.symsofflen != 0)
137     {
138       symtab.symsoff = (uint32_t *) obstack_finish (&symtab.symsoffob);
139 
140       /* Fill in the number of offsets now.  */
141       symtab.symsoff[AR_HDR_WORDS] = le_bswap_32 ((symtab.symsofflen
142 						    - sizeof (struct ar_hdr))
143 						   / sizeof (uint32_t) - 1);
144     }
145 
146   symtab.symsnamelen = obstack_object_size (&symtab.symsnameob);
147   if ((symtab.symsnamelen & 1) != 0)
148     {
149       /* Add one more NUL byte to make length even.  */
150       obstack_grow (&symtab.symsnameob, "", 1);
151       ++symtab.symsnamelen;
152     }
153   symtab.symsname = obstack_finish (&symtab.symsnameob);
154 
155   /* Determine correction for the offsets in the symbol table.   */
156   off_t disp = 0;
157   if (symtab.symsnamelen > 0)
158     disp = symtab.symsofflen + symtab.symsnamelen;
159   if (symtab.longnameslen > sizeof (struct ar_hdr))
160     disp += symtab.longnameslen;
161 
162   if (disp != 0 && symtab.symsoff != NULL)
163     {
164       uint32_t nsyms = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS]);
165 
166       for (uint32_t cnt = 1; cnt <= nsyms; ++cnt)
167 	{
168 	  uint32_t val = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS + cnt]);
169 	  val += disp;
170 	  symtab.symsoff[AR_HDR_WORDS + cnt] = le_bswap_32 (val);
171 	}
172     }
173 
174   /* See comment for ar_date above.  */
175   memcpy (&((struct ar_hdr *) symtab.symsoff)->ar_size, tmpbuf,
176 	  snprintf (tmpbuf, sizeof (tmpbuf), "%-*" PRIu32 "",
177 		    (int) sizeof (((struct ar_hdr *) NULL)->ar_size),
178 		    (uint32_t) (symtab.symsofflen + symtab.symsnamelen
179 				- sizeof (struct ar_hdr))));
180 }
181 
182 
183 /* Free resources for ARLIB_SYMTAB.  */
184 void
arlib_fini(void)185 arlib_fini (void)
186 {
187   obstack_free (&symtab.symsoffob, NULL);
188   obstack_free (&symtab.symsnameob, NULL);
189   obstack_free (&symtab.longnamesob, NULL);
190 }
191 
192 
193 /* Add name a file offset of a symbol.  */
194 void
arlib_add_symref(const char * symname,off_t symoff)195 arlib_add_symref (const char *symname, off_t symoff)
196 {
197   /* For all supported platforms the following is true.  */
198   assert (sizeof (uint32_t) == sizeof (int));
199   obstack_int_grow (&symtab.symsoffob, (int) le_bswap_32 (symoff));
200 
201   size_t symname_len = strlen (symname) + 1;
202   obstack_grow (&symtab.symsnameob, symname, symname_len);
203 }
204 
205 
206 /* Add symbols from ELF with value OFFSET to the symbol table SYMTAB.  */
207 void
arlib_add_symbols(Elf * elf,const char * arfname,const char * membername,off_t off)208 arlib_add_symbols (Elf *elf, const char *arfname, const char *membername,
209 		   off_t off)
210 {
211   if (sizeof (off) > sizeof (uint32_t) && off > ~((uint32_t) 0))
212     /* The archive is too big.  */
213     error (EXIT_FAILURE, 0, gettext ("the archive '%s' is too large"),
214 	   arfname);
215 
216   /* We only add symbol tables for ELF files.  It makes not much sense
217      to add symbols from executables but we do so for compatibility.
218      For DSOs and executables we use the dynamic symbol table, for
219      relocatable files all the DT_SYMTAB tables.  */
220   if (elf_kind (elf) != ELF_K_ELF)
221     return;
222 
223   GElf_Ehdr ehdr_mem;
224   GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
225   if (ehdr == NULL)
226     error (EXIT_FAILURE, 0, gettext ("cannot read ELF header of %s(%s): %s"),
227 	   arfname, membername, elf_errmsg (-1));
228 
229   GElf_Word symtype;
230   if (ehdr->e_type == ET_REL)
231     symtype = SHT_SYMTAB;
232   else if (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN)
233     symtype = SHT_DYNSYM;
234   else
235     /* We do not handle that type.  */
236     return;
237 
238   /* Iterate over all sections.  */
239   Elf_Scn *scn = NULL;
240   while ((scn = elf_nextscn (elf, scn)) != NULL)
241     {
242       /* Get the section header.  */
243       GElf_Shdr shdr_mem;
244       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
245       if (shdr == NULL)
246 	continue;
247 
248       if (shdr->sh_type != symtype)
249 	continue;
250 
251       Elf_Data *data = elf_getdata (scn, NULL);
252       if (data == NULL)
253 	continue;
254 
255       if (shdr->sh_entsize == 0)
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 }
281