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