Home | History | Annotate | Download | only in tests
      1 /* Test program for adding a section to an empty ELF file.
      2    Copyright (C) 2016 Red Hat, Inc.
      3    This file is part of elfutils.
      4 
      5    This file is free software; you can redistribute it and/or modify
      6    it under the terms of the GNU General Public License as published by
      7    the Free Software Foundation; either version 3 of the License, or
      8    (at your option) any later version.
      9 
     10    elfutils is distributed in the hope that it will be useful, but
     11    WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13    GNU General Public License for more details.
     14 
     15    You should have received a copy of the GNU General Public License
     16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     17 
     18 
     19 #ifdef HAVE_CONFIG_H
     20 # include <config.h>
     21 #endif
     22 
     23 #include <errno.h>
     24 #include <fcntl.h>
     25 #include <inttypes.h>
     26 #include <stdio.h>
     27 #include <stdlib.h>
     28 #include <string.h>
     29 #include <unistd.h>
     30 
     31 #include ELFUTILS_HEADER(elf)
     32 #include <gelf.h>
     33 
     34 
     35 /* Index of last string added.  Returned by add_string ().  */
     36 static size_t stridx = 0;
     37 
     38 /* Adds a string and returns the offset in the section.  */
     39 static size_t
     40 add_string (Elf_Scn *scn, char *str)
     41 {
     42   size_t lastidx = stridx;
     43   size_t size = strlen (str) + 1;
     44 
     45   Elf_Data *data = elf_newdata (scn);
     46   if (data == NULL)
     47     {
     48       printf ("cannot create data SHSTRTAB section: %s\n", elf_errmsg (-1));
     49       exit (1);
     50     }
     51 
     52   data->d_buf = str;
     53   data->d_type = ELF_T_BYTE;
     54   data->d_size = size;
     55   data->d_align = 1;
     56   data->d_version = EV_CURRENT;
     57 
     58   stridx += size;
     59   printf ("add_string: '%s', stridx: %zd, lastidx: %zd\n",
     60 	  str, stridx, lastidx);
     61   return lastidx;
     62 }
     63 
     64 static void
     65 check_elf (const char *fname, int class, int use_mmap)
     66 {
     67   printf ("\nfname: %s\n", fname);
     68   stridx = 0; // Reset strtab strings index
     69 
     70   int fd = open (fname, O_RDWR | O_CREAT | O_TRUNC, 0666);
     71   if (fd == -1)
     72     {
     73       printf ("cannot open `%s': %s\n", fname, strerror (errno));
     74       exit (1);
     75     }
     76 
     77   Elf *elf = elf_begin (fd, use_mmap ? ELF_C_WRITE_MMAP : ELF_C_WRITE, NULL);
     78   if (elf == NULL)
     79     {
     80       printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1));
     81       exit (1);
     82     }
     83 
     84   // Create an ELF header.
     85   if (gelf_newehdr (elf, class) == 0)
     86     {
     87       printf ("cannot create ELF header: %s\n", elf_errmsg (-1));
     88       exit (1);
     89     }
     90 
     91   GElf_Ehdr ehdr_mem;
     92   GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
     93   if (ehdr == NULL)
     94     {
     95       printf ("cannot get ELF header: %s\n", elf_errmsg (-1));
     96       exit (1);
     97     }
     98 
     99   // Initialize header.
    100   ehdr->e_ident[EI_DATA] = class == ELFCLASS64 ? ELFDATA2LSB : ELFDATA2MSB;
    101   ehdr->e_ident[EI_OSABI] = ELFOSABI_GNU;
    102   ehdr->e_type = ET_NONE;
    103   ehdr->e_machine = EM_X86_64;
    104   ehdr->e_version = EV_CURRENT;
    105 
    106   if (gelf_update_ehdr (elf, ehdr) == 0)
    107     {
    108       printf ("cannot update ELF header: %s\n", elf_errmsg (-1));
    109       exit (1);
    110     }
    111 
    112   // Write everything to disk.
    113   if (elf_update (elf, ELF_C_WRITE) < 0)
    114     {
    115       printf ("failure in elf_update(WRITE): %s\n", elf_errmsg (-1));
    116       exit (1);
    117     }
    118 
    119   if (elf_end (elf) != 0)
    120     {
    121       printf ("failure in elf_end: %s\n", elf_errmsg (-1));
    122       exit (1);
    123     }
    124 
    125   close (fd);
    126 
    127   /* Reread the ELF from disk now.  */
    128   fd = open (fname, O_RDWR, 0666);
    129   if (fd == -1)
    130     {
    131       printf ("cannot (re)open `%s': %s\n", fname, strerror (errno));
    132       exit (1);
    133     }
    134 
    135   elf = elf_begin (fd, use_mmap ? ELF_C_RDWR_MMAP : ELF_C_RDWR, NULL);
    136   if (elf == NULL)
    137     {
    138       printf ("cannot create ELF descriptor read-only: %s\n", elf_errmsg (-1));
    139       exit (1);
    140     }
    141 
    142   // There are no sections yet.
    143   if (elf_nextscn (elf, NULL) != NULL)
    144     {
    145       printf ("Empty elf had a section???\n");
    146       exit (1);
    147     }
    148 
    149   // Create strtab section.
    150   Elf_Scn *scn = elf_newscn (elf);
    151   if (scn == NULL)
    152     {
    153       printf ("cannot create strings section: %s\n", elf_errmsg (-1));
    154       exit (1);
    155     }
    156 
    157   // Add an empty string to the table as NUL entry for section zero.
    158   add_string (scn, "");
    159 
    160   GElf_Shdr shdr_mem;
    161   GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    162   if (shdr == NULL)
    163     {
    164       printf ("cannot get header for strings section: %s\n", elf_errmsg (-1));
    165       exit (1);
    166     }
    167 
    168   shdr->sh_type = SHT_STRTAB;
    169   shdr->sh_flags = 0;
    170   shdr->sh_addr = 0;
    171   shdr->sh_link = SHN_UNDEF;
    172   shdr->sh_info = SHN_UNDEF;
    173   shdr->sh_addralign = 1;
    174   shdr->sh_entsize = 0;
    175   shdr->sh_name = add_string (scn, ".strtab");
    176 
    177   // We have to store the section strtab index in the ELF header.
    178   // So sections have actual names.
    179   int ndx = elf_ndxscn (scn);
    180   ehdr->e_shstrndx = ndx;
    181 
    182   if (gelf_update_ehdr (elf, ehdr) == 0)
    183     {
    184       printf ("cannot update ELF header: %s\n", elf_errmsg (-1));
    185       exit (1);
    186     }
    187 
    188   // Finished strtab section, update the header.
    189   if (gelf_update_shdr (scn, shdr) == 0)
    190     {
    191       printf ("cannot update STRTAB section header: %s\n", elf_errmsg (-1));
    192       exit (1);
    193     }
    194 
    195   // Write everything to disk.
    196   if (elf_update (elf, ELF_C_WRITE) < 0)
    197     {
    198       printf ("failure in elf_update(WRITE): %s\n", elf_errmsg (-1));
    199       exit (1);
    200     }
    201 
    202   if (elf_end (elf) != 0)
    203     {
    204       printf ("failure in elf_end: %s\n", elf_errmsg (-1));
    205       exit (1);
    206     }
    207 
    208   close (fd);
    209 
    210   // And read it in one last time.
    211   fd = open (fname, O_RDONLY, 0666);
    212   if (fd == -1)
    213     {
    214       printf ("cannot open `%s' read-only: %s\n", fname, strerror (errno));
    215       exit (1);
    216     }
    217 
    218   elf = elf_begin (fd, use_mmap ? ELF_C_READ_MMAP : ELF_C_READ, NULL);
    219   if (elf == NULL)
    220     {
    221       printf ("cannot create ELF descriptor read-only: %s\n", elf_errmsg (-1));
    222       exit (1);
    223     }
    224 
    225   // Is our new section there?
    226   scn = elf_nextscn (elf, NULL);
    227   if (scn == NULL)
    228     {
    229       printf ("cannot get new section: %s\n", elf_errmsg (-1));
    230       exit (1);
    231     }
    232 
    233   shdr = gelf_getshdr (scn, &shdr_mem);
    234   if (shdr == NULL)
    235     {
    236       printf ("cannot get header for new section: %s\n", elf_errmsg (-1));
    237       exit (1);
    238     }
    239 
    240   size_t shstrndx;
    241   if (elf_getshdrstrndx (elf, &shstrndx) < 0)
    242     {
    243       printf ("elf_getshdrstrndx: %s\n", elf_errmsg (-1));
    244       exit (1);
    245     }
    246 
    247   const char *sname = elf_strptr (elf, shstrndx, shdr->sh_name);
    248   if (sname == NULL || strcmp (sname, ".strtab") != 0)
    249     {
    250       printf ("Bad section name: %s\n", sname);
    251       exit (1);
    252     }
    253 
    254   if (elf_end (elf) != 0)
    255     {
    256       printf ("failure in elf_end: %s\n", elf_errmsg (-1));
    257       exit (1);
    258     }
    259 
    260   close (fd);
    261 
    262   unlink (fname);
    263 }
    264 
    265 int
    266 main (int argc __attribute__ ((unused)),
    267       char *argv[] __attribute__ ((unused)))
    268 {
    269   elf_version (EV_CURRENT);
    270 
    271   check_elf ("empty.elf.32", ELFCLASS32, 0);
    272   check_elf ("empty.elf.32.mmap", ELFCLASS32, 1);
    273   check_elf ("empty.elf.64", ELFCLASS64, 0);
    274   check_elf ("empty.elf.64.mmap", ELFCLASS64, 1);
    275 
    276   return 0;
    277 }
    278