192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard/* Compress or decompress an ELF file.
292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard   Copyright (C) 2015 Red Hat, Inc.
392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard   This file is part of elfutils.
492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard   This file is free software; you can redistribute it and/or modify
692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard   it under the terms of the GNU General Public License as published by
792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard   the Free Software Foundation; either version 3 of the License, or
892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard   (at your option) any later version.
992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
1092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard   elfutils is distributed in the hope that it will be useful, but
1192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard   WITHOUT ANY WARRANTY; without even the implied warranty of
1292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard   GNU General Public License for more details.
1492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
1592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard   You should have received a copy of the GNU General Public License
1692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
1792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
1892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include <config.h>
1992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include <assert.h>
2092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include <argp.h>
2192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include <error.h>
2292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include <stdbool.h>
2392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include <stdlib.h>
2492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include <inttypes.h>
2592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include <stdio.h>
2692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include <string.h>
2792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include <locale.h>
2892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include <fcntl.h>
2992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include <fnmatch.h>
3092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include <sys/types.h>
3192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include <sys/stat.h>
3292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include <unistd.h>
3392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include ELFUTILS_HEADER(elf)
3492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include ELFUTILS_HEADER(ebl)
3592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include <gelf.h>
3692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#include "system.h"
3792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
3892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard/* Name and version of program.  */
3992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardstatic void print_version (FILE *stream, struct argp_state *state);
4092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark WielaardARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
4192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
4292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard/* Bug report address.  */
4392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark WielaardARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
4492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
4592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardstatic int verbose = 0; /* < 0, no warnings, > 0 extra verbosity.  */
4692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardstatic bool force = false;
4792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardstatic bool permissive = false;
4892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardstatic const char *foutput = NULL;
4992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
5092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#define T_UNSET 0
5192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#define T_DECOMPRESS 1    /* none */
5292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#define T_COMPRESS_ZLIB 2 /* zlib */
5392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#define T_COMPRESS_GNU  3 /* zlib-gnu */
5492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardstatic int type = T_UNSET;
5592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
5692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardstatic void
5792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardprint_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
5892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard{
5992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  fprintf (stream, "elfcompress (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
6092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard}
6192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
6292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardstruct section_pattern
6392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard{
6492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  char *pattern;
6592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  struct section_pattern *next;
6692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard};
6792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
6892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardstatic struct section_pattern *patterns = NULL;
6992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
7092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardstatic void
7192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardadd_pattern (const char *pattern)
7292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard{
7392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  struct section_pattern *p = xmalloc (sizeof *p);
7492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  p->pattern = xstrdup (pattern);
7592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  p->next = patterns;
7692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  patterns = p;
7792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard}
7892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
7992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardstatic void
8092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardfree_patterns (void)
8192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard{
8292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  struct section_pattern *pattern = patterns;
8392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  while (pattern != NULL)
8492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
8592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      struct section_pattern *p = pattern;
8692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      pattern = p->next;
8792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      free (p->pattern);
8892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      free (p);
8992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
9092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard}
9192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
9292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardstatic error_t
9392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardparse_opt (int key, char *arg __attribute__ ((unused)),
9492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	   struct argp_state *state __attribute__ ((unused)))
9592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard{
9692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  switch (key)
9792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
9892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    case 'v':
9992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      verbose++;
10092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      break;
10192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
10292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    case 'q':
10392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      verbose--;
10492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
10592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    case 'f':
10692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      force = true;
10792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      break;
10892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
10992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    case 'p':
11092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      permissive = true;
11192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      break;
11292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
11392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    case 'n':
11492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      add_pattern (arg);
11592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      break;
11692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
11792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    case 'o':
11892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (foutput != NULL)
11992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	argp_error (state, N_("-o option specified twice"));
12092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      else
12192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	foutput = arg;
12292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      break;
12392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
12492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    case 't':
12592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (type != T_UNSET)
12692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	argp_error (state, N_("-t option specified twice"));
12792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
12892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (strcmp ("none", arg) == 0)
12992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	type = T_DECOMPRESS;
13092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      else if (strcmp ("zlib", arg) == 0 || strcmp ("zlib-gabi", arg) == 0)
13192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	type = T_COMPRESS_ZLIB;
13292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      else if (strcmp ("zlib-gnu", arg) == 0 || strcmp ("gnu", arg) == 0)
13392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	type = T_COMPRESS_GNU;
13492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      else
13592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	argp_error (state, N_("unknown compression type '%s'"), arg);
13692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      break;
13792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
13892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    case ARGP_KEY_SUCCESS:
13992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (type == T_UNSET)
14092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	type = T_COMPRESS_ZLIB;
14192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (patterns == NULL)
14292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	add_pattern (".?(z)debug*");
14392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      break;
14492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
14592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    case ARGP_KEY_NO_ARGS:
14692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      /* We need at least one input file.  */
14792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      argp_error (state, N_("No input file given"));
14892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      break;
14992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
15092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    case ARGP_KEY_ARGS:
15192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (foutput != NULL && state->argc - state->next > 1)
15292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	argp_error (state,
15392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    N_("Only one input file allowed together with '-o'"));
15492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      /* We only use this for checking the number of arguments, we don't
15592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	 actually want to consume them, so fallthrough.  */
15692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    default:
15792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      return ARGP_ERR_UNKNOWN;
15892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
15992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  return 0;
16092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard}
16192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
16292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardstatic bool
16392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardsection_name_matches (const char *name)
16492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard{
16592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  struct section_pattern *pattern = patterns;
16692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  while (pattern != NULL)
16792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
16892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (fnmatch (pattern->pattern, name, FNM_EXTMATCH) == 0)
16992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	return true;
17092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      pattern = pattern->next;
17192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
17292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  return false;
17392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard}
17492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
17592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardstatic int
17692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardsetshdrstrndx (Elf *elf, GElf_Ehdr *ehdr, size_t ndx)
17792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard{
17892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (ndx < SHN_LORESERVE)
17992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    ehdr->e_shstrndx = ndx;
18092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  else
18192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
18292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      ehdr->e_shstrndx = SHN_XINDEX;
18392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      Elf_Scn *zscn = elf_getscn (elf, 0);
18492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      GElf_Shdr zshdr_mem;
18592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      GElf_Shdr *zshdr = gelf_getshdr (zscn, &zshdr_mem);
18692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (zshdr == NULL)
18792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	return -1;
18892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      zshdr->sh_link = ndx;
18992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (gelf_update_shdr (zscn, zshdr) == 0)
19092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	return -1;
19192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
19292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
19392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (gelf_update_ehdr (elf, ehdr) == 0)
19492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    return -1;
19592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
19692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  return 0;
19792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard}
19892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
19992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardstatic int
20092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardcompress_section (Elf_Scn *scn, size_t orig_size, const char *name,
20192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  const char *newname, size_t ndx,
20292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  bool gnu, bool compress, bool report_verbose)
20392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard{
20492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  int res;
20592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  unsigned int flags = compress && force ? ELF_CHF_FORCE : 0;
20692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (gnu)
20792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    res = elf_compress_gnu (scn, compress ? 1 : 0, flags);
20892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  else
20992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    res = elf_compress (scn, compress ? ELFCOMPRESS_ZLIB : 0, flags);
21092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
21192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (res < 0)
21292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    error (0, 0, "Couldn't decompress section [%zd] %s: %s",
21392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	   ndx, name, elf_errmsg (-1));
21492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  else
21592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
21692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (compress && res == 0)
21792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
21892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (verbose >= 0)
21992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    printf ("[%zd] %s NOT compressed, wouldn't be smaller\n",
22092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    ndx, name);
22192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
22292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
22392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (report_verbose && res > 0)
22492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
22592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  printf ("[%zd] %s %s", ndx, name,
22692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  compress ? "compressed" : "decompressed");
22792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (newname != NULL)
22892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    printf (" -> %s", newname);
22992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
23092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  /* Reload shdr, it has changed.  */
23192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  GElf_Shdr shdr_mem;
23292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
23392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (shdr == NULL)
23492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
23592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      error (0, 0, "Couldn't get shdr for section [%zd]", ndx);
23692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      return -1;
23792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
23892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  float new = shdr->sh_size;
23992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  float orig = orig_size ?: 1;
2403a5fc51573ae88a06d2050ef8425336e23013852Mark Wielaard	  printf (" (%zu => %" PRIu64 " %.2f%%)\n",
24192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  orig_size, shdr->sh_size, (new / orig) * 100);
24292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
24392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
24492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
24592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  return res;
24692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard}
24792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
24892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardstatic int
24992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardprocess_file (const char *fname)
25092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard{
25192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (verbose > 0)
25292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    printf ("processing: %s\n", fname);
25392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
25492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* The input ELF.  */
25592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  int fd = -1;
25692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  Elf *elf = NULL;
25792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
25892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* The output ELF.  */
25992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  char *fnew = NULL;
26092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  int fdnew = -1;
26192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  Elf *elfnew = NULL;
26292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
26392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Buffer for (one) new section name if necessary.  */
26492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  char *snamebuf = NULL;
26592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
26692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* String table (and symbol table), if section names need adjusting.  */
26792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  struct Ebl_Strtab *names = NULL;
26892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  struct Ebl_Strent **scnstrents = NULL;
26992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  struct Ebl_Strent **symstrents = NULL;
27092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  char **scnnames = NULL;
27192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
27292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Section data from names.  */
27392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  void *namesbuf = NULL;
27492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
27592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Which sections match and need to be (un)compressed.  */
27692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  unsigned int *sections = NULL;
27792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
27892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* How many sections are we talking about?  */
27992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  size_t shnum = 0;
28092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
28192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard#define WORD_BITS (8U * sizeof (unsigned int))
28292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  void set_section (size_t ndx)
28392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  {
28492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    sections[ndx / WORD_BITS] |= (1U << (ndx % WORD_BITS));
28592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  }
28692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
28792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  bool get_section (size_t ndx)
28892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  {
28992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    return (sections[ndx / WORD_BITS] & (1U << (ndx % WORD_BITS))) != 0;
29092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  }
29192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
29292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  int cleanup (int res)
29392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  {
29492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    elf_end (elf);
29592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    close (fd);
29692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
29792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    elf_end (elfnew);
29892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    close (fdnew);
29992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
30092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    if (fnew != NULL)
30192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      {
30292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	unlink (fnew);
30392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	free (fnew);
30492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	fnew = NULL;
30592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      }
30692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
30792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    free (snamebuf);
30892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    if (names != NULL)
30992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      {
31092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	ebl_strtabfree (names);
31192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	free (scnstrents);
31292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	free (symstrents);
31392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	free (namesbuf);
31492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	if (scnnames != NULL)
31592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  {
31692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    for (size_t n = 0; n < shnum; n++)
31792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      free (scnnames[n]);
31892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    free (scnnames);
31992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  }
32092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      }
32192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
32292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    free (sections);
32392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
32492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    return res;
32592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  }
32692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
32792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  fd = open (fname, O_RDONLY);
32892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (fd < 0)
32992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
33092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      error (0, errno, "Couldn't open %s\n", fname);
33192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      return cleanup (-1);
33292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
33392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
33492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  elf = elf_begin (fd, ELF_C_READ, NULL);
33592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (elf == NULL)
33692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
33792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      error (0, 0, "Couldn't open ELF file %s for reading: %s",
33892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	     fname, elf_errmsg (-1));
33992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      return cleanup (-1);
34092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
34192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
34292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* We dont' handle ar files (or anything else), we probably should.  */
34392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  Elf_Kind kind = elf_kind (elf);
34492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (kind != ELF_K_ELF)
34592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
34692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (kind == ELF_K_AR)
34792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	error (0, 0, "Cannot handle ar files: %s", fname);
34892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      else
34992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	error (0, 0, "Unknown file type: %s", fname);
35092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      return cleanup (-1);
35192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
35292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
35392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  struct stat st;
35492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (fstat (fd, &st) != 0)
35592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
35692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      error (0, errno, "Couldn't fstat %s", fname);
35792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      return cleanup (-1);
35892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
35992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
36092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  GElf_Ehdr ehdr;
36192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (gelf_getehdr (elf, &ehdr) == NULL)
36292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
36392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      error (0, 0, "Couldn't get ehdr for %s: %s", fname, elf_errmsg (-1));
36492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      return cleanup (-1);
36592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
36692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
36792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Get the section header string table.  */
36892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  size_t shdrstrndx;
36992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (elf_getshdrstrndx (elf, &shdrstrndx) != 0)
37092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
37192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      error (0, 0, "Couldn't get section header string table index in %s: %s",
37292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	     fname, elf_errmsg (-1));
37392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      return cleanup (-1);
37492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
37592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
37692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* How many sections are we talking about?  */
37792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (elf_getshdrnum (elf, &shnum) != 0)
37892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
37992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      error (0, 0, "Couldn't get number of sections in %s: %s",
38092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	     fname, elf_errmsg (1));
38192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      return cleanup (-1);
38292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
38392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
38492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (shnum == 0)
38592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
38692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      error (0, 0, "ELF file %s has no sections", fname);
38792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      return cleanup (-1);
38892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
38992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
39092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  sections = xcalloc (shnum / 8 + 1, sizeof (unsigned int));
39192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
39292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  size_t phnum;
39392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (elf_getphdrnum (elf, &phnum) != 0)
39492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
39592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      error (0, 0, "Couldn't get phdrnum: %s", elf_errmsg (-1));
39692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      return cleanup (-1);
39792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
39892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
39992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Whether we need to adjust any section names (going to/from GNU
40092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     naming).  If so we'll need to build a new section header string
40192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     table.  */
40292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  bool adjust_names = false;
40392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
40492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* If there are phdrs we want to maintain the layout of the
40592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     allocated sections in the file.  */
40692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  bool layout = phnum != 0;
40792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
40892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* While going through all sections keep track of last section data
40992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     offset if needed to keep the layout.  We are responsible for
41092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     adding the section offsets and headers (e_shoff) in that case
41192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     (which we will place after the last section).  */
41292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  GElf_Off last_offset = 0;
41392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (layout)
41492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    last_offset = (ehdr.e_phoff
41592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		   + gelf_fsize (elf, ELF_T_PHDR, phnum, EV_CURRENT));
41692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
41792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Which section, if any, is a symbol table that shares a string
41892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     table with the section header string table?  */
41992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  size_t symtabndx = 0;
42092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
42192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* We do three passes over all sections.
42292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
42392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     First an inspection pass over the old Elf to see which section
42492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     data needs to be copied and/or transformed, which sections need a
42592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     names change and whether there is a symbol table that might need
42692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     to be adjusted be if the section header name table is changed.
42792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
42892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     Second a collection pass that creates the Elf sections and copies
42992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     the data.  This pass will compress/decompress section data when
43092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     needed.  And it will collect all data needed if we'll need to
43192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     construct a new string table. Afterwards the new string table is
43292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     constructed.
43392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
43492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     Third a fixup/adjustment pass over the new Elf that will adjust
43592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     any section references (names) and adjust the layout based on the
43692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     new sizes of the sections if necessary.  This pass is optional if
43792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     we aren't responsible for the layout and the section header
43892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     string table hasn't been changed.  */
43992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
44092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Inspection pass.  */
44192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  size_t maxnamelen = 0;
44292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  Elf_Scn *scn = NULL;
44392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  while ((scn = elf_nextscn (elf, scn)) != NULL)
44492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
44592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      size_t ndx = elf_ndxscn (scn);
44692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (ndx > shnum)
44792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
44892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  error (0, 0, "Unexpected section number %zd, expected only %zd",
44992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		 ndx, shnum);
45092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  cleanup (-1);
45192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
45292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
45392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      GElf_Shdr shdr_mem;
45492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
45592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (shdr == NULL)
45692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
45792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  error (0, 0, "Couldn't get shdr for section %zd", ndx);
45892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  return cleanup (-1);
45992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
46092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
46192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      const char *sname = elf_strptr (elf, shdrstrndx, shdr->sh_name);
46292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (sname == NULL)
46392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
46492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  error (0, 0, "Couldn't get name for section %zd", ndx);
46592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  return cleanup (-1);
46692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
46792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
46892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (section_name_matches (sname))
46992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
47092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (shdr->sh_type != SHT_NOBITS
47192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      && (shdr->sh_flags & SHF_ALLOC) == 0)
47292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
47392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      set_section (ndx);
47492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      /* Check if we might want to change this section name.  */
47592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      if (! adjust_names
47692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  && ((type != T_COMPRESS_GNU
47792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		       && strncmp (sname, ".zdebug",
47892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard				   strlen (".zdebug")) == 0)
47992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      || (type == T_COMPRESS_GNU
48092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  && strncmp (sname, ".debug",
48192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard				      strlen (".debug")) == 0)))
48292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		adjust_names = true;
48392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
48492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      /* We need a buffer this large if we change the names.  */
48592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      if (adjust_names)
48692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		{
48792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  size_t slen = strlen (sname);
48892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  if (slen > maxnamelen)
48992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    maxnamelen = slen;
49092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		}
49192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
49292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  else
49392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    if (verbose >= 0)
49492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      printf ("[%zd] %s ignoring %s section\n", ndx, sname,
49592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      (shdr->sh_type == SHT_NOBITS ? "no bits" : "allocated"));
49692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
49792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
49892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (shdr->sh_type == SHT_SYMTAB)
49992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
50092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  /* Check if we might have to adjust the symbol name indexes.  */
50192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (shdr->sh_link == shdrstrndx)
50292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
50392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      if (symtabndx != 0)
50492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		{
50592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  error (0, 0,
50692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			 "Multiple symbol tables (%zd, %zd) using the same string table unsupported", symtabndx, ndx);
50792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  return cleanup (-1);
50892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		}
50992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      symtabndx = ndx;
51092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
51192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
51292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
51392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      /* Keep track of last allocated data offset.  */
51492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (layout)
51592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	if ((shdr->sh_flags & SHF_ALLOC) != 0)
51692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  {
51792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    GElf_Off off = shdr->sh_offset + (shdr->sh_type != SHT_NOBITS
51892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard					      ? shdr->sh_size : 0);
51992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    if (last_offset < off)
52092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      last_offset = off;
52192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  }
52292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
52392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
52492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (adjust_names)
52592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
52692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      names = ebl_strtabinit (true);
52792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (names == NULL)
52892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
52992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  error (0, 0, "Not enough memory for new strtab");
53092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  return cleanup (-1);
53192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
53292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      scnstrents = xmalloc (shnum
53392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			    * sizeof (struct Ebl_Strent *));
53492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      scnnames = xcalloc (shnum, sizeof (char *));
53592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
53692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
53792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Create a new (temporary) ELF file for the result.  */
53892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (foutput == NULL)
53992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
54092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      size_t fname_len = strlen (fname);
54192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      fnew = xmalloc (fname_len + sizeof (".XXXXXX"));
54292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      strcpy (mempcpy (fnew, fname, fname_len), ".XXXXXX");
54392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      fdnew = mkstemp (fnew);
54492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
54592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  else
54692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
54792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      fnew = xstrdup (foutput);
54892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      fdnew = open (fnew, O_WRONLY | O_CREAT, st.st_mode & ALLPERMS);
54992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
55092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
55192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (fdnew < 0)
55292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
55392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      error (0, errno, "Couldn't create output file %s", fnew);
55492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      /* Since we didn't create it we don't want to try to unlink it.  */
55592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      free (fnew);
55692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      fnew = NULL;
55792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      return cleanup (-1);
55892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
55992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
56092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  elfnew = elf_begin (fdnew, ELF_C_WRITE, NULL);
56192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (elfnew == NULL)
56292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
56392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      error (0, 0, "Couldn't open new ELF %s for writing: %s",
56492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	     fnew, elf_errmsg (-1));
56592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      return cleanup (-1);
56692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
56792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
56892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Create the new ELF header and copy over all the data.  */
56992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (gelf_newehdr (elfnew, gelf_getclass (elf)) == 0)
57092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
57192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      error (0, 0, "Couldn't create new ehdr: %s", elf_errmsg (-1));
57292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      return cleanup (-1);
57392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
57492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
57592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  GElf_Ehdr newehdr;
57692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (gelf_getehdr (elfnew, &newehdr) == NULL)
57792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
57892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      error (0, 0, "Couldn't get new ehdr: %s", elf_errmsg (-1));
57992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      return cleanup (-1);
58092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
58192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
58292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  newehdr.e_ident[EI_DATA] = ehdr.e_ident[EI_DATA];
58392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  newehdr.e_type = ehdr.e_type;
58492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  newehdr.e_machine = ehdr.e_machine;
58592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  newehdr.e_version = ehdr.e_version;
58692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  newehdr.e_entry = ehdr.e_entry;
58792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  newehdr.e_flags = ehdr.e_flags;
58892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
58992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (gelf_update_ehdr (elfnew, &newehdr) == 0)
59092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
59192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      error (0, 0, "Couldn't update ehdr: %s", elf_errmsg (-1));
59292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      return cleanup (-1);
59392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
59492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
59592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Copy over the phdrs as is.  */
59692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (phnum != 0)
59792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
59892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (gelf_newphdr (elfnew, phnum) == 0)
59992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
60092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  error (0, 0, "Couldn't create phdrs: %s", elf_errmsg (-1));
60192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  return cleanup (-1);
60292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
60392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
60492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      for (size_t cnt = 0; cnt < phnum; ++cnt)
60592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
60692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  GElf_Phdr phdr_mem;
60792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem);
60892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (phdr == NULL)
60992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
61092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      error (0, 0, "Couldn't get phdr %zd: %s", cnt, elf_errmsg (-1));
61192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      return cleanup (-1);
61292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
61392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (gelf_update_phdr (elfnew, cnt, phdr) == 0)
61492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
61592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      error (0, 0, "Couldn't create phdr %zd: %s", cnt,
61692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		     elf_errmsg (-1));
61792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      return cleanup (-1);
61892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
61992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
62092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
62192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
62292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Possibly add a 'z' and zero terminator.  */
62392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (maxnamelen > 0)
62492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    snamebuf = xmalloc (maxnamelen + 2);
62592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
62692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* We might want to read/adjust the section header strings and
62792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     symbol tables.  If so, and those sections are to be compressed
62892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     then we will have to decompress it during the collection pass and
62992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     compress it again in the fixup pass.  Don't compress unnecessary
63092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     and keep track of whether or not to compress them (later in the
63192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     fixup pass).  Also record the original size, so we can report the
63292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     difference later when we do compress.  */
63392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  int shstrtab_compressed = T_UNSET;
63492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  size_t shstrtab_size = 0;
63592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  char *shstrtab_name = NULL;
63692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  char *shstrtab_newname = NULL;
63792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  int symtab_compressed = T_UNSET;
63892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  size_t symtab_size = 0;
63992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  char *symtab_name = NULL;
64092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  char *symtab_newname = NULL;
64192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
64292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Collection pass.  Copy over the sections, (de)compresses matching
64392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     sections, collect names of sections and symbol table if
64492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     necessary.  */
64592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  scn = NULL;
64692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  while ((scn = elf_nextscn (elf, scn)) != NULL)
64792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
64892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      size_t ndx = elf_ndxscn (scn);
64992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      assert (ndx < shnum);
65092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
65192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      /* (de)compress if section matched.  */
65292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      char *sname = NULL;
65392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      char *newname = NULL;
65492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (get_section (ndx))
65592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
65692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  GElf_Shdr shdr_mem;
65792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
65892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (shdr == NULL)
65992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
66092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      error (0, 0, "Couldn't get shdr for section %zd", ndx);
66192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      return cleanup (-1);
66292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
66392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
66492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  uint64_t size = shdr->sh_size;
66592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  sname = elf_strptr (elf, shdrstrndx, shdr->sh_name);
66692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (sname == NULL)
66792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
66892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      error (0, 0, "Couldn't get name for section %zd", ndx);
66992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      return cleanup (-1);
67092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
67192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
67292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  /* strdup sname, the shdrstrndx section itself might be
67392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	     (de)compressed, invalidating the string pointers.  */
67492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  sname = xstrdup (sname);
67592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
67692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  /* We might want to decompress (and rename), but not
67792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	     compress during this pass since we might need the section
67892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	     data in later passes.  Skip those sections for now and
67992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	     compress them in the fixup pass.  */
68092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  bool skip_compress_section = (adjust_names
68192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard					&& (ndx == shdrstrndx
68292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard					    || ndx == symtabndx));
68392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
68492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  switch (type)
68592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
68692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    case T_DECOMPRESS:
68792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
68892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		{
68992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  if (compress_section (scn, size, sname, NULL, ndx,
69092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard					false, false, verbose > 0) < 0)
69192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    return cleanup (-1);
69292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		}
69392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      else if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
69492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		{
69592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  snamebuf[0] = '.';
69692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  strcpy (&snamebuf[1], &sname[2]);
69792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  newname = snamebuf;
69892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  if (compress_section (scn, size, sname, newname, ndx,
69992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard					true, false, verbose > 0) < 0)
70092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    return cleanup (-1);
70192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		}
70292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      else if (verbose > 0)
70392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		printf ("[%zd] %s already decompressed\n", ndx, sname);
70492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      break;
70592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
70692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    case T_COMPRESS_GNU:
70792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      if (strncmp (sname, ".debug", strlen (".debug")) == 0)
70892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		{
70992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
71092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    {
71192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      /* First decompress to recompress GNU style.
71292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			 Don't report even when verbose.  */
71392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      if (compress_section (scn, size, sname, NULL, ndx,
71492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard					    false, false, false) < 0)
71592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			return cleanup (-1);
71692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    }
71792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
71892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  snamebuf[0] = '.';
71992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  snamebuf[1] = 'z';
72092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  strcpy (&snamebuf[2], &sname[1]);
72192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  newname = snamebuf;
72292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
72392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  if (skip_compress_section)
72492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    {
72592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      if (ndx == shdrstrndx)
72692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			{
72792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  shstrtab_size = size;
72892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  shstrtab_compressed = T_COMPRESS_GNU;
72992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  shstrtab_name = xstrdup (sname);
73092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  shstrtab_newname = xstrdup (newname);
73192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			}
73292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      else
73392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			{
73492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  symtab_size = size;
73592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  symtab_compressed = T_COMPRESS_GNU;
73692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  symtab_name = xstrdup (sname);
73792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  symtab_newname = xstrdup (newname);
73892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			}
73992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    }
74092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  else
74192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    {
74292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      int res = compress_section (scn, size, sname, newname,
74392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard						  ndx, true, true,
74492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard						  verbose > 0);
74592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      if (res < 0)
74692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			return cleanup (-1);
74792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
74892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      if (res == 0)
74992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			newname = NULL;
75092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    }
75192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		}
75292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      else if (verbose >= 0)
75392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		{
75492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
75592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    printf ("[%zd] %s unchanged, already GNU compressed",
75692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			    ndx, sname);
75792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  else
75892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    printf ("[%zd] %s cannot GNU compress section not starting with .debug\n",
75992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			    ndx, sname);
76092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		}
76192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      break;
76292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
76392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    case T_COMPRESS_ZLIB:
76492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
76592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		{
76692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
76792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    {
76892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      /* First decompress to recompress zlib style.
76992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			 Don't report even when verbose.  */
77092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      if (compress_section (scn, size, sname, NULL, ndx,
77192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard					    true, false, false) < 0)
77292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			return cleanup (-1);
77392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
77492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      snamebuf[0] = '.';
77592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      strcpy (&snamebuf[1], &sname[2]);
77692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      newname = snamebuf;
77792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    }
77892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
77992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  if (skip_compress_section)
78092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    {
78192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      if (ndx == shdrstrndx)
78292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			{
78392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  shstrtab_size = size;
78492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  shstrtab_compressed = T_COMPRESS_ZLIB;
78592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  shstrtab_name = xstrdup (sname);
78692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  shstrtab_newname = (newname == NULL
78792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard					      ? NULL : xstrdup (newname));
78892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			}
78992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      else
79092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			{
79192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  symtab_size = size;
79292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  symtab_compressed = T_COMPRESS_ZLIB;
79392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  symtab_name = xstrdup (sname);
79492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  symtab_newname = (newname == NULL
79592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard					    ? NULL : xstrdup (newname));
79692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			}
79792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    }
79892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  else if (compress_section (scn, size, sname, newname, ndx,
79992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard					     false, true, verbose > 0) < 0)
80092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    return cleanup (-1);
80192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		}
80292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      else if (verbose > 0)
80392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		printf ("[%zd] %s already compressed\n", ndx, sname);
80492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      break;
80592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
80692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
80792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  free (sname);
80892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
80992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
81092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      Elf_Scn *newscn = elf_newscn (elfnew);
81192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (newscn == NULL)
81292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
81392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  error (0, 0, "Couldn't create new section %zd", ndx);
81492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  return cleanup (-1);
81592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
81692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
81792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      GElf_Shdr shdr_mem;
81892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
81992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (shdr == NULL)
82092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
82192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  error (0, 0, "Couldn't get shdr for section %zd", ndx);
82292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  return cleanup (-1);
82392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
82492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
82592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (gelf_update_shdr (newscn, shdr) == 0)
82692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard        {
82792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  error (0, 0, "Couldn't update section header %zd", ndx);
82892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  return cleanup (-1);
82992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
83092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
83192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      /* Except for the section header string table all data can be
83292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	 copied as is.  The section header string table will be
83392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	 created later and the symbol table might be fixed up if
83492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	 necessary.  */
83592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (! adjust_names || ndx != shdrstrndx)
83692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
83792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  Elf_Data *data = elf_getdata (scn, NULL);
83892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (data == NULL)
83992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
84092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      error (0, 0, "Couldn't get data from section %zd", ndx);
84192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      return cleanup (-1);
84292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
84392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
84492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  Elf_Data *newdata = elf_newdata (newscn);
84592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (newdata == NULL)
84692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
84792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      error (0, 0, "Couldn't create new data for section %zd", ndx);
84892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      return cleanup (-1);
84992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
85092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
85192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  *newdata = *data;
85292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
85392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
85492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      /* Keep track of the (new) section names.  */
85592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (adjust_names)
85692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
85792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  char *name;
85892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (newname != NULL)
85992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    name = newname;
86092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  else
86192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
86292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      name = elf_strptr (elf, shdrstrndx, shdr->sh_name);
86392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      if (name == NULL)
86492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		{
86592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  error (0, 0, "Couldn't get name for section [%zd]", ndx);
86692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  return cleanup (-1);
86792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		}
86892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
86992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
87092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  /* We need to keep a copy of the name till the strtab is done.  */
87192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  name = scnnames[ndx] = xstrdup (name);
87292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if ((scnstrents[ndx] = ebl_strtabadd (names, name, 0)) == NULL)
87392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
87492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      error (0, 0, "No memory to add section name string table");
87592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      return cleanup (-1);
87692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
87792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
87892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  /* If the symtab shares strings then add those too.  */
87992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (ndx == symtabndx)
88092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
88192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      /* If the section is (still) compressed we'll need to
88292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		 uncompress it first to adjust the data, then
88392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		 recompress it in the fixup pass.  */
88492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      if (symtab_compressed == T_UNSET)
88592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		{
88692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  size_t size = shdr->sh_size;
88792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  if ((shdr->sh_flags == SHF_COMPRESSED) != 0)
88892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    {
88992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      /* Don't report the (internal) uncompression.  */
89092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      if (compress_section (newscn, size, sname, NULL, ndx,
89192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard					    false, false, false) < 0)
89292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			return cleanup (-1);
89392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
89492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      symtab_size = size;
89592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      symtab_compressed = T_COMPRESS_ZLIB;
89692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    }
89792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  else if (strncmp (name, ".zdebug", strlen (".zdebug")) == 0)
89892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    {
89992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      /* Don't report the (internal) uncompression.  */
90092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      if (compress_section (newscn, size, sname, NULL, ndx,
90192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard					    true, false, false) < 0)
90292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			return cleanup (-1);
90392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
90492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      symtab_size = size;
90592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      symtab_compressed = T_COMPRESS_GNU;
90692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    }
90792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		}
90892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
90992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      Elf_Data *symd = elf_getdata (newscn, NULL);
91092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      if (symd == NULL)
91192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		{
91292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  error (0, 0, "Couldn't get symtab data for section [%zd] %s",
91392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			 ndx, name);
91492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  return cleanup (-1);
91592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		}
91692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      size_t elsize = gelf_fsize (elfnew, ELF_T_SYM, 1, EV_CURRENT);
91792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      size_t syms = symd->d_size / elsize;
91892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      symstrents = xmalloc (syms * sizeof (struct Ebl_Strent *));
91992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      for (size_t i = 0; i < syms; i++)
92092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		{
92192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  GElf_Sym sym_mem;
92292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  GElf_Sym *sym = gelf_getsym (symd, i, &sym_mem);
92392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  if (sym == NULL)
92492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    {
92592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      error (0, 0, "Couldn't get symbol %zd", i);
92692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      return cleanup (-1);
92792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    }
92892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  if (sym->st_name != 0)
92992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    {
93092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      /* Note we take the name from the original ELF,
93192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			 since the new one will not have setup the
93292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			 strtab yet.  */
93392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      const char *symname = elf_strptr (elf, shdrstrndx,
93492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard							sym->st_name);
93592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      if (symname == NULL)
93692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			{
93792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  error (0, 0, "Couldn't get symbol %zd name", i);
93892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  return cleanup (-1);
93992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			}
94092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      symstrents[i] = ebl_strtabadd (names, symname, 0);
94192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      if (symstrents[i] == NULL)
94292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			{
94392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  error (0, 0, "No memory to add to symbol name");
94492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  return cleanup (-1);
94592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			}
94692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    }
94792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		}
94892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
94992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
95092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
95192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
95292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (adjust_names)
95392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
95492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      /* We got all needed strings, put the new data in the shstrtab.  */
95592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (verbose > 0)
95692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	printf ("[%zd] Updating section string table\n", shdrstrndx);
95792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
95892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      scn = elf_getscn (elfnew, shdrstrndx);
95992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (scn == NULL)
96092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
96192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  error (0, 0, "Couldn't get new section header string table [%zd]",
96292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		 shdrstrndx);
96392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  return cleanup (-1);
96492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
96592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
96692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      Elf_Data *data = elf_newdata (scn);
96792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (data == NULL)
96892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
96992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  error (0, 0, "Couldn't create new section header string table data");
97092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  return cleanup (-1);
97192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
97292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      ebl_strtabfinalize (names, data);
97392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      namesbuf = data->d_buf;
97492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
97592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      GElf_Shdr shdr_mem;
97692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
97792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (shdr == NULL)
97892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
97992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  error (0, 0, "Couldn't get shdr for new section strings %zd",
98092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		 shdrstrndx);
98192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  return cleanup (-1);
98292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
98392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
98492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      /* Note that we also might have to compress and possibly set
98592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	 sh_off below */
98692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      shdr->sh_name = ebl_strtaboffset (scnstrents[shdrstrndx]);
98792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      shdr->sh_type = SHT_STRTAB;
98892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      shdr->sh_flags = 0;
98992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      shdr->sh_addr = 0;
99092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      shdr->sh_offset = 0;
99192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      shdr->sh_size = data->d_size;
99292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      shdr->sh_link = SHN_UNDEF;
99392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      shdr->sh_info = SHN_UNDEF;
99492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      shdr->sh_addralign = 1;
99592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      shdr->sh_entsize = 0;
99692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
99792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (gelf_update_shdr (scn, shdr) == 0)
99892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
99992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  error (0, 0, "Couldn't update new section strings [%zd]",
100092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		 shdrstrndx);
100192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  return cleanup (-1);
100292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
100392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
100492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      /* We might have to compress the data if the user asked us to,
100592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	 or if the section was already compressed (and the user didn't
100692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	 ask for decompression).  Note somewhat identical code for
100792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	 symtab below.  */
100892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (shstrtab_compressed == T_UNSET)
100992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
101092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  /* The user didn't ask for compression, but maybe it was
101192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	     compressed in the original ELF file.  */
101292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  Elf_Scn *oldscn = elf_getscn (elf, shdrstrndx);
101392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (oldscn == NULL)
101492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
101592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      error (0, 0, "Couldn't get section header string table [%zd]",
101692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		     shdrstrndx);
101792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      return cleanup (-1);
101892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
101992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
102092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  shdr = gelf_getshdr (oldscn, &shdr_mem);
102192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (shdr == NULL)
102292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
102392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      error (0, 0, "Couldn't get shdr for old section strings [%zd]",
102492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		     shdrstrndx);
102592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      return cleanup (-1);
102692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
102792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
102892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  shstrtab_name = elf_strptr (elf, shdrstrndx, shdr->sh_name);
102992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (shstrtab_name == NULL)
103092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
103192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      error (0, 0, "Couldn't get name for old section strings [%zd]",
103292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		     shdrstrndx);
103392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      return cleanup (-1);
103492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
103592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
103692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  shstrtab_size = shdr->sh_size;
103792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
103892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    shstrtab_compressed = T_COMPRESS_ZLIB;
103992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  else if (strncmp (shstrtab_name, ".zdebug", strlen (".zdebug")) == 0)
104092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    shstrtab_compressed = T_COMPRESS_GNU;
104192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
104292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
104392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      /* Should we (re)compress?  */
104492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (shstrtab_compressed != T_UNSET)
104592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
104692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (compress_section (scn, shstrtab_size, shstrtab_name,
104792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard				shstrtab_newname, shdrstrndx,
104892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard				shstrtab_compressed == T_COMPRESS_GNU,
104992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard				true, verbose > 0) < 0)
105092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    return cleanup (-1);
105192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
105292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
105392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
105492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Make sure to re-get the new ehdr.  Adding phdrs and shdrs will
105592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     have changed it.  */
105692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (gelf_getehdr (elfnew, &newehdr) == NULL)
105792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
105892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      error (0, 0, "Couldn't re-get new ehdr: %s", elf_errmsg (-1));
105992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      return cleanup (-1);
106092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
106192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
106292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Set this after the sections have been created, otherwise section
106392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     zero might not exist yet.  */
106492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (setshdrstrndx (elfnew, &newehdr, shdrstrndx) != 0)
106592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
106692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      error (0, 0, "Couldn't set new shdrstrndx: %s", elf_errmsg (-1));
106792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      return cleanup (-1);
106892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
106992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
107092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Fixup pass.  Adjust string table references, symbol table and
107192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     layout if necessary.  */
107292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (layout || adjust_names)
107392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
107492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      scn = NULL;
107592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      while ((scn = elf_nextscn (elfnew, scn)) != NULL)
107692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
107792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  size_t ndx = elf_ndxscn (scn);
107892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
107992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  GElf_Shdr shdr_mem;
108092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
108192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (shdr == NULL)
108292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
108392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      error (0, 0, "Couldn't get shdr for section %zd", ndx);
108492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      return cleanup (-1);
108592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
108692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
108792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  /* Keep the offset of allocated sections so they are at the
108892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	     same place in the file. Add (possibly changed)
108992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	     unallocated ones after the allocated ones.  */
109092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if ((shdr->sh_flags & SHF_ALLOC) == 0)
109192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
109292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      /* Zero means one.  No alignment constraints.  */
109392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      size_t addralign = shdr->sh_addralign ?: 1;
109492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      last_offset = (last_offset + addralign - 1) & ~(addralign - 1);
109592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      shdr->sh_offset = last_offset;
109692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      if (shdr->sh_type != SHT_NOBITS)
109792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		last_offset += shdr->sh_size;
109892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
109992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
110092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (adjust_names)
110192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    shdr->sh_name = ebl_strtaboffset (scnstrents[ndx]);
110292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
110392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (gelf_update_shdr (scn, shdr) == 0)
110492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
110592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      error (0, 0, "Couldn't update section header %zd", ndx);
110692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      return cleanup (-1);
110792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
110892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
110992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  if (adjust_names && ndx == symtabndx)
111092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    {
111192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      if (verbose > 0)
111292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		printf ("[%zd] Updating symbol table\n", symtabndx);
111392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
111492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      Elf_Data *symd = elf_getdata (scn, NULL);
111592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      if (symd == NULL)
111692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		{
111792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  error (0, 0, "Couldn't get new symtab data section [%zd]",
111892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			 ndx);
111992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  return cleanup (-1);
112092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		}
112192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      size_t elsize = gelf_fsize (elfnew, ELF_T_SYM, 1, EV_CURRENT);
112292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      size_t syms = symd->d_size / elsize;
112392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      for (size_t i = 0; i < syms; i++)
112492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		{
112592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  GElf_Sym sym_mem;
112692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  GElf_Sym *sym = gelf_getsym (symd, i, &sym_mem);
112792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  if (sym == NULL)
112892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    {
112992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      error (0, 0, "2 Couldn't get symbol %zd", i);
113092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      return cleanup (-1);
113192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    }
113292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
113392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  if (sym->st_name != 0)
113492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    {
113592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      sym->st_name = ebl_strtaboffset (symstrents[i]);
113692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
113792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      if (gelf_update_sym (symd, i, sym) == 0)
113892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			{
113992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  error (0, 0, "Couldn't update symbol %zd", i);
114092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			  return cleanup (-1);
114192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			}
114292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    }
114392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		}
114492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
114592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      /* We might have to compress the data if the user asked
114692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		 us to, or if the section was already compressed (and
114792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		 the user didn't ask for decompression).  Note
114892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		 somewhat identical code for shstrtab above.  */
114992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      if (symtab_compressed == T_UNSET)
115092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		{
115192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  /* The user didn't ask for compression, but maybe it was
115292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		     compressed in the original ELF file.  */
115392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  Elf_Scn *oldscn = elf_getscn (elf, symtabndx);
115492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  if (oldscn == NULL)
115592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    {
115692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      error (0, 0, "Couldn't get symbol table [%zd]",
115792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			     symtabndx);
115892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      return cleanup (-1);
115992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    }
116092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
116192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  shdr = gelf_getshdr (oldscn, &shdr_mem);
116292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  if (shdr == NULL)
116392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    {
116492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      error (0, 0, "Couldn't get old symbol table shdr [%zd]",
116592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			     symtabndx);
116692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      return cleanup (-1);
116792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    }
116892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
116992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  symtab_name = elf_strptr (elf, shdrstrndx, shdr->sh_name);
117092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  if (symtab_name == NULL)
117192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    {
117292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      error (0, 0, "Couldn't get old symbol table name [%zd]",
117392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			     symtabndx);
117492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		      return cleanup (-1);
117592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    }
117692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
117792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  symtab_size = shdr->sh_size;
117892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
117992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    symtab_compressed = T_COMPRESS_ZLIB;
118092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  else if (strncmp (symtab_name, ".zdebug",
118192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard				    strlen (".zdebug")) == 0)
118292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    symtab_compressed = T_COMPRESS_GNU;
118392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		}
118492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
118592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      /* Should we (re)compress?  */
118692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	      if (symtab_compressed != T_UNSET)
118792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		{
118892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		  if (compress_section (scn, symtab_size, symtab_name,
118992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard					symtab_newname, symtabndx,
119092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard					symtab_compressed == T_COMPRESS_GNU,
119192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard					true, verbose > 0) < 0)
119292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		    return cleanup (-1);
119392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard		}
119492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	    }
119592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
119692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
119792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
119892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* If we have phdrs we want elf_update to layout the SHF_ALLOC
119992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     sections precisely as in the original file.  In that case we are
120092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     also responsible for setting phoff and shoff */
120192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (layout)
120292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
120392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (gelf_getehdr (elfnew, &newehdr) == NULL)
120492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
120592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  error (0, 0, "Couldn't get ehdr: %s", elf_errmsg (-1));
120692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  return cleanup (-1);
120792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
120892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
120992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      /* Position the shdrs after the last (unallocated) section.  */
121092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      const size_t offsize = gelf_fsize (elfnew, ELF_T_OFF, 1, EV_CURRENT);
121192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      newehdr.e_shoff = ((last_offset + offsize - 1)
121292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard			 & ~((GElf_Off) (offsize - 1)));
121392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
121492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      /* The phdrs go in the same place as in the original file.
121592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	 Normally right after the ELF header.  */
121692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      newehdr.e_phoff = ehdr.e_phoff;
121792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
121892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      if (gelf_update_ehdr (elfnew, &newehdr) == 0)
121992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	{
122092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  error (0, 0, "Couldn't update ehdr: %s", elf_errmsg (-1));
122192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	  return cleanup (-1);
122292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	}
122392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
122492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
122592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  elf_flagelf (elfnew, ELF_C_SET, ((layout ? ELF_F_LAYOUT : 0)
122692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard				   | (permissive ? ELF_F_PERMISSIVE : 0)));
122792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
122892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (elf_update (elfnew, ELF_C_WRITE) < 0)
122992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
123092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      error (0, 0, "Couldn't write %s: %s", fnew, elf_errmsg (-1));
123192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      return cleanup (-1);
123292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    }
123392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
123492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  elf_end (elfnew);
123592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  elfnew = NULL;
123692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
123792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Try to match mode and owner.group of the original file.  */
123892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (fchmod (fdnew, st.st_mode & ALLPERMS) != 0)
123992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    if (verbose >= 0)
124092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      error (0, errno, "Couldn't fchmod %s", fnew);
124192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (fchown (fdnew, st.st_uid, st.st_gid) != 0)
124292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    if (verbose >= 0)
124392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      error (0, errno, "Couldn't fchown %s", fnew);
124492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
124592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Finally replace the old file with the new file.  */
124692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (foutput == NULL)
124792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    if (rename (fnew, fname) != 0)
124892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      {
124992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	error (0, errno, "Couldn't rename %s to %s", fnew, fname);
125092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	return cleanup (-1);
125192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      }
125292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
125392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* We are finally done with the new file, don't unlink it now.  */
125492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  free (fnew);
125592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  fnew = NULL;
125692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
125792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  return cleanup (0);
125892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard}
125992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
126092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardint
126192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaardmain (int argc, char **argv)
126292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard{
126392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  const struct argp_option options[] =
126492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
126592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      { "output", 'o', "FILE", 0,
126692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	N_("Place (de)compressed output into FILE"),
126792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	0 },
126892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      { "type", 't', "TYPE", 0,
126992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	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)"),
127092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	0 },
127192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      { "name", 'n', "SECTION", 0,
127292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	N_("SECTION name to (de)compress, SECTION is an extended wildcard pattern (defaults to '.?(z)debug*')"),
127392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	0 },
127492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      { "verbose", 'v', NULL, 0,
127592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	N_("Print a message for each section being (de)compressed"),
127692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	0 },
127792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      { "force", 'f', NULL, 0,
127892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	N_("Force compression of section even if it would become larger"),
127992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	0 },
128092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      { "permissive", 'p', NULL, 0,
128192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	N_("Relax a few rules to handle slightly broken ELF files"),
128292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	0 },
128392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      { "quiet", 'q', NULL, 0,
128492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	N_("Be silent when a section cannot be compressed"),
128592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	0 },
128692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      { NULL, 0, NULL, 0, NULL, 0 }
128792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    };
128892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
128992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  const struct argp argp =
129092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    {
129192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      .options = options,
129292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      .parser = parse_opt,
129392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      .args_doc = N_("FILE..."),
129492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard      .doc = N_("Compress or decompress sections in an ELF file.")
129592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    };
129692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
129792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  int remaining;
129892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (argp_parse (&argp, argc, argv, 0, &remaining, NULL) != 0)
129992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    return EXIT_FAILURE;
130092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
130192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Should already be handled by ARGP_KEY_NO_ARGS case above,
130292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard     just sanity check.  */
130392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (remaining >= argc)
130492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    error (EXIT_FAILURE, 0, N_("No input file given"));
130592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
130692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Likewise for the ARGP_KEY_ARGS case above, an extra sanity check.  */
130792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  if (foutput != NULL && remaining + 1 < argc)
130892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    error (EXIT_FAILURE, 0,
130992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard	   N_("Only one input file allowed together with '-o'"));
131092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
131192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  elf_version (EV_CURRENT);
131292acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
131392acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  /* Process all the remaining files.  */
131492acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  int result = 0;
131592acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  do
131692acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard    result |= process_file (argv[remaining]);
131792acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  while (++remaining < argc);
131892acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard
131992acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  free_patterns ();
132092acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard  return result;
132192acb57eb0468de93c4976eb1de6bf08ede9abd0Mark Wielaard}
1322