Home | History | Annotate | Download | only in src
      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 (at) 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
     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
    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
    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
    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
    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