Home | History | Annotate | Download | only in tests
      1 /* Copyright (C) 2015 Red Hat, Inc.
      2    This file is part of elfutils.
      3 
      4    This file is free software; you can redistribute it and/or modify
      5    it under the terms of the GNU General Public License as published by
      6    the Free Software Foundation; either version 3 of the License, or
      7    (at your option) any later version.
      8 
      9    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
     12    GNU General Public License for more details.
     13 
     14    You should have received a copy of the GNU General Public License
     15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     16 
     17 #ifdef HAVE_CONFIG_H
     18 # include <config.h>
     19 #endif
     20 
     21 #include <sys/types.h>
     22 #include <sys/stat.h>
     23 #include <fcntl.h>
     24 #include <inttypes.h>
     25 #include <libelf.h>
     26 #include <gelf.h>
     27 #include <stdbool.h>
     28 #include <stdio.h>
     29 #include <stdlib.h>
     30 #include <string.h>
     31 #include <unistd.h>
     32 
     33 
     34 int
     35 main (int argc, char *argv[])
     36 {
     37   int result = 0;
     38   int cnt;
     39 
     40   if (argc < 3
     41       || (strcmp (argv[1], "elf") != 0
     42 	  && strcmp (argv[1], "gnu") != 0))
     43     {
     44       printf ("Usage: (elf|gnu) files...\n");
     45       return -1;
     46     }
     47 
     48   int gnu;
     49   if (strcmp (argv[1], "gnu") == 0)
     50     gnu = 1;
     51   else
     52     gnu = 0;
     53 
     54   elf_version (EV_CURRENT);
     55 
     56   for (cnt = 2; cnt < argc; ++cnt)
     57     {
     58       int fd = open (argv[cnt], O_RDONLY);
     59 
     60       Elf *elf = elf_begin (fd, ELF_C_READ, NULL);
     61       if (elf == NULL)
     62 	{
     63 	  printf ("%s not usable %s\n", argv[cnt], elf_errmsg (-1));
     64 	  result = 1;
     65 	  close (fd);
     66 	  continue;
     67 	}
     68 
     69       /* To get the section names.  */
     70       size_t strndx;
     71       elf_getshdrstrndx (elf, &strndx);
     72 
     73       Elf_Scn *scn = NULL;
     74       while ((scn = elf_nextscn (elf, scn)) != NULL)
     75 	{
     76 	  size_t idx = elf_ndxscn (scn);
     77 	  GElf_Shdr mem;
     78 	  GElf_Shdr *shdr = gelf_getshdr (scn, &mem);
     79 	  const char *name = elf_strptr (elf, strndx, shdr->sh_name);
     80 	  if (shdr->sh_type == SHT_NOBITS
     81 	      || (shdr->sh_flags & SHF_ALLOC) != 0)
     82 	    {
     83 	      printf ("Cannot compress %zd %s\n", idx, name);
     84 	    }
     85 	  else if ((shdr->sh_flags & SHF_COMPRESSED) != 0
     86 		   || strncmp (name, ".zdebug", strlen (".zdebug")) == 0)
     87 	    {
     88 	      printf ("Already compressed %zd %s\n", idx, name);
     89 	    }
     90 	  else
     91 	    {
     92 	      size_t orig_size = shdr->sh_size;
     93 	      printf ("Lets compress %zd %s, size: %" PRId64 "\n",
     94 		      idx, name, shdr->sh_size);
     95 	      Elf_Data *d = elf_getdata (scn, NULL);
     96 	      if (d == NULL)
     97 		{
     98 		  printf ("Couldn't get orig data for section %zd\n", idx);
     99 		  return -1;
    100 		}
    101 	      /* Make a copy so we can compare after
    102 		 compression/decompression.  */
    103 	      if (d->d_size != orig_size)
    104 		{
    105 		  printf ("Unexpected data size for orig section %zd\n", idx);
    106 		  return -1;
    107 		}
    108 	      char *orig_buf = malloc (d->d_size);
    109 	      if (orig_size > 0 && orig_buf == NULL)
    110 		{
    111 		  printf ("No memory to copy section %zd data\n", idx);
    112 		  return -1;
    113 		}
    114 	      if (orig_size > 0)
    115 		memcpy (orig_buf, d->d_buf, orig_size);
    116 
    117 	      bool forced = false;
    118 	      if (gnu)
    119 		{
    120 		  int res = elf_compress_gnu (scn, 1, 0);
    121 		  if (res == 0)
    122 		    {
    123 		      forced = true;
    124 		      res = elf_compress_gnu (scn, 1, ELF_CHF_FORCE);
    125 		    }
    126 		  if (res < 0)
    127 		    {
    128 		      printf ("elf_compress_gnu%sfailed for section %zd: %s\n",
    129 			      forced ? " (forced) " : " ",
    130 			      idx, elf_errmsg (-1));
    131 		      return -1;
    132 		    }
    133 		}
    134 	      else
    135 		{
    136 		  int res = elf_compress (scn, ELFCOMPRESS_ZLIB, 0);
    137 		  if (res == 0)
    138 		    {
    139 		      forced = true;
    140 		      res = elf_compress (scn, ELFCOMPRESS_ZLIB, ELF_CHF_FORCE);
    141 		    }
    142 		  if (res < 0)
    143 		    {
    144 		      printf ("elf_compress%sfailed for section %zd: %s\n",
    145 			      forced ? " (forced) " : " ",
    146 			      idx, elf_errmsg (-1));
    147 		      return -1;
    148 		    }
    149 		}
    150 	      GElf_Shdr newmem;
    151 	      GElf_Shdr *newshdr = gelf_getshdr (scn, &newmem);
    152 	      size_t new_size = newshdr->sh_size;
    153 	      d = elf_getdata (scn, NULL);
    154 	      // Don't check this, might depend on zlib implementation.
    155 	      // fprintf (stderr, "  new_size: %zd\n", new_size);
    156 	      if (d->d_size != new_size)
    157 		{
    158 		  printf ("Unexpected data size for compressed section %zd\n",
    159 			  idx);
    160 		  return -1;
    161 		}
    162 
    163 	      if (forced && new_size < orig_size)
    164 		{
    165 		  printf ("section %zd forced to compress, but size smaller\n",
    166 			  idx);
    167 		  return -1;
    168 		}
    169 
    170 	      if (! forced && new_size >= orig_size)
    171 		{
    172 		  printf ("section %zd compressed to bigger size\n",
    173 			  idx);
    174 		  return -1;
    175 		}
    176 
    177 	      if (new_size == orig_size
    178 		  && memcmp (orig_buf, d->d_buf, orig_size) == 0)
    179 		{
    180 		  printf ("section %zd didn't compress\n", idx);
    181 		  return -1;
    182 		}
    183 
    184 	      if (gnu)
    185 		{
    186 		  if (elf_compress_gnu (scn, 0, 0) < 0)
    187 		    {
    188 		      printf ("elf_[un]compress_gnu failed for section %zd: %s\n",
    189 			      idx, elf_errmsg (-1));
    190 		      return -1;
    191 		    }
    192 		}
    193 	      else
    194 		{
    195 		  if (elf_compress (scn, 0, 0) < 0)
    196 		    {
    197 		      printf ("elf_[un]compress failed for section %zd: %s\n",
    198 			      idx, elf_errmsg (-1));
    199 		      return -1;
    200 		    }
    201 		}
    202 	      GElf_Shdr newermem;
    203 	      GElf_Shdr *newershdr = gelf_getshdr (scn, &newermem);
    204 	      size_t newer_size = newershdr->sh_size;
    205 	      d = elf_getdata (scn, NULL);
    206 	      // fprintf (stderr, "  newer_size: %zd\n", newer_size);
    207 	      if (d->d_size != newer_size)
    208 		{
    209 		  printf ("Unexpected data size for compressed section %zd\n",
    210 			  idx);
    211 		  return -1;
    212 		}
    213 	      if (newer_size != orig_size
    214 		  && memcmp (orig_buf, d->d_buf, orig_size) != 0)
    215 		{
    216 		  printf ("section %zd didn't correctly uncompress\n", idx);
    217 		  return -1;
    218 		}
    219 	      free (orig_buf);
    220 	      // Recompress the string table, just to make sure
    221 	      // everything keeps working. See elf_strptr above.
    222 	      if (! gnu && idx == strndx
    223 		  && elf_compress (scn, ELFCOMPRESS_ZLIB, 0) < 0)
    224 		{
    225 		  printf ("couldn't recompress section header strings: %s\n",
    226 			  elf_errmsg (-1));
    227 		  return -1;
    228 		}
    229 	    }
    230 	}
    231 
    232       elf_end (elf);
    233       close (fd);
    234     }
    235 
    236   return result;
    237 }
    238