Home | History | Annotate | Download | only in src
      1 /* Functions to handle creation of Linux archives.
      2    Copyright (C) 2007-2012 Red Hat, Inc.
      3    Written by Ulrich Drepper <drepper (at) 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 }
    281