• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Compress or decompress an ELF file.
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 #include <config.h>
19 #include <assert.h>
20 #include <argp.h>
21 #include <error.h>
22 #include <stdbool.h>
23 #include <stdlib.h>
24 #include <inttypes.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <locale.h>
28 #include <fcntl.h>
29 #include <fnmatch.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
33 #include ELFUTILS_HEADER(elf)
34 #include ELFUTILS_HEADER(ebl)
35 #include <gelf.h>
36 #include "system.h"
37 
38 /* Name and version of program.  */
39 static void print_version (FILE *stream, struct argp_state *state);
40 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
41 
42 /* Bug report address.  */
43 ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
44 
45 static int verbose = 0; /* < 0, no warnings, > 0 extra verbosity.  */
46 static bool force = false;
47 static bool permissive = false;
48 static const char *foutput = NULL;
49 
50 #define T_UNSET 0
51 #define T_DECOMPRESS 1    /* none */
52 #define T_COMPRESS_ZLIB 2 /* zlib */
53 #define T_COMPRESS_GNU  3 /* zlib-gnu */
54 static int type = T_UNSET;
55 
56 static void
print_version(FILE * stream,struct argp_state * state)57 print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
58 {
59   fprintf (stream, "elfcompress (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
60 }
61 
62 struct section_pattern
63 {
64   char *pattern;
65   struct section_pattern *next;
66 };
67 
68 static struct section_pattern *patterns = NULL;
69 
70 static void
add_pattern(const char * pattern)71 add_pattern (const char *pattern)
72 {
73   struct section_pattern *p = xmalloc (sizeof *p);
74   p->pattern = xstrdup (pattern);
75   p->next = patterns;
76   patterns = p;
77 }
78 
79 static void
free_patterns(void)80 free_patterns (void)
81 {
82   struct section_pattern *pattern = patterns;
83   while (pattern != NULL)
84     {
85       struct section_pattern *p = pattern;
86       pattern = p->next;
87       free (p->pattern);
88       free (p);
89     }
90 }
91 
92 static error_t
parse_opt(int key,char * arg,struct argp_state * state)93 parse_opt (int key, char *arg __attribute__ ((unused)),
94 	   struct argp_state *state __attribute__ ((unused)))
95 {
96   switch (key)
97     {
98     case 'v':
99       verbose++;
100       break;
101 
102     case 'q':
103       verbose--;
104 
105     case 'f':
106       force = true;
107       break;
108 
109     case 'p':
110       permissive = true;
111       break;
112 
113     case 'n':
114       add_pattern (arg);
115       break;
116 
117     case 'o':
118       if (foutput != NULL)
119 	argp_error (state, N_("-o option specified twice"));
120       else
121 	foutput = arg;
122       break;
123 
124     case 't':
125       if (type != T_UNSET)
126 	argp_error (state, N_("-t option specified twice"));
127 
128       if (strcmp ("none", arg) == 0)
129 	type = T_DECOMPRESS;
130       else if (strcmp ("zlib", arg) == 0 || strcmp ("zlib-gabi", arg) == 0)
131 	type = T_COMPRESS_ZLIB;
132       else if (strcmp ("zlib-gnu", arg) == 0 || strcmp ("gnu", arg) == 0)
133 	type = T_COMPRESS_GNU;
134       else
135 	argp_error (state, N_("unknown compression type '%s'"), arg);
136       break;
137 
138     case ARGP_KEY_SUCCESS:
139       if (type == T_UNSET)
140 	type = T_COMPRESS_ZLIB;
141       if (patterns == NULL)
142 	add_pattern (".?(z)debug*");
143       break;
144 
145     case ARGP_KEY_NO_ARGS:
146       /* We need at least one input file.  */
147       argp_error (state, N_("No input file given"));
148       break;
149 
150     case ARGP_KEY_ARGS:
151       if (foutput != NULL && state->argc - state->next > 1)
152 	argp_error (state,
153 		    N_("Only one input file allowed together with '-o'"));
154       /* We only use this for checking the number of arguments, we don't
155 	 actually want to consume them, so fallthrough.  */
156     default:
157       return ARGP_ERR_UNKNOWN;
158     }
159   return 0;
160 }
161 
162 static bool
section_name_matches(const char * name)163 section_name_matches (const char *name)
164 {
165   struct section_pattern *pattern = patterns;
166   while (pattern != NULL)
167     {
168       if (fnmatch (pattern->pattern, name, FNM_EXTMATCH) == 0)
169 	return true;
170       pattern = pattern->next;
171     }
172   return false;
173 }
174 
175 static int
setshdrstrndx(Elf * elf,GElf_Ehdr * ehdr,size_t ndx)176 setshdrstrndx (Elf *elf, GElf_Ehdr *ehdr, size_t ndx)
177 {
178   if (ndx < SHN_LORESERVE)
179     ehdr->e_shstrndx = ndx;
180   else
181     {
182       ehdr->e_shstrndx = SHN_XINDEX;
183       Elf_Scn *zscn = elf_getscn (elf, 0);
184       GElf_Shdr zshdr_mem;
185       GElf_Shdr *zshdr = gelf_getshdr (zscn, &zshdr_mem);
186       if (zshdr == NULL)
187 	return -1;
188       zshdr->sh_link = ndx;
189       if (gelf_update_shdr (zscn, zshdr) == 0)
190 	return -1;
191     }
192 
193   if (gelf_update_ehdr (elf, ehdr) == 0)
194     return -1;
195 
196   return 0;
197 }
198 
199 static int
compress_section(Elf_Scn * scn,size_t orig_size,const char * name,const char * newname,size_t ndx,bool gnu,bool compress,bool report_verbose)200 compress_section (Elf_Scn *scn, size_t orig_size, const char *name,
201 		  const char *newname, size_t ndx,
202 		  bool gnu, bool compress, bool report_verbose)
203 {
204   int res;
205   unsigned int flags = compress && force ? ELF_CHF_FORCE : 0;
206   if (gnu)
207     res = elf_compress_gnu (scn, compress ? 1 : 0, flags);
208   else
209     res = elf_compress (scn, compress ? ELFCOMPRESS_ZLIB : 0, flags);
210 
211   if (res < 0)
212     error (0, 0, "Couldn't decompress section [%zd] %s: %s",
213 	   ndx, name, elf_errmsg (-1));
214   else
215     {
216       if (compress && res == 0)
217 	{
218 	  if (verbose >= 0)
219 	    printf ("[%zd] %s NOT compressed, wouldn't be smaller\n",
220 		    ndx, name);
221 	}
222 
223       if (report_verbose && res > 0)
224 	{
225 	  printf ("[%zd] %s %s", ndx, name,
226 		  compress ? "compressed" : "decompressed");
227 	  if (newname != NULL)
228 	    printf (" -> %s", newname);
229 
230 	  /* Reload shdr, it has changed.  */
231 	  GElf_Shdr shdr_mem;
232 	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
233 	  if (shdr == NULL)
234 	    {
235 	      error (0, 0, "Couldn't get shdr for section [%zd]", ndx);
236 	      return -1;
237 	    }
238 	  float new = shdr->sh_size;
239 	  float orig = orig_size ?: 1;
240 	  printf (" (%zu => %" PRIu64 " %.2f%%)\n",
241 		  orig_size, shdr->sh_size, (new / orig) * 100);
242 	}
243     }
244 
245   return res;
246 }
247 
248 static int
process_file(const char * fname)249 process_file (const char *fname)
250 {
251   if (verbose > 0)
252     printf ("processing: %s\n", fname);
253 
254   /* The input ELF.  */
255   int fd = -1;
256   Elf *elf = NULL;
257 
258   /* The output ELF.  */
259   char *fnew = NULL;
260   int fdnew = -1;
261   Elf *elfnew = NULL;
262 
263   /* Buffer for (one) new section name if necessary.  */
264   char *snamebuf = NULL;
265 
266   /* String table (and symbol table), if section names need adjusting.  */
267   struct Ebl_Strtab *names = NULL;
268   struct Ebl_Strent **scnstrents = NULL;
269   struct Ebl_Strent **symstrents = NULL;
270   char **scnnames = NULL;
271 
272   /* Section data from names.  */
273   void *namesbuf = NULL;
274 
275   /* Which sections match and need to be (un)compressed.  */
276   unsigned int *sections = NULL;
277 
278   /* How many sections are we talking about?  */
279   size_t shnum = 0;
280 
281 #define WORD_BITS (8U * sizeof (unsigned int))
282   void set_section (size_t ndx)
283   {
284     sections[ndx / WORD_BITS] |= (1U << (ndx % WORD_BITS));
285   }
286 
287   bool get_section (size_t ndx)
288   {
289     return (sections[ndx / WORD_BITS] & (1U << (ndx % WORD_BITS))) != 0;
290   }
291 
292   int cleanup (int res)
293   {
294     elf_end (elf);
295     close (fd);
296 
297     elf_end (elfnew);
298     close (fdnew);
299 
300     if (fnew != NULL)
301       {
302 	unlink (fnew);
303 	free (fnew);
304 	fnew = NULL;
305       }
306 
307     free (snamebuf);
308     if (names != NULL)
309       {
310 	ebl_strtabfree (names);
311 	free (scnstrents);
312 	free (symstrents);
313 	free (namesbuf);
314 	if (scnnames != NULL)
315 	  {
316 	    for (size_t n = 0; n < shnum; n++)
317 	      free (scnnames[n]);
318 	    free (scnnames);
319 	  }
320       }
321 
322     free (sections);
323 
324     return res;
325   }
326 
327   fd = open (fname, O_RDONLY);
328   if (fd < 0)
329     {
330       error (0, errno, "Couldn't open %s\n", fname);
331       return cleanup (-1);
332     }
333 
334   elf = elf_begin (fd, ELF_C_READ, NULL);
335   if (elf == NULL)
336     {
337       error (0, 0, "Couldn't open ELF file %s for reading: %s",
338 	     fname, elf_errmsg (-1));
339       return cleanup (-1);
340     }
341 
342   /* We dont' handle ar files (or anything else), we probably should.  */
343   Elf_Kind kind = elf_kind (elf);
344   if (kind != ELF_K_ELF)
345     {
346       if (kind == ELF_K_AR)
347 	error (0, 0, "Cannot handle ar files: %s", fname);
348       else
349 	error (0, 0, "Unknown file type: %s", fname);
350       return cleanup (-1);
351     }
352 
353   struct stat st;
354   if (fstat (fd, &st) != 0)
355     {
356       error (0, errno, "Couldn't fstat %s", fname);
357       return cleanup (-1);
358     }
359 
360   GElf_Ehdr ehdr;
361   if (gelf_getehdr (elf, &ehdr) == NULL)
362     {
363       error (0, 0, "Couldn't get ehdr for %s: %s", fname, elf_errmsg (-1));
364       return cleanup (-1);
365     }
366 
367   /* Get the section header string table.  */
368   size_t shdrstrndx;
369   if (elf_getshdrstrndx (elf, &shdrstrndx) != 0)
370     {
371       error (0, 0, "Couldn't get section header string table index in %s: %s",
372 	     fname, elf_errmsg (-1));
373       return cleanup (-1);
374     }
375 
376   /* How many sections are we talking about?  */
377   if (elf_getshdrnum (elf, &shnum) != 0)
378     {
379       error (0, 0, "Couldn't get number of sections in %s: %s",
380 	     fname, elf_errmsg (1));
381       return cleanup (-1);
382     }
383 
384   if (shnum == 0)
385     {
386       error (0, 0, "ELF file %s has no sections", fname);
387       return cleanup (-1);
388     }
389 
390   sections = xcalloc (shnum / 8 + 1, sizeof (unsigned int));
391 
392   size_t phnum;
393   if (elf_getphdrnum (elf, &phnum) != 0)
394     {
395       error (0, 0, "Couldn't get phdrnum: %s", elf_errmsg (-1));
396       return cleanup (-1);
397     }
398 
399   /* Whether we need to adjust any section names (going to/from GNU
400      naming).  If so we'll need to build a new section header string
401      table.  */
402   bool adjust_names = false;
403 
404   /* If there are phdrs we want to maintain the layout of the
405      allocated sections in the file.  */
406   bool layout = phnum != 0;
407 
408   /* While going through all sections keep track of last section data
409      offset if needed to keep the layout.  We are responsible for
410      adding the section offsets and headers (e_shoff) in that case
411      (which we will place after the last section).  */
412   GElf_Off last_offset = 0;
413   if (layout)
414     last_offset = (ehdr.e_phoff
415 		   + gelf_fsize (elf, ELF_T_PHDR, phnum, EV_CURRENT));
416 
417   /* Which section, if any, is a symbol table that shares a string
418      table with the section header string table?  */
419   size_t symtabndx = 0;
420 
421   /* We do three passes over all sections.
422 
423      First an inspection pass over the old Elf to see which section
424      data needs to be copied and/or transformed, which sections need a
425      names change and whether there is a symbol table that might need
426      to be adjusted be if the section header name table is changed.
427 
428      Second a collection pass that creates the Elf sections and copies
429      the data.  This pass will compress/decompress section data when
430      needed.  And it will collect all data needed if we'll need to
431      construct a new string table. Afterwards the new string table is
432      constructed.
433 
434      Third a fixup/adjustment pass over the new Elf that will adjust
435      any section references (names) and adjust the layout based on the
436      new sizes of the sections if necessary.  This pass is optional if
437      we aren't responsible for the layout and the section header
438      string table hasn't been changed.  */
439 
440   /* Inspection pass.  */
441   size_t maxnamelen = 0;
442   Elf_Scn *scn = NULL;
443   while ((scn = elf_nextscn (elf, scn)) != NULL)
444     {
445       size_t ndx = elf_ndxscn (scn);
446       if (ndx > shnum)
447 	{
448 	  error (0, 0, "Unexpected section number %zd, expected only %zd",
449 		 ndx, shnum);
450 	  cleanup (-1);
451 	}
452 
453       GElf_Shdr shdr_mem;
454       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
455       if (shdr == NULL)
456 	{
457 	  error (0, 0, "Couldn't get shdr for section %zd", ndx);
458 	  return cleanup (-1);
459 	}
460 
461       const char *sname = elf_strptr (elf, shdrstrndx, shdr->sh_name);
462       if (sname == NULL)
463 	{
464 	  error (0, 0, "Couldn't get name for section %zd", ndx);
465 	  return cleanup (-1);
466 	}
467 
468       if (section_name_matches (sname))
469 	{
470 	  if (shdr->sh_type != SHT_NOBITS
471 	      && (shdr->sh_flags & SHF_ALLOC) == 0)
472 	    {
473 	      set_section (ndx);
474 	      /* Check if we might want to change this section name.  */
475 	      if (! adjust_names
476 		  && ((type != T_COMPRESS_GNU
477 		       && strncmp (sname, ".zdebug",
478 				   strlen (".zdebug")) == 0)
479 		      || (type == T_COMPRESS_GNU
480 			  && strncmp (sname, ".debug",
481 				      strlen (".debug")) == 0)))
482 		adjust_names = true;
483 
484 	      /* We need a buffer this large if we change the names.  */
485 	      if (adjust_names)
486 		{
487 		  size_t slen = strlen (sname);
488 		  if (slen > maxnamelen)
489 		    maxnamelen = slen;
490 		}
491 	    }
492 	  else
493 	    if (verbose >= 0)
494 	      printf ("[%zd] %s ignoring %s section\n", ndx, sname,
495 		      (shdr->sh_type == SHT_NOBITS ? "no bits" : "allocated"));
496 	}
497 
498       if (shdr->sh_type == SHT_SYMTAB)
499 	{
500 	  /* Check if we might have to adjust the symbol name indexes.  */
501 	  if (shdr->sh_link == shdrstrndx)
502 	    {
503 	      if (symtabndx != 0)
504 		{
505 		  error (0, 0,
506 			 "Multiple symbol tables (%zd, %zd) using the same string table unsupported", symtabndx, ndx);
507 		  return cleanup (-1);
508 		}
509 	      symtabndx = ndx;
510 	    }
511 	}
512 
513       /* Keep track of last allocated data offset.  */
514       if (layout)
515 	if ((shdr->sh_flags & SHF_ALLOC) != 0)
516 	  {
517 	    GElf_Off off = shdr->sh_offset + (shdr->sh_type != SHT_NOBITS
518 					      ? shdr->sh_size : 0);
519 	    if (last_offset < off)
520 	      last_offset = off;
521 	  }
522     }
523 
524   if (adjust_names)
525     {
526       names = ebl_strtabinit (true);
527       if (names == NULL)
528 	{
529 	  error (0, 0, "Not enough memory for new strtab");
530 	  return cleanup (-1);
531 	}
532       scnstrents = xmalloc (shnum
533 			    * sizeof (struct Ebl_Strent *));
534       scnnames = xcalloc (shnum, sizeof (char *));
535     }
536 
537   /* Create a new (temporary) ELF file for the result.  */
538   if (foutput == NULL)
539     {
540       size_t fname_len = strlen (fname);
541       fnew = xmalloc (fname_len + sizeof (".XXXXXX"));
542       strcpy (mempcpy (fnew, fname, fname_len), ".XXXXXX");
543       fdnew = mkstemp (fnew);
544     }
545   else
546     {
547       fnew = xstrdup (foutput);
548       fdnew = open (fnew, O_WRONLY | O_CREAT, st.st_mode & ALLPERMS);
549     }
550 
551   if (fdnew < 0)
552     {
553       error (0, errno, "Couldn't create output file %s", fnew);
554       /* Since we didn't create it we don't want to try to unlink it.  */
555       free (fnew);
556       fnew = NULL;
557       return cleanup (-1);
558     }
559 
560   elfnew = elf_begin (fdnew, ELF_C_WRITE, NULL);
561   if (elfnew == NULL)
562     {
563       error (0, 0, "Couldn't open new ELF %s for writing: %s",
564 	     fnew, elf_errmsg (-1));
565       return cleanup (-1);
566     }
567 
568   /* Create the new ELF header and copy over all the data.  */
569   if (gelf_newehdr (elfnew, gelf_getclass (elf)) == 0)
570     {
571       error (0, 0, "Couldn't create new ehdr: %s", elf_errmsg (-1));
572       return cleanup (-1);
573     }
574 
575   GElf_Ehdr newehdr;
576   if (gelf_getehdr (elfnew, &newehdr) == NULL)
577     {
578       error (0, 0, "Couldn't get new ehdr: %s", elf_errmsg (-1));
579       return cleanup (-1);
580     }
581 
582   newehdr.e_ident[EI_DATA] = ehdr.e_ident[EI_DATA];
583   newehdr.e_type = ehdr.e_type;
584   newehdr.e_machine = ehdr.e_machine;
585   newehdr.e_version = ehdr.e_version;
586   newehdr.e_entry = ehdr.e_entry;
587   newehdr.e_flags = ehdr.e_flags;
588 
589   if (gelf_update_ehdr (elfnew, &newehdr) == 0)
590     {
591       error (0, 0, "Couldn't update ehdr: %s", elf_errmsg (-1));
592       return cleanup (-1);
593     }
594 
595   /* Copy over the phdrs as is.  */
596   if (phnum != 0)
597     {
598       if (gelf_newphdr (elfnew, phnum) == 0)
599 	{
600 	  error (0, 0, "Couldn't create phdrs: %s", elf_errmsg (-1));
601 	  return cleanup (-1);
602 	}
603 
604       for (size_t cnt = 0; cnt < phnum; ++cnt)
605 	{
606 	  GElf_Phdr phdr_mem;
607 	  GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem);
608 	  if (phdr == NULL)
609 	    {
610 	      error (0, 0, "Couldn't get phdr %zd: %s", cnt, elf_errmsg (-1));
611 	      return cleanup (-1);
612 	    }
613 	  if (gelf_update_phdr (elfnew, cnt, phdr) == 0)
614 	    {
615 	      error (0, 0, "Couldn't create phdr %zd: %s", cnt,
616 		     elf_errmsg (-1));
617 	      return cleanup (-1);
618 	    }
619 	}
620     }
621 
622   /* Possibly add a 'z' and zero terminator.  */
623   if (maxnamelen > 0)
624     snamebuf = xmalloc (maxnamelen + 2);
625 
626   /* We might want to read/adjust the section header strings and
627      symbol tables.  If so, and those sections are to be compressed
628      then we will have to decompress it during the collection pass and
629      compress it again in the fixup pass.  Don't compress unnecessary
630      and keep track of whether or not to compress them (later in the
631      fixup pass).  Also record the original size, so we can report the
632      difference later when we do compress.  */
633   int shstrtab_compressed = T_UNSET;
634   size_t shstrtab_size = 0;
635   char *shstrtab_name = NULL;
636   char *shstrtab_newname = NULL;
637   int symtab_compressed = T_UNSET;
638   size_t symtab_size = 0;
639   char *symtab_name = NULL;
640   char *symtab_newname = NULL;
641 
642   /* Collection pass.  Copy over the sections, (de)compresses matching
643      sections, collect names of sections and symbol table if
644      necessary.  */
645   scn = NULL;
646   while ((scn = elf_nextscn (elf, scn)) != NULL)
647     {
648       size_t ndx = elf_ndxscn (scn);
649       assert (ndx < shnum);
650 
651       /* (de)compress if section matched.  */
652       char *sname = NULL;
653       char *newname = NULL;
654       if (get_section (ndx))
655 	{
656 	  GElf_Shdr shdr_mem;
657 	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
658 	  if (shdr == NULL)
659 	    {
660 	      error (0, 0, "Couldn't get shdr for section %zd", ndx);
661 	      return cleanup (-1);
662 	    }
663 
664 	  uint64_t size = shdr->sh_size;
665 	  sname = elf_strptr (elf, shdrstrndx, shdr->sh_name);
666 	  if (sname == NULL)
667 	    {
668 	      error (0, 0, "Couldn't get name for section %zd", ndx);
669 	      return cleanup (-1);
670 	    }
671 
672 	  /* strdup sname, the shdrstrndx section itself might be
673 	     (de)compressed, invalidating the string pointers.  */
674 	  sname = xstrdup (sname);
675 
676 	  /* We might want to decompress (and rename), but not
677 	     compress during this pass since we might need the section
678 	     data in later passes.  Skip those sections for now and
679 	     compress them in the fixup pass.  */
680 	  bool skip_compress_section = (adjust_names
681 					&& (ndx == shdrstrndx
682 					    || ndx == symtabndx));
683 
684 	  switch (type)
685 	    {
686 	    case T_DECOMPRESS:
687 	      if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
688 		{
689 		  if (compress_section (scn, size, sname, NULL, ndx,
690 					false, false, verbose > 0) < 0)
691 		    return cleanup (-1);
692 		}
693 	      else if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
694 		{
695 		  snamebuf[0] = '.';
696 		  strcpy (&snamebuf[1], &sname[2]);
697 		  newname = snamebuf;
698 		  if (compress_section (scn, size, sname, newname, ndx,
699 					true, false, verbose > 0) < 0)
700 		    return cleanup (-1);
701 		}
702 	      else if (verbose > 0)
703 		printf ("[%zd] %s already decompressed\n", ndx, sname);
704 	      break;
705 
706 	    case T_COMPRESS_GNU:
707 	      if (strncmp (sname, ".debug", strlen (".debug")) == 0)
708 		{
709 		  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
710 		    {
711 		      /* First decompress to recompress GNU style.
712 			 Don't report even when verbose.  */
713 		      if (compress_section (scn, size, sname, NULL, ndx,
714 					    false, false, false) < 0)
715 			return cleanup (-1);
716 		    }
717 
718 		  snamebuf[0] = '.';
719 		  snamebuf[1] = 'z';
720 		  strcpy (&snamebuf[2], &sname[1]);
721 		  newname = snamebuf;
722 
723 		  if (skip_compress_section)
724 		    {
725 		      if (ndx == shdrstrndx)
726 			{
727 			  shstrtab_size = size;
728 			  shstrtab_compressed = T_COMPRESS_GNU;
729 			  shstrtab_name = xstrdup (sname);
730 			  shstrtab_newname = xstrdup (newname);
731 			}
732 		      else
733 			{
734 			  symtab_size = size;
735 			  symtab_compressed = T_COMPRESS_GNU;
736 			  symtab_name = xstrdup (sname);
737 			  symtab_newname = xstrdup (newname);
738 			}
739 		    }
740 		  else
741 		    {
742 		      int res = compress_section (scn, size, sname, newname,
743 						  ndx, true, true,
744 						  verbose > 0);
745 		      if (res < 0)
746 			return cleanup (-1);
747 
748 		      if (res == 0)
749 			newname = NULL;
750 		    }
751 		}
752 	      else if (verbose >= 0)
753 		{
754 		  if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
755 		    printf ("[%zd] %s unchanged, already GNU compressed",
756 			    ndx, sname);
757 		  else
758 		    printf ("[%zd] %s cannot GNU compress section not starting with .debug\n",
759 			    ndx, sname);
760 		}
761 	      break;
762 
763 	    case T_COMPRESS_ZLIB:
764 	      if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
765 		{
766 		  if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
767 		    {
768 		      /* First decompress to recompress zlib style.
769 			 Don't report even when verbose.  */
770 		      if (compress_section (scn, size, sname, NULL, ndx,
771 					    true, false, false) < 0)
772 			return cleanup (-1);
773 
774 		      snamebuf[0] = '.';
775 		      strcpy (&snamebuf[1], &sname[2]);
776 		      newname = snamebuf;
777 		    }
778 
779 		  if (skip_compress_section)
780 		    {
781 		      if (ndx == shdrstrndx)
782 			{
783 			  shstrtab_size = size;
784 			  shstrtab_compressed = T_COMPRESS_ZLIB;
785 			  shstrtab_name = xstrdup (sname);
786 			  shstrtab_newname = (newname == NULL
787 					      ? NULL : xstrdup (newname));
788 			}
789 		      else
790 			{
791 			  symtab_size = size;
792 			  symtab_compressed = T_COMPRESS_ZLIB;
793 			  symtab_name = xstrdup (sname);
794 			  symtab_newname = (newname == NULL
795 					    ? NULL : xstrdup (newname));
796 			}
797 		    }
798 		  else if (compress_section (scn, size, sname, newname, ndx,
799 					     false, true, verbose > 0) < 0)
800 		    return cleanup (-1);
801 		}
802 	      else if (verbose > 0)
803 		printf ("[%zd] %s already compressed\n", ndx, sname);
804 	      break;
805 	    }
806 
807 	  free (sname);
808 	}
809 
810       Elf_Scn *newscn = elf_newscn (elfnew);
811       if (newscn == NULL)
812 	{
813 	  error (0, 0, "Couldn't create new section %zd", ndx);
814 	  return cleanup (-1);
815 	}
816 
817       GElf_Shdr shdr_mem;
818       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
819       if (shdr == NULL)
820 	{
821 	  error (0, 0, "Couldn't get shdr for section %zd", ndx);
822 	  return cleanup (-1);
823 	}
824 
825       if (gelf_update_shdr (newscn, shdr) == 0)
826         {
827 	  error (0, 0, "Couldn't update section header %zd", ndx);
828 	  return cleanup (-1);
829 	}
830 
831       /* Except for the section header string table all data can be
832 	 copied as is.  The section header string table will be
833 	 created later and the symbol table might be fixed up if
834 	 necessary.  */
835       if (! adjust_names || ndx != shdrstrndx)
836 	{
837 	  Elf_Data *data = elf_getdata (scn, NULL);
838 	  if (data == NULL)
839 	    {
840 	      error (0, 0, "Couldn't get data from section %zd", ndx);
841 	      return cleanup (-1);
842 	    }
843 
844 	  Elf_Data *newdata = elf_newdata (newscn);
845 	  if (newdata == NULL)
846 	    {
847 	      error (0, 0, "Couldn't create new data for section %zd", ndx);
848 	      return cleanup (-1);
849 	    }
850 
851 	  *newdata = *data;
852 	}
853 
854       /* Keep track of the (new) section names.  */
855       if (adjust_names)
856 	{
857 	  char *name;
858 	  if (newname != NULL)
859 	    name = newname;
860 	  else
861 	    {
862 	      name = elf_strptr (elf, shdrstrndx, shdr->sh_name);
863 	      if (name == NULL)
864 		{
865 		  error (0, 0, "Couldn't get name for section [%zd]", ndx);
866 		  return cleanup (-1);
867 		}
868 	    }
869 
870 	  /* We need to keep a copy of the name till the strtab is done.  */
871 	  name = scnnames[ndx] = xstrdup (name);
872 	  if ((scnstrents[ndx] = ebl_strtabadd (names, name, 0)) == NULL)
873 	    {
874 	      error (0, 0, "No memory to add section name string table");
875 	      return cleanup (-1);
876 	    }
877 
878 	  /* If the symtab shares strings then add those too.  */
879 	  if (ndx == symtabndx)
880 	    {
881 	      /* If the section is (still) compressed we'll need to
882 		 uncompress it first to adjust the data, then
883 		 recompress it in the fixup pass.  */
884 	      if (symtab_compressed == T_UNSET)
885 		{
886 		  size_t size = shdr->sh_size;
887 		  if ((shdr->sh_flags == SHF_COMPRESSED) != 0)
888 		    {
889 		      /* Don't report the (internal) uncompression.  */
890 		      if (compress_section (newscn, size, sname, NULL, ndx,
891 					    false, false, false) < 0)
892 			return cleanup (-1);
893 
894 		      symtab_size = size;
895 		      symtab_compressed = T_COMPRESS_ZLIB;
896 		    }
897 		  else if (strncmp (name, ".zdebug", strlen (".zdebug")) == 0)
898 		    {
899 		      /* Don't report the (internal) uncompression.  */
900 		      if (compress_section (newscn, size, sname, NULL, ndx,
901 					    true, false, false) < 0)
902 			return cleanup (-1);
903 
904 		      symtab_size = size;
905 		      symtab_compressed = T_COMPRESS_GNU;
906 		    }
907 		}
908 
909 	      Elf_Data *symd = elf_getdata (newscn, NULL);
910 	      if (symd == NULL)
911 		{
912 		  error (0, 0, "Couldn't get symtab data for section [%zd] %s",
913 			 ndx, name);
914 		  return cleanup (-1);
915 		}
916 	      size_t elsize = gelf_fsize (elfnew, ELF_T_SYM, 1, EV_CURRENT);
917 	      size_t syms = symd->d_size / elsize;
918 	      symstrents = xmalloc (syms * sizeof (struct Ebl_Strent *));
919 	      for (size_t i = 0; i < syms; i++)
920 		{
921 		  GElf_Sym sym_mem;
922 		  GElf_Sym *sym = gelf_getsym (symd, i, &sym_mem);
923 		  if (sym == NULL)
924 		    {
925 		      error (0, 0, "Couldn't get symbol %zd", i);
926 		      return cleanup (-1);
927 		    }
928 		  if (sym->st_name != 0)
929 		    {
930 		      /* Note we take the name from the original ELF,
931 			 since the new one will not have setup the
932 			 strtab yet.  */
933 		      const char *symname = elf_strptr (elf, shdrstrndx,
934 							sym->st_name);
935 		      if (symname == NULL)
936 			{
937 			  error (0, 0, "Couldn't get symbol %zd name", i);
938 			  return cleanup (-1);
939 			}
940 		      symstrents[i] = ebl_strtabadd (names, symname, 0);
941 		      if (symstrents[i] == NULL)
942 			{
943 			  error (0, 0, "No memory to add to symbol name");
944 			  return cleanup (-1);
945 			}
946 		    }
947 		}
948 	    }
949 	}
950     }
951 
952   if (adjust_names)
953     {
954       /* We got all needed strings, put the new data in the shstrtab.  */
955       if (verbose > 0)
956 	printf ("[%zd] Updating section string table\n", shdrstrndx);
957 
958       scn = elf_getscn (elfnew, shdrstrndx);
959       if (scn == NULL)
960 	{
961 	  error (0, 0, "Couldn't get new section header string table [%zd]",
962 		 shdrstrndx);
963 	  return cleanup (-1);
964 	}
965 
966       Elf_Data *data = elf_newdata (scn);
967       if (data == NULL)
968 	{
969 	  error (0, 0, "Couldn't create new section header string table data");
970 	  return cleanup (-1);
971 	}
972       ebl_strtabfinalize (names, data);
973       namesbuf = data->d_buf;
974 
975       GElf_Shdr shdr_mem;
976       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
977       if (shdr == NULL)
978 	{
979 	  error (0, 0, "Couldn't get shdr for new section strings %zd",
980 		 shdrstrndx);
981 	  return cleanup (-1);
982 	}
983 
984       /* Note that we also might have to compress and possibly set
985 	 sh_off below */
986       shdr->sh_name = ebl_strtaboffset (scnstrents[shdrstrndx]);
987       shdr->sh_type = SHT_STRTAB;
988       shdr->sh_flags = 0;
989       shdr->sh_addr = 0;
990       shdr->sh_offset = 0;
991       shdr->sh_size = data->d_size;
992       shdr->sh_link = SHN_UNDEF;
993       shdr->sh_info = SHN_UNDEF;
994       shdr->sh_addralign = 1;
995       shdr->sh_entsize = 0;
996 
997       if (gelf_update_shdr (scn, shdr) == 0)
998 	{
999 	  error (0, 0, "Couldn't update new section strings [%zd]",
1000 		 shdrstrndx);
1001 	  return cleanup (-1);
1002 	}
1003 
1004       /* We might have to compress the data if the user asked us to,
1005 	 or if the section was already compressed (and the user didn't
1006 	 ask for decompression).  Note somewhat identical code for
1007 	 symtab below.  */
1008       if (shstrtab_compressed == T_UNSET)
1009 	{
1010 	  /* The user didn't ask for compression, but maybe it was
1011 	     compressed in the original ELF file.  */
1012 	  Elf_Scn *oldscn = elf_getscn (elf, shdrstrndx);
1013 	  if (oldscn == NULL)
1014 	    {
1015 	      error (0, 0, "Couldn't get section header string table [%zd]",
1016 		     shdrstrndx);
1017 	      return cleanup (-1);
1018 	    }
1019 
1020 	  shdr = gelf_getshdr (oldscn, &shdr_mem);
1021 	  if (shdr == NULL)
1022 	    {
1023 	      error (0, 0, "Couldn't get shdr for old section strings [%zd]",
1024 		     shdrstrndx);
1025 	      return cleanup (-1);
1026 	    }
1027 
1028 	  shstrtab_name = elf_strptr (elf, shdrstrndx, shdr->sh_name);
1029 	  if (shstrtab_name == NULL)
1030 	    {
1031 	      error (0, 0, "Couldn't get name for old section strings [%zd]",
1032 		     shdrstrndx);
1033 	      return cleanup (-1);
1034 	    }
1035 
1036 	  shstrtab_size = shdr->sh_size;
1037 	  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
1038 	    shstrtab_compressed = T_COMPRESS_ZLIB;
1039 	  else if (strncmp (shstrtab_name, ".zdebug", strlen (".zdebug")) == 0)
1040 	    shstrtab_compressed = T_COMPRESS_GNU;
1041 	}
1042 
1043       /* Should we (re)compress?  */
1044       if (shstrtab_compressed != T_UNSET)
1045 	{
1046 	  if (compress_section (scn, shstrtab_size, shstrtab_name,
1047 				shstrtab_newname, shdrstrndx,
1048 				shstrtab_compressed == T_COMPRESS_GNU,
1049 				true, verbose > 0) < 0)
1050 	    return cleanup (-1);
1051 	}
1052     }
1053 
1054   /* Make sure to re-get the new ehdr.  Adding phdrs and shdrs will
1055      have changed it.  */
1056   if (gelf_getehdr (elfnew, &newehdr) == NULL)
1057     {
1058       error (0, 0, "Couldn't re-get new ehdr: %s", elf_errmsg (-1));
1059       return cleanup (-1);
1060     }
1061 
1062   /* Set this after the sections have been created, otherwise section
1063      zero might not exist yet.  */
1064   if (setshdrstrndx (elfnew, &newehdr, shdrstrndx) != 0)
1065     {
1066       error (0, 0, "Couldn't set new shdrstrndx: %s", elf_errmsg (-1));
1067       return cleanup (-1);
1068     }
1069 
1070   /* Fixup pass.  Adjust string table references, symbol table and
1071      layout if necessary.  */
1072   if (layout || adjust_names)
1073     {
1074       scn = NULL;
1075       while ((scn = elf_nextscn (elfnew, scn)) != NULL)
1076 	{
1077 	  size_t ndx = elf_ndxscn (scn);
1078 
1079 	  GElf_Shdr shdr_mem;
1080 	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1081 	  if (shdr == NULL)
1082 	    {
1083 	      error (0, 0, "Couldn't get shdr for section %zd", ndx);
1084 	      return cleanup (-1);
1085 	    }
1086 
1087 	  /* Keep the offset of allocated sections so they are at the
1088 	     same place in the file. Add (possibly changed)
1089 	     unallocated ones after the allocated ones.  */
1090 	  if ((shdr->sh_flags & SHF_ALLOC) == 0)
1091 	    {
1092 	      /* Zero means one.  No alignment constraints.  */
1093 	      size_t addralign = shdr->sh_addralign ?: 1;
1094 	      last_offset = (last_offset + addralign - 1) & ~(addralign - 1);
1095 	      shdr->sh_offset = last_offset;
1096 	      if (shdr->sh_type != SHT_NOBITS)
1097 		last_offset += shdr->sh_size;
1098 	    }
1099 
1100 	  if (adjust_names)
1101 	    shdr->sh_name = ebl_strtaboffset (scnstrents[ndx]);
1102 
1103 	  if (gelf_update_shdr (scn, shdr) == 0)
1104 	    {
1105 	      error (0, 0, "Couldn't update section header %zd", ndx);
1106 	      return cleanup (-1);
1107 	    }
1108 
1109 	  if (adjust_names && ndx == symtabndx)
1110 	    {
1111 	      if (verbose > 0)
1112 		printf ("[%zd] Updating symbol table\n", symtabndx);
1113 
1114 	      Elf_Data *symd = elf_getdata (scn, NULL);
1115 	      if (symd == NULL)
1116 		{
1117 		  error (0, 0, "Couldn't get new symtab data section [%zd]",
1118 			 ndx);
1119 		  return cleanup (-1);
1120 		}
1121 	      size_t elsize = gelf_fsize (elfnew, ELF_T_SYM, 1, EV_CURRENT);
1122 	      size_t syms = symd->d_size / elsize;
1123 	      for (size_t i = 0; i < syms; i++)
1124 		{
1125 		  GElf_Sym sym_mem;
1126 		  GElf_Sym *sym = gelf_getsym (symd, i, &sym_mem);
1127 		  if (sym == NULL)
1128 		    {
1129 		      error (0, 0, "2 Couldn't get symbol %zd", i);
1130 		      return cleanup (-1);
1131 		    }
1132 
1133 		  if (sym->st_name != 0)
1134 		    {
1135 		      sym->st_name = ebl_strtaboffset (symstrents[i]);
1136 
1137 		      if (gelf_update_sym (symd, i, sym) == 0)
1138 			{
1139 			  error (0, 0, "Couldn't update symbol %zd", i);
1140 			  return cleanup (-1);
1141 			}
1142 		    }
1143 		}
1144 
1145 	      /* We might have to compress the data if the user asked
1146 		 us to, or if the section was already compressed (and
1147 		 the user didn't ask for decompression).  Note
1148 		 somewhat identical code for shstrtab above.  */
1149 	      if (symtab_compressed == T_UNSET)
1150 		{
1151 		  /* The user didn't ask for compression, but maybe it was
1152 		     compressed in the original ELF file.  */
1153 		  Elf_Scn *oldscn = elf_getscn (elf, symtabndx);
1154 		  if (oldscn == NULL)
1155 		    {
1156 		      error (0, 0, "Couldn't get symbol table [%zd]",
1157 			     symtabndx);
1158 		      return cleanup (-1);
1159 		    }
1160 
1161 		  shdr = gelf_getshdr (oldscn, &shdr_mem);
1162 		  if (shdr == NULL)
1163 		    {
1164 		      error (0, 0, "Couldn't get old symbol table shdr [%zd]",
1165 			     symtabndx);
1166 		      return cleanup (-1);
1167 		    }
1168 
1169 		  symtab_name = elf_strptr (elf, shdrstrndx, shdr->sh_name);
1170 		  if (symtab_name == NULL)
1171 		    {
1172 		      error (0, 0, "Couldn't get old symbol table name [%zd]",
1173 			     symtabndx);
1174 		      return cleanup (-1);
1175 		    }
1176 
1177 		  symtab_size = shdr->sh_size;
1178 		  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
1179 		    symtab_compressed = T_COMPRESS_ZLIB;
1180 		  else if (strncmp (symtab_name, ".zdebug",
1181 				    strlen (".zdebug")) == 0)
1182 		    symtab_compressed = T_COMPRESS_GNU;
1183 		}
1184 
1185 	      /* Should we (re)compress?  */
1186 	      if (symtab_compressed != T_UNSET)
1187 		{
1188 		  if (compress_section (scn, symtab_size, symtab_name,
1189 					symtab_newname, symtabndx,
1190 					symtab_compressed == T_COMPRESS_GNU,
1191 					true, verbose > 0) < 0)
1192 		    return cleanup (-1);
1193 		}
1194 	    }
1195 	}
1196     }
1197 
1198   /* If we have phdrs we want elf_update to layout the SHF_ALLOC
1199      sections precisely as in the original file.  In that case we are
1200      also responsible for setting phoff and shoff */
1201   if (layout)
1202     {
1203       if (gelf_getehdr (elfnew, &newehdr) == NULL)
1204 	{
1205 	  error (0, 0, "Couldn't get ehdr: %s", elf_errmsg (-1));
1206 	  return cleanup (-1);
1207 	}
1208 
1209       /* Position the shdrs after the last (unallocated) section.  */
1210       const size_t offsize = gelf_fsize (elfnew, ELF_T_OFF, 1, EV_CURRENT);
1211       newehdr.e_shoff = ((last_offset + offsize - 1)
1212 			 & ~((GElf_Off) (offsize - 1)));
1213 
1214       /* The phdrs go in the same place as in the original file.
1215 	 Normally right after the ELF header.  */
1216       newehdr.e_phoff = ehdr.e_phoff;
1217 
1218       if (gelf_update_ehdr (elfnew, &newehdr) == 0)
1219 	{
1220 	  error (0, 0, "Couldn't update ehdr: %s", elf_errmsg (-1));
1221 	  return cleanup (-1);
1222 	}
1223     }
1224 
1225   elf_flagelf (elfnew, ELF_C_SET, ((layout ? ELF_F_LAYOUT : 0)
1226 				   | (permissive ? ELF_F_PERMISSIVE : 0)));
1227 
1228   if (elf_update (elfnew, ELF_C_WRITE) < 0)
1229     {
1230       error (0, 0, "Couldn't write %s: %s", fnew, elf_errmsg (-1));
1231       return cleanup (-1);
1232     }
1233 
1234   elf_end (elfnew);
1235   elfnew = NULL;
1236 
1237   /* Try to match mode and owner.group of the original file.  */
1238   if (fchmod (fdnew, st.st_mode & ALLPERMS) != 0)
1239     if (verbose >= 0)
1240       error (0, errno, "Couldn't fchmod %s", fnew);
1241   if (fchown (fdnew, st.st_uid, st.st_gid) != 0)
1242     if (verbose >= 0)
1243       error (0, errno, "Couldn't fchown %s", fnew);
1244 
1245   /* Finally replace the old file with the new file.  */
1246   if (foutput == NULL)
1247     if (rename (fnew, fname) != 0)
1248       {
1249 	error (0, errno, "Couldn't rename %s to %s", fnew, fname);
1250 	return cleanup (-1);
1251       }
1252 
1253   /* We are finally done with the new file, don't unlink it now.  */
1254   free (fnew);
1255   fnew = NULL;
1256 
1257   return cleanup (0);
1258 }
1259 
1260 int
main(int argc,char ** argv)1261 main (int argc, char **argv)
1262 {
1263   const struct argp_option options[] =
1264     {
1265       { "output", 'o', "FILE", 0,
1266 	N_("Place (de)compressed output into FILE"),
1267 	0 },
1268       { "type", 't', "TYPE", 0,
1269 	N_("What type of compression to apply. TYPE can be 'none' (decompress), 'zlib' (ELF ZLIB compression, the default, 'zlib-gabi' is an alias) or 'zlib-gnu' (.zdebug GNU style compression, 'gnu' is an alias)"),
1270 	0 },
1271       { "name", 'n', "SECTION", 0,
1272 	N_("SECTION name to (de)compress, SECTION is an extended wildcard pattern (defaults to '.?(z)debug*')"),
1273 	0 },
1274       { "verbose", 'v', NULL, 0,
1275 	N_("Print a message for each section being (de)compressed"),
1276 	0 },
1277       { "force", 'f', NULL, 0,
1278 	N_("Force compression of section even if it would become larger"),
1279 	0 },
1280       { "permissive", 'p', NULL, 0,
1281 	N_("Relax a few rules to handle slightly broken ELF files"),
1282 	0 },
1283       { "quiet", 'q', NULL, 0,
1284 	N_("Be silent when a section cannot be compressed"),
1285 	0 },
1286       { NULL, 0, NULL, 0, NULL, 0 }
1287     };
1288 
1289   const struct argp argp =
1290     {
1291       .options = options,
1292       .parser = parse_opt,
1293       .args_doc = N_("FILE..."),
1294       .doc = N_("Compress or decompress sections in an ELF file.")
1295     };
1296 
1297   int remaining;
1298   if (argp_parse (&argp, argc, argv, 0, &remaining, NULL) != 0)
1299     return EXIT_FAILURE;
1300 
1301   /* Should already be handled by ARGP_KEY_NO_ARGS case above,
1302      just sanity check.  */
1303   if (remaining >= argc)
1304     error (EXIT_FAILURE, 0, N_("No input file given"));
1305 
1306   /* Likewise for the ARGP_KEY_ARGS case above, an extra sanity check.  */
1307   if (foutput != NULL && remaining + 1 < argc)
1308     error (EXIT_FAILURE, 0,
1309 	   N_("Only one input file allowed together with '-o'"));
1310 
1311   elf_version (EV_CURRENT);
1312 
1313   /* Process all the remaining files.  */
1314   int result = 0;
1315   do
1316     result |= process_file (argv[remaining]);
1317   while (++remaining < argc);
1318 
1319   free_patterns ();
1320   return result;
1321 }
1322