Home | History | Annotate | Download | only in tests
      1 /* Test program for elf_strptr function.
      2    Copyright (C) 2015 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 #ifdef HAVE_CONFIG_H
     19 # include <config.h>
     20 #endif
     21 
     22 #include <errno.h>
     23 #include <fcntl.h>
     24 #include <inttypes.h>
     25 #include <stdio.h>
     26 #include <stdlib.h>
     27 #include <string.h>
     28 #include <unistd.h>
     29 
     30 #include ELFUTILS_HEADER(elf)
     31 #include <gelf.h>
     32 
     33 
     34 /* Index of last string added.  Returned by add_string ().  */
     35 static size_t stridx = 0;
     36 
     37 /* Some random strings.  */
     38 static char *str1;
     39 static size_t str1_off;
     40 static char *str2;
     41 static size_t str2_off;
     42 static char *str3;
     43 static size_t str3_off;
     44 
     45 /* First three strings we write out. They should always be there.  */
     46 static char *orig_str1;
     47 static size_t orig_str1_off;
     48 static char *orig_str2;
     49 static size_t orig_str2_off;
     50 static char *orig_str3;
     51 static size_t orig_str3_off;
     52 
     53 static void
     54 check_orig_strings (Elf *elf, int ndx, const char *msg)
     55 {
     56   printf ("checking orig strings: %s\n", msg);
     57 
     58   const char *str = elf_strptr (elf, ndx, 0);
     59   printf ("\t'%s'\n", str);
     60   if (str == NULL || strcmp ("", str) != 0)
     61     exit (1);
     62 
     63   str = elf_strptr (elf, ndx, 1);
     64   printf ("\t'%s'\n", str);
     65   if (str == NULL || strcmp (".strings", str) != 0)
     66     exit (1);
     67 
     68   str = elf_strptr (elf, ndx, orig_str1_off);
     69   printf ("\t'%s'\n", str);
     70   if (str == NULL || strcmp (orig_str1, str) != 0)
     71     exit (1);
     72 
     73   str = elf_strptr (elf, ndx, orig_str2_off);
     74   printf ("\t'%s'\n", str);
     75   if (str == NULL || strcmp (orig_str2, str) != 0)
     76     exit (1);
     77 
     78   str = elf_strptr (elf, ndx, orig_str3_off);
     79   printf ("\t'%s'\n", str);
     80   if (str == NULL || strcmp (orig_str3, str) != 0)
     81     exit (1);
     82 }
     83 
     84 static void
     85 check_strings (Elf *elf, int ndx, const char *msg)
     86 {
     87   check_orig_strings (elf, ndx, msg);
     88 
     89   const char *str = elf_strptr (elf, ndx, str1_off);
     90   printf ("\t'%s'\n", str);
     91   if (str == NULL || strcmp (str1, str) != 0)
     92     exit (1);
     93 
     94   str = elf_strptr (elf, ndx, str2_off);
     95   printf ("\t'%s'\n", str);
     96   if (str == NULL || strcmp (str2, str) != 0)
     97     exit (1);
     98 
     99   str = elf_strptr (elf, ndx, str3_off);
    100   printf ("\t'%s'\n", str);
    101   if (str == NULL || strcmp (str3, str) != 0)
    102     exit (1);
    103 }
    104 
    105 /* Adds a string and returns the offset in the section.  */
    106 static size_t
    107 add_string (Elf_Scn *scn, char *str)
    108 {
    109   size_t lastidx = stridx;
    110   size_t size = strlen (str) + 1;
    111 
    112   Elf_Data *data = elf_newdata (scn);
    113   if (data == NULL)
    114     {
    115       printf ("cannot create data SHSTRTAB section: %s\n", elf_errmsg (-1));
    116       exit (1);
    117     }
    118 
    119   data->d_buf = str;
    120   data->d_type = ELF_T_BYTE;
    121   data->d_size = size;
    122   data->d_align = 1;
    123   data->d_version = EV_CURRENT;
    124 
    125   stridx += size;
    126   printf ("add_string: '%s', stridx: %zd, lastidx: %zd\n",
    127 	  str, stridx, lastidx);
    128   return lastidx;
    129 }
    130 
    131 static void
    132 check_elf (const char *fname, int class, int use_mmap)
    133 {
    134   printf ("\nfname: %s\n", fname);
    135   stridx = 0;
    136 
    137   int fd = open (fname, O_RDWR | O_CREAT | O_TRUNC, 0666);
    138   if (fd == -1)
    139     {
    140       printf ("cannot open `%s': %s\n", fname, strerror (errno));
    141       exit (1);
    142     }
    143 
    144   Elf *elf = elf_begin (fd, use_mmap ? ELF_C_WRITE_MMAP : ELF_C_WRITE, NULL);
    145   if (elf == NULL)
    146     {
    147       printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1));
    148       exit (1);
    149     }
    150 
    151   // Create an ELF header.
    152   if (gelf_newehdr (elf, class) == 0)
    153     {
    154       printf ("cannot create ELF header: %s\n", elf_errmsg (-1));
    155       exit (1);
    156     }
    157 
    158   GElf_Ehdr ehdr_mem;
    159   GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
    160   if (ehdr == NULL)
    161     {
    162       printf ("cannot get ELF header: %s\n", elf_errmsg (-1));
    163       exit (1);
    164     }
    165 
    166   // Initialize header.
    167   ehdr->e_ident[EI_DATA] = class == ELFCLASS64 ? ELFDATA2LSB : ELFDATA2MSB;
    168   ehdr->e_ident[EI_OSABI] = ELFOSABI_GNU;
    169   ehdr->e_type = ET_NONE;
    170   ehdr->e_machine = EM_X86_64;
    171   ehdr->e_version = EV_CURRENT;
    172 
    173   // Create strings section.
    174   Elf_Scn *scn = elf_newscn (elf);
    175   if (scn == NULL)
    176     {
    177       printf ("cannot create strings section: %s\n", elf_errmsg (-1));
    178       exit (1);
    179     }
    180 
    181   // Add an empty string to the table as NUL entry for section zero.
    182   add_string (scn, "");
    183 
    184   GElf_Shdr shdr_mem;
    185   GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    186   if (shdr == NULL)
    187     {
    188       printf ("cannot get header for strings section: %s\n", elf_errmsg (-1));
    189       exit (1);
    190     }
    191 
    192   shdr->sh_type = SHT_STRTAB;
    193   shdr->sh_flags = 0;
    194   shdr->sh_addr = 0;
    195   shdr->sh_link = SHN_UNDEF;
    196   shdr->sh_info = SHN_UNDEF;
    197   shdr->sh_addralign = 1;
    198   shdr->sh_entsize = 0;
    199   shdr->sh_name = add_string (scn, ".strings");
    200 
    201   // We have to store the section strtab index in the ELF header.
    202   // So sections have actual names.
    203   int ndx = elf_ndxscn (scn);
    204   ehdr->e_shstrndx = ndx;
    205 
    206   if (gelf_update_ehdr (elf, ehdr) == 0)
    207     {
    208       printf ("cannot update ELF header: %s\n", elf_errmsg (-1));
    209       exit (1);
    210     }
    211 
    212   // Add some random strings. These are the original ones. They should
    213   // always be there (together with the empty "" and .strings section
    214   // name strings.
    215   orig_str1 = "elfutils";
    216   orig_str1_off = add_string (scn, orig_str1);
    217   orig_str2 = "strtabelf";
    218   orig_str2_off = add_string (scn, orig_str2);
    219   orig_str3 = "three";
    220   orig_str3_off = add_string (scn, orig_str3);
    221 
    222   // Finished strings section, update the header.
    223   if (gelf_update_shdr (scn, shdr) == 0)
    224     {
    225       printf ("cannot update STRTAB section header: %s\n", elf_errmsg (-1));
    226       exit (1);
    227     }
    228 
    229   // Let the library compute the internal structure information.
    230   if (elf_update (elf, ELF_C_NULL) < 0)
    231     {
    232       printf ("failure in elf_update(NULL): %s\n", elf_errmsg (-1));
    233       exit (1);
    234     }
    235 
    236   // Check our strings are there.
    237   check_orig_strings (elf, ndx, "first elf_update, before write");
    238 
    239   // Write everything to disk.
    240   if (elf_update (elf, ELF_C_WRITE) < 0)
    241     {
    242       printf ("failure in elf_update(WRITE): %s\n", elf_errmsg (-1));
    243       exit (1);
    244     }
    245 
    246   // Check out strings are there.
    247   check_orig_strings (elf, ndx, "first elf_update, after write");
    248 
    249   // Add some more random strings.  These will not be written to disk.
    250   scn = elf_getscn (elf, ndx);
    251   if (scn == NULL)
    252     {
    253       printf ("couldn't re-get strings section: %s\n", elf_errmsg (-1));
    254       exit (1);
    255     }
    256 
    257   str1 = "elfutils2";
    258   str1_off = add_string (scn, str1);
    259   str2 = "strtabelf2";
    260   str2_off = add_string (scn, str2);
    261   str3 = "three2";
    262   str3_off = add_string (scn, str3);
    263 
    264   // Update internal structure information again.
    265   if (elf_update (elf, ELF_C_NULL) < 0)
    266     {
    267       printf ("failure in re-elf_update(NULL): %s\n", elf_errmsg (-1));
    268       exit (1);
    269     }
    270 
    271   // Check our new strings are there.
    272   check_strings (elf, ndx, "first extra strings");
    273 
    274   if (elf_end (elf) != 0)
    275     {
    276       printf ("failure in elf_end: %s\n", elf_errmsg (-1));
    277       exit (1);
    278     }
    279 
    280   close (fd);
    281 
    282   /* Read the ELF from disk now.  */
    283   fd = open (fname, O_RDWR, 0666);
    284   if (fd == -1)
    285     {
    286       printf ("cannot open `%s' read-only: %s\n", fname, strerror (errno));
    287       exit (1);
    288     }
    289 
    290   elf = elf_begin (fd, use_mmap ? ELF_C_RDWR_MMAP : ELF_C_RDWR, NULL);
    291   if (elf == NULL)
    292     {
    293       printf ("cannot create ELF descriptor read-only: %s\n", elf_errmsg (-1));
    294       exit (1);
    295     }
    296 
    297   /* Are our strings there?  */
    298   check_orig_strings (elf, ndx, "read ELF file, orig strings");
    299 
    300   // Add some more random strings.
    301   scn = elf_getscn (elf, ndx);
    302   if (scn == NULL)
    303     {
    304       printf ("couldn't re-get strings section: %s\n", elf_errmsg (-1));
    305       exit (1);
    306     }
    307 
    308   shdr = gelf_getshdr (scn, &shdr_mem);
    309   if (shdr == NULL)
    310     {
    311       printf ("cannot get header for strings section: %s\n", elf_errmsg (-1));
    312       exit (1);
    313     }
    314 
    315   // Reset stridx to end of section.
    316   printf ("sh_size: %" PRIu64 "\n", shdr->sh_size);
    317   stridx = shdr->sh_size;
    318 
    319   str1 = "0123456789";
    320   str1_off = add_string (scn, str1);
    321   str2 = "supercalifragilisticexpialidocious";
    322   str2_off = add_string (scn, str2);
    323   str3 = "forty-two";
    324   str3_off = add_string (scn, str3);
    325 
    326   // Update internal structure information.
    327   if (elf_update (elf, ELF_C_NULL) < 0)
    328     {
    329       printf ("failure in rw-elf_update(NULL): %s\n", elf_errmsg (-1));
    330       exit (1);
    331     }
    332 
    333   /* Check our new strings are there.  */
    334   check_strings (elf, ndx, "read file, added strings");
    335 
    336   // Write updated ELF file.
    337   if (elf_update (elf, ELF_C_WRITE) < 0)
    338     {
    339       printf ("failure in re-elf_update(NULL): %s\n", elf_errmsg (-1));
    340       exit (1);
    341     }
    342 
    343   if (elf_end (elf) != 0)
    344     {
    345       printf ("failure in elf_end: %s\n", elf_errmsg (-1));
    346       exit (1);
    347     }
    348 
    349   close (fd);
    350 
    351   // And read it in one last time.
    352   fd = open (fname, O_RDONLY, 0666);
    353   if (fd == -1)
    354     {
    355       printf ("cannot open `%s' read-only: %s\n", fname, strerror (errno));
    356       exit (1);
    357     }
    358 
    359   elf = elf_begin (fd, use_mmap ? ELF_C_READ_MMAP : ELF_C_READ, NULL);
    360   if (elf == NULL)
    361     {
    362       printf ("cannot create ELF descriptor read-only: %s\n", elf_errmsg (-1));
    363       exit (1);
    364     }
    365 
    366   /* Are all our strings there?  */
    367   check_strings (elf, ndx, "all together now");
    368 
    369   if (elf_end (elf) != 0)
    370     {
    371       printf ("failure in elf_end: %s\n", elf_errmsg (-1));
    372       exit (1);
    373     }
    374 
    375   close (fd);
    376 
    377   unlink (fname);
    378 }
    379 
    380 int
    381 main (int argc __attribute__ ((unused)), char *argv[] __attribute__ ((unused)))
    382 {
    383   elf_version (EV_CURRENT);
    384 
    385   // Fill holes with something non-zero to more easily spot
    386   // unterminated strings.
    387   elf_fill ('X');
    388 
    389   check_elf ("strtab.elf.32", ELFCLASS32, 0);
    390   check_elf ("strtab.elf.32.mmap", ELFCLASS32, 1);
    391   check_elf ("strtab.elf.64", ELFCLASS64, 0);
    392   check_elf ("strtab.elf.64.mmap", ELFCLASS64, 1);
    393 
    394   return 0;
    395 }
    396 
    397