Blame src/strip.c

Packit 032894
/* Discard section not used at runtime from object files.
Packit 032894
   Copyright (C) 2000-2012, 2014, 2015, 2016, 2017, 2018 Red Hat, Inc.
Packit 032894
   This file is part of elfutils.
Packit 032894
   Written by Ulrich Drepper <drepper@redhat.com>, 2000.
Packit 032894
Packit 032894
   This file is free software; you can redistribute it and/or modify
Packit 032894
   it under the terms of the GNU General Public License as published by
Packit 032894
   the Free Software Foundation; either version 3 of the License, or
Packit 032894
   (at your option) any later version.
Packit 032894
Packit 032894
   elfutils is distributed in the hope that it will be useful, but
Packit 032894
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 032894
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 032894
   GNU General Public License for more details.
Packit 032894
Packit 032894
   You should have received a copy of the GNU General Public License
Packit 032894
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit 032894
Packit 032894
#ifdef HAVE_CONFIG_H
Packit 032894
# include <config.h>
Packit 032894
#endif
Packit 032894
Packit 032894
#include <argp.h>
Packit 032894
#include <assert.h>
Packit 032894
#include <byteswap.h>
Packit 032894
#include <endian.h>
Packit 032894
#include <fcntl.h>
Packit 032894
#include <fnmatch.h>
Packit 032894
#include <gelf.h>
Packit 032894
#include <libelf.h>
Packit 032894
#include <libintl.h>
Packit 032894
#include <locale.h>
Packit 032894
#include <stdbool.h>
Packit 032894
#include <stdio.h>
Packit 032894
#include <stdio_ext.h>
Packit 032894
#include <stdlib.h>
Packit 032894
#include <string.h>
Packit 032894
#include <unistd.h>
Packit 032894
#include <sys/stat.h>
Packit 032894
#include <sys/time.h>
Packit 032894
Packit 032894
#include <elf-knowledge.h>
Packit 032894
#include <libebl.h>
Packit 032894
#include "libdwelf.h"
Packit 032894
#include <libeu.h>
Packit 032894
#include <system.h>
Packit 032894
#include <printversion.h>
Packit 032894
Packit 032894
typedef uint8_t GElf_Byte;
Packit 032894
Packit 032894
/* Name and version of program.  */
Packit 032894
ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
Packit 032894
Packit 032894
/* Bug report address.  */
Packit 032894
ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
Packit 032894
Packit 032894
Packit 032894
/* Values for the parameters which have no short form.  */
Packit 032894
#define OPT_REMOVE_COMMENT	0x100
Packit 032894
#define OPT_PERMISSIVE		0x101
Packit 032894
#define OPT_STRIP_SECTIONS	0x102
Packit 032894
#define OPT_RELOC_DEBUG 	0x103
Packit 032894
#define OPT_KEEP_SECTION 	0x104
Packit 032894
#define OPT_RELOC_DEBUG_ONLY    0x105
Packit 032894
Packit 032894
Packit 032894
/* Definitions of arguments for argp functions.  */
Packit 032894
static const struct argp_option options[] =
Packit 032894
{
Packit 032894
  { NULL, 0, NULL, 0, N_("Output selection:"), 0 },
Packit 032894
  { "output", 'o', "FILE", 0, N_("Place stripped output into FILE"), 0 },
Packit 032894
  { NULL, 'f', "FILE", 0, N_("Extract the removed sections into FILE"), 0 },
Packit 032894
  { NULL, 'F', "FILE", 0, N_("Embed name FILE instead of -f argument"), 0 },
Packit 032894
Packit 032894
  { NULL, 0, NULL, 0, N_("Output options:"), 0 },
Packit 032894
  { "strip-all", 's', NULL, OPTION_HIDDEN, NULL, 0 },
Packit 032894
  { "strip-debug", 'g', NULL, 0, N_("Remove all debugging symbols"), 0 },
Packit 032894
  { NULL, 'd', NULL, OPTION_ALIAS, NULL, 0 },
Packit 032894
  { NULL, 'S', NULL, OPTION_ALIAS, NULL, 0 },
Packit 032894
  { "strip-sections", OPT_STRIP_SECTIONS, NULL, 0,
Packit 032894
    N_("Remove section headers (not recommended)"), 0 },
Packit 032894
  { "preserve-dates", 'p', NULL, 0,
Packit 032894
    N_("Copy modified/access timestamps to the output"), 0 },
Packit 032894
  { "reloc-debug-sections", OPT_RELOC_DEBUG, NULL, 0,
Packit 032894
    N_("Resolve all trivial relocations between debug sections if the removed sections are placed in a debug file (only relevant for ET_REL files, operation is not reversable, needs -f)"), 0 },
Packit 032894
  { "reloc-debug-sections-only", OPT_RELOC_DEBUG_ONLY, NULL, 0,
Packit 032894
    N_("Similar to --reloc-debug-sections, but resolve all trivial relocations between debug sections in place.  No other stripping is performed (operation is not reversable, incompatible with -f, -g, --remove-comment and --remove-section)"), 0 },
Packit 032894
  { "remove-comment", OPT_REMOVE_COMMENT, NULL, 0,
Packit 032894
    N_("Remove .comment section"), 0 },
Packit 032894
  { "remove-section", 'R', "SECTION", 0, N_("Remove the named section.  SECTION is an extended wildcard pattern.  May be given more than once.  Only non-allocated sections can be removed."), 0 },
Packit 032894
  { "keep-section", OPT_KEEP_SECTION, "SECTION", 0, N_("Keep the named section.  SECTION is an extended wildcard pattern.  May be given more than once."), 0 },
Packit 032894
  { "permissive", OPT_PERMISSIVE, NULL, 0,
Packit 032894
    N_("Relax a few rules to handle slightly broken ELF files"), 0 },
Packit 032894
  { NULL, 0, NULL, 0, NULL, 0 }
Packit 032894
};
Packit 032894
Packit 032894
/* Short description of program.  */
Packit 032894
static const char doc[] = N_("Discard symbols from object files.");
Packit 032894
Packit 032894
/* Strings for arguments in help texts.  */
Packit 032894
static const char args_doc[] = N_("[FILE...]");
Packit 032894
Packit 032894
/* Prototype for option handler.  */
Packit 032894
static error_t parse_opt (int key, char *arg, struct argp_state *state);
Packit 032894
Packit 032894
/* Data structure to communicate with argp functions.  */
Packit 032894
static struct argp argp =
Packit 032894
{
Packit 032894
  options, parse_opt, args_doc, doc, NULL, NULL, NULL
Packit 032894
};
Packit 032894
Packit 032894
Packit 032894
/* Print symbols in file named FNAME.  */
Packit 032894
static int process_file (const char *fname);
Packit 032894
Packit 032894
/* Handle one ELF file.  */
Packit 032894
static int handle_elf (int fd, Elf *elf, const char *prefix,
Packit 032894
		       const char *fname, mode_t mode, struct timespec tvp[2]);
Packit 032894
Packit 032894
/* Handle all files contained in the archive.  */
Packit 032894
static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
Packit 032894
		      struct timespec tvp[2]) __attribute__ ((unused));
Packit 032894
Packit 032894
static int debug_fd = -1;
Packit 032894
static char *tmp_debug_fname = NULL;
Packit 032894
Packit 032894
/* Close debug file descriptor, if opened. And remove temporary debug file.  */
Packit 032894
static void cleanup_debug (void);
Packit 032894
Packit 032894
#define INTERNAL_ERROR(fname) \
Packit 032894
  do { \
Packit 032894
    cleanup_debug (); \
Packit 032894
    error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s): %s"),      \
Packit 032894
	   fname, __LINE__, PACKAGE_VERSION, elf_errmsg (-1)); \
Packit 032894
  } while (0)
Packit 032894
Packit 032894
Packit 032894
/* Name of the output file.  */
Packit 032894
static const char *output_fname;
Packit 032894
Packit 032894
/* Name of the debug output file.  */
Packit 032894
static const char *debug_fname;
Packit 032894
Packit 032894
/* Name to pretend the debug output file has.  */
Packit 032894
static const char *debug_fname_embed;
Packit 032894
Packit 032894
/* If true output files shall have same date as the input file.  */
Packit 032894
static bool preserve_dates;
Packit 032894
Packit 032894
/* If true .comment sections will be removed.  */
Packit 032894
static bool remove_comment;
Packit 032894
Packit 032894
/* If true remove all debug sections.  */
Packit 032894
static bool remove_debug;
Packit 032894
Packit 032894
/* If true remove all section headers.  */
Packit 032894
static bool remove_shdrs;
Packit 032894
Packit 032894
/* If true relax some ELF rules for input files.  */
Packit 032894
static bool permissive;
Packit 032894
Packit 032894
/* If true perform relocations between debug sections.  */
Packit 032894
static bool reloc_debug;
Packit 032894
Packit 032894
/* If true perform relocations between debug sections only.  */
Packit 032894
static bool reloc_debug_only;
Packit 032894
Packit 032894
/* Sections the user explicitly wants to keep or remove.  */
Packit 032894
struct section_pattern
Packit 032894
{
Packit 032894
  char *pattern;
Packit 032894
  struct section_pattern *next;
Packit 032894
};
Packit 032894
Packit 032894
static struct section_pattern *keep_secs = NULL;
Packit 032894
static struct section_pattern *remove_secs = NULL;
Packit 032894
Packit 032894
static void
Packit 032894
add_pattern (struct section_pattern **patterns, const char *pattern)
Packit 032894
{
Packit 032894
  struct section_pattern *p = xmalloc (sizeof *p);
Packit 032894
  p->pattern = xstrdup (pattern);
Packit 032894
  p->next = *patterns;
Packit 032894
  *patterns = p;
Packit 032894
}
Packit 032894
Packit 032894
static void
Packit 032894
free_sec_patterns (struct section_pattern *patterns)
Packit 032894
{
Packit 032894
  struct section_pattern *pattern = patterns;
Packit 032894
  while (pattern != NULL)
Packit 032894
    {
Packit 032894
      struct section_pattern *p = pattern;
Packit 032894
      pattern = p->next;
Packit 032894
      free (p->pattern);
Packit 032894
      free (p);
Packit 032894
    }
Packit 032894
}
Packit 032894
Packit 032894
static void
Packit 032894
free_patterns (void)
Packit 032894
{
Packit 032894
  free_sec_patterns (keep_secs);
Packit 032894
  free_sec_patterns (remove_secs);
Packit 032894
}
Packit 032894
Packit 032894
static bool
Packit 032894
section_name_matches (struct section_pattern *patterns, const char *name)
Packit 032894
{
Packit 032894
  struct section_pattern *pattern = patterns;
Packit 032894
  while (pattern != NULL)
Packit 032894
    {
Packit 032894
      if (fnmatch (pattern->pattern, name, FNM_EXTMATCH) == 0)
Packit 032894
	return true;
Packit 032894
      pattern = pattern->next;
Packit 032894
    }
Packit 032894
  return false;
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
int
Packit 032894
main (int argc, char *argv[])
Packit 032894
{
Packit 032894
  int remaining;
Packit 032894
  int result = 0;
Packit 032894
Packit 032894
  /* We use no threads here which can interfere with handling a stream.  */
Packit 032894
  __fsetlocking (stdin, FSETLOCKING_BYCALLER);
Packit 032894
  __fsetlocking (stdout, FSETLOCKING_BYCALLER);
Packit 032894
  __fsetlocking (stderr, FSETLOCKING_BYCALLER);
Packit 032894
Packit 032894
  /* Set locale.  */
Packit 032894
  setlocale (LC_ALL, "");
Packit 032894
Packit 032894
  /* Make sure the message catalog can be found.  */
Packit 032894
  bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
Packit 032894
Packit 032894
  /* Initialize the message catalog.  */
Packit 032894
  textdomain (PACKAGE_TARNAME);
Packit 032894
Packit 032894
  /* Parse and process arguments.  */
Packit 032894
  if (argp_parse (&argp, argc, argv, 0, &remaining, NULL) != 0)
Packit 032894
    return EXIT_FAILURE;
Packit 032894
Packit 032894
  if (reloc_debug && debug_fname == NULL)
Packit 032894
    error (EXIT_FAILURE, 0,
Packit 032894
	   gettext ("--reloc-debug-sections used without -f"));
Packit 032894
Packit 032894
  if (reloc_debug_only &&
Packit 032894
      (debug_fname != NULL || remove_secs != NULL
Packit 032894
       || remove_comment == true || remove_debug == true))
Packit 032894
    error (EXIT_FAILURE, 0,
Packit 032894
	   gettext ("--reloc-debug-sections-only incompatible with -f, -g, --remove-comment and --remove-section"));
Packit 032894
Packit 032894
  /* Tell the library which version we are expecting.  */
Packit 032894
  elf_version (EV_CURRENT);
Packit 032894
Packit 032894
  if (remaining == argc)
Packit 032894
    /* The user didn't specify a name so we use a.out.  */
Packit 032894
    result = process_file ("a.out");
Packit 032894
  else
Packit 032894
    {
Packit 032894
      /* If we have seen the '-o' or '-f' option there must be exactly one
Packit 032894
	 input file.  */
Packit 032894
      if ((output_fname != NULL || debug_fname != NULL)
Packit 032894
	  && remaining + 1 < argc)
Packit 032894
	error (EXIT_FAILURE, 0, gettext ("\
Packit 032894
Only one input file allowed together with '-o' and '-f'"));
Packit 032894
Packit 032894
      /* Process all the remaining files.  */
Packit 032894
      do
Packit 032894
	result |= process_file (argv[remaining]);
Packit 032894
      while (++remaining < argc);
Packit 032894
    }
Packit 032894
Packit 032894
  free_patterns ();
Packit 032894
  return result;
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
/* Handle program arguments.  */
Packit 032894
static error_t
Packit 032894
parse_opt (int key, char *arg, struct argp_state *state)
Packit 032894
{
Packit 032894
  switch (key)
Packit 032894
    {
Packit 032894
    case 'f':
Packit 032894
      if (debug_fname != NULL)
Packit 032894
	{
Packit 032894
	  error (0, 0, gettext ("-f option specified twice"));
Packit 032894
	  return EINVAL;
Packit 032894
	}
Packit 032894
      debug_fname = arg;
Packit 032894
      break;
Packit 032894
Packit 032894
    case 'F':
Packit 032894
      if (debug_fname_embed != NULL)
Packit 032894
	{
Packit 032894
	  error (0, 0, gettext ("-F option specified twice"));
Packit 032894
	  return EINVAL;
Packit 032894
	}
Packit 032894
      debug_fname_embed = arg;
Packit 032894
      break;
Packit 032894
Packit 032894
    case 'o':
Packit 032894
      if (output_fname != NULL)
Packit 032894
	{
Packit 032894
	  error (0, 0, gettext ("-o option specified twice"));
Packit 032894
	  return EINVAL;
Packit 032894
	}
Packit 032894
      output_fname = arg;
Packit 032894
      break;
Packit 032894
Packit 032894
    case 'p':
Packit 032894
      preserve_dates = true;
Packit 032894
      break;
Packit 032894
Packit 032894
    case OPT_RELOC_DEBUG:
Packit 032894
      reloc_debug = true;
Packit 032894
      break;
Packit 032894
Packit 032894
    case OPT_RELOC_DEBUG_ONLY:
Packit 032894
      reloc_debug_only = true;
Packit 032894
      break;
Packit 032894
Packit 032894
    case OPT_REMOVE_COMMENT:
Packit 032894
      remove_comment = true;
Packit 032894
      break;
Packit 032894
Packit 032894
    case 'R':
Packit 032894
      if (fnmatch (arg, ".comment", FNM_EXTMATCH) == 0)
Packit 032894
	remove_comment = true;
Packit 032894
      add_pattern (&remove_secs, arg);
Packit 032894
      break;
Packit 032894
Packit 032894
    case OPT_KEEP_SECTION:
Packit 032894
      add_pattern (&keep_secs, arg);
Packit 032894
      break;
Packit 032894
Packit 032894
    case 'g':
Packit 032894
    case 'd':
Packit 032894
    case 'S':
Packit 032894
      remove_debug = true;
Packit 032894
      break;
Packit 032894
Packit 032894
    case OPT_STRIP_SECTIONS:
Packit 032894
      remove_shdrs = true;
Packit 032894
      break;
Packit 032894
Packit 032894
    case OPT_PERMISSIVE:
Packit 032894
      permissive = true;
Packit 032894
      break;
Packit 032894
Packit 032894
    case 's':			/* Ignored for compatibility.  */
Packit 032894
      break;
Packit 032894
Packit 032894
    case ARGP_KEY_SUCCESS:
Packit 032894
      if (remove_comment == true
Packit 032894
	  && section_name_matches (keep_secs, ".comment"))
Packit 032894
	{
Packit 032894
	  argp_error (state,
Packit 032894
		      gettext ("cannot both keep and remove .comment section"));
Packit 032894
	  return EINVAL;
Packit 032894
	}
Packit 032894
      break;
Packit 032894
Packit 032894
    default:
Packit 032894
      return ARGP_ERR_UNKNOWN;
Packit 032894
    }
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
Packit 032894
static const char *
Packit 032894
secndx_name (Elf *elf, size_t ndx)
Packit 032894
{
Packit 032894
  size_t shstrndx;
Packit 032894
  GElf_Shdr mem;
Packit 032894
  Elf_Scn *sec = elf_getscn (elf, ndx);
Packit 032894
  GElf_Shdr *shdr = gelf_getshdr (sec, &mem;;
Packit 032894
  if (shdr == NULL || elf_getshdrstrndx (elf, &shstrndx) < 0)
Packit 032894
    return "???";
Packit 032894
  return elf_strptr (elf, shstrndx, shdr->sh_name) ?: "???";
Packit 032894
}
Packit 032894
Packit 032894
/* Get the extended section index table data for a symbol table section.  */
Packit 032894
static Elf_Data *
Packit 032894
get_xndxdata (Elf *elf, Elf_Scn *symscn)
Packit 032894
{
Packit 032894
  Elf_Data *xndxdata = NULL;
Packit 032894
  GElf_Shdr shdr_mem;
Packit 032894
  GElf_Shdr *shdr = gelf_getshdr (symscn, &shdr_mem);
Packit 032894
  if (shdr != NULL && shdr->sh_type == SHT_SYMTAB)
Packit 032894
    {
Packit 032894
      size_t scnndx = elf_ndxscn (symscn);
Packit 032894
      Elf_Scn *xndxscn = NULL;
Packit 032894
      while ((xndxscn = elf_nextscn (elf, xndxscn)) != NULL)
Packit 032894
	{
Packit 032894
	  GElf_Shdr xndxshdr_mem;
Packit 032894
	  GElf_Shdr *xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
Packit 032894
Packit 032894
	  if (xndxshdr != NULL
Packit 032894
	      && xndxshdr->sh_type == SHT_SYMTAB_SHNDX
Packit 032894
	      && xndxshdr->sh_link == scnndx)
Packit 032894
	    {
Packit 032894
	      xndxdata = elf_getdata (xndxscn, NULL);
Packit 032894
	      break;
Packit 032894
	    }
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  return xndxdata;
Packit 032894
}
Packit 032894
Packit 032894
/* Updates the shdrstrndx for the given Elf by updating the Ehdr and
Packit 032894
   possibly the section zero extension field.  Returns zero on success.  */
Packit 032894
static int
Packit 032894
update_shdrstrndx (Elf *elf, size_t shdrstrndx)
Packit 032894
{
Packit 032894
  GElf_Ehdr ehdr;
Packit 032894
  if (gelf_getehdr (elf, &ehdr) == 0)
Packit 032894
    return 1;
Packit 032894
Packit 032894
  if (shdrstrndx < SHN_LORESERVE)
Packit 032894
    ehdr.e_shstrndx = shdrstrndx;
Packit 032894
  else
Packit 032894
    {
Packit 032894
      ehdr.e_shstrndx = SHN_XINDEX;
Packit 032894
      Elf_Scn *scn0 = elf_getscn (elf, 0);
Packit 032894
      GElf_Shdr shdr0_mem;
Packit 032894
      GElf_Shdr *shdr0 = gelf_getshdr (scn0, &shdr0_mem);
Packit 032894
      if (shdr0 == NULL)
Packit 032894
	return 1;
Packit 032894
Packit 032894
      shdr0->sh_link = shdrstrndx;
Packit 032894
      if (gelf_update_shdr (scn0, shdr0) == 0)
Packit 032894
	return 1;
Packit 032894
    }
Packit 032894
Packit 032894
  if (unlikely (gelf_update_ehdr (elf, &ehdr) == 0))
Packit 032894
    return 1;
Packit 032894
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
Packit 032894
/* Remove any relocations between debug sections in ET_REL
Packit 032894
   for the debug file when requested.  These relocations are always
Packit 032894
   zero based between the unallocated sections.  */
Packit 032894
static void
Packit 032894
remove_debug_relocations (Ebl *ebl, Elf *elf, GElf_Ehdr *ehdr,
Packit 032894
			  const char *fname, size_t shstrndx)
Packit 032894
{
Packit 032894
  Elf_Scn *scn = NULL;
Packit 032894
  while ((scn = elf_nextscn (elf, scn)) != NULL)
Packit 032894
    {
Packit 032894
      /* We need the actual section and header from the elf
Packit 032894
	 not just the cached original in shdr_info because we
Packit 032894
	 might want to change the size.  */
Packit 032894
      GElf_Shdr shdr_mem;
Packit 032894
      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Packit 032894
      if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
Packit 032894
	{
Packit 032894
	  /* Make sure that this relocation section points to a
Packit 032894
	     section to relocate with contents, that isn't
Packit 032894
	     allocated and that is a debug section.  */
Packit 032894
	  Elf_Scn *tscn = elf_getscn (elf, shdr->sh_info);
Packit 032894
	  GElf_Shdr tshdr_mem;
Packit 032894
	  GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
Packit 032894
	  if (tshdr->sh_type == SHT_NOBITS
Packit 032894
	      || tshdr->sh_size == 0
Packit 032894
	      || (tshdr->sh_flags & SHF_ALLOC) != 0)
Packit 032894
	    continue;
Packit 032894
Packit 032894
	  const char *tname =  elf_strptr (elf, shstrndx,
Packit 032894
					   tshdr->sh_name);
Packit 032894
	  if (! tname || ! ebl_debugscn_p (ebl, tname))
Packit 032894
	    continue;
Packit 032894
Packit 032894
	  /* OK, lets relocate all trivial cross debug section
Packit 032894
	     relocations. */
Packit 032894
	  Elf_Data *reldata = elf_getdata (scn, NULL);
Packit 032894
	  if (reldata == NULL || reldata->d_buf == NULL)
Packit 032894
	    INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
	  /* Make sure we adjust the uncompressed debug data
Packit 032894
	     (and recompress if necessary at the end).  */
Packit 032894
	  GElf_Chdr tchdr;
Packit 032894
	  int tcompress_type = 0;
Packit 032894
	  bool is_gnu_compressed = false;
Packit 032894
	  if (strncmp (tname, ".zdebug", strlen ("zdebug")) == 0)
Packit 032894
	    {
Packit 032894
	      is_gnu_compressed = true;
Packit 032894
	      if (elf_compress_gnu (tscn, 0, 0) != 1)
Packit 032894
		INTERNAL_ERROR (fname);
Packit 032894
	    }
Packit 032894
	  else
Packit 032894
	    {
Packit 032894
	      if (gelf_getchdr (tscn, &tchdr) != NULL)
Packit 032894
		{
Packit 032894
		  tcompress_type = tchdr.ch_type;
Packit 032894
		  if (elf_compress (tscn, 0, 0) != 1)
Packit 032894
		    INTERNAL_ERROR (fname);
Packit 032894
		}
Packit 032894
	    }
Packit 032894
Packit 032894
	  Elf_Data *tdata = elf_getdata (tscn, NULL);
Packit 032894
	  if (tdata == NULL || tdata->d_buf == NULL
Packit 032894
	      || tdata->d_type != ELF_T_BYTE)
Packit 032894
	    INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
	  /* Pick up the symbol table and shndx table to
Packit 032894
	     resolve relocation symbol indexes.  */
Packit 032894
	  Elf64_Word symt = shdr->sh_link;
Packit 032894
	  Elf_Data *symdata, *xndxdata;
Packit 032894
	  Elf_Scn * symscn = elf_getscn (elf, symt);
Packit 032894
	  symdata = elf_getdata (symscn, NULL);
Packit 032894
	  xndxdata = get_xndxdata (elf, symscn);
Packit 032894
	  if (symdata == NULL)
Packit 032894
	    INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
	  /* Apply one relocation.  Returns true when trivial
Packit 032894
	     relocation actually done.  */
Packit 032894
	  bool relocate (GElf_Addr offset, const GElf_Sxword addend,
Packit 032894
			 bool is_rela, int rtype, int symndx)
Packit 032894
	  {
Packit 032894
	    /* R_*_NONE relocs can always just be removed.  */
Packit 032894
	    if (rtype == 0)
Packit 032894
	      return true;
Packit 032894
Packit 032894
	    /* We only do simple absolute relocations.  */
Packit 032894
	    int addsub = 0;
Packit 032894
	    Elf_Type type = ebl_reloc_simple_type (ebl, rtype, &addsub);
Packit 032894
	    if (type == ELF_T_NUM)
Packit 032894
	      return false;
Packit 032894
Packit 032894
	    /* These are the types we can relocate.  */
Packit 032894
#define TYPES   DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half);		\
Packit 032894
		DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword);		\
Packit 032894
		DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
Packit 032894
Packit 032894
	    /* And only for relocations against other debug sections.  */
Packit 032894
	    GElf_Sym sym_mem;
Packit 032894
	    Elf32_Word xndx;
Packit 032894
	    GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
Packit 032894
					      symndx, &sym_mem,
Packit 032894
					      &xndx);
Packit 032894
	    Elf32_Word sec = (sym->st_shndx == SHN_XINDEX
Packit 032894
			      ? xndx : sym->st_shndx);
Packit 032894
Packit 032894
	    if (ebl_debugscn_p (ebl, secndx_name (elf, sec)))
Packit 032894
	      {
Packit 032894
		size_t size;
Packit 032894
Packit 032894
#define DO_TYPE(NAME, Name) GElf_##Name Name;
Packit 032894
		union { TYPES; } tmpbuf;
Packit 032894
#undef DO_TYPE
Packit 032894
Packit 032894
		switch (type)
Packit 032894
		  {
Packit 032894
#define DO_TYPE(NAME, Name)				\
Packit 032894
		    case ELF_T_##NAME:			\
Packit 032894
		      size = sizeof (GElf_##Name);	\
Packit 032894
		      tmpbuf.Name = 0;			\
Packit 032894
		      break;
Packit 032894
		    TYPES;
Packit 032894
#undef DO_TYPE
Packit 032894
		  default:
Packit 032894
		    return false;
Packit 032894
		  }
Packit 032894
Packit 032894
		if (offset > tdata->d_size
Packit 032894
		    || tdata->d_size - offset < size)
Packit 032894
		  {
Packit 032894
		    cleanup_debug ();
Packit 032894
		    error (EXIT_FAILURE, 0, gettext ("bad relocation"));
Packit 032894
		  }
Packit 032894
Packit 032894
		/* When the symbol value is zero then for SHT_REL
Packit 032894
		   sections this is all that needs to be checked.
Packit 032894
		   The addend is contained in the original data at
Packit 032894
		   the offset already.  So if the (section) symbol
Packit 032894
		   address is zero and the given addend is zero
Packit 032894
		   just remove the relocation, it isn't needed
Packit 032894
		   anymore.  */
Packit 032894
		if (addend == 0 && sym->st_value == 0)
Packit 032894
		  return true;
Packit 032894
Packit 032894
		Elf_Data tmpdata =
Packit 032894
		  {
Packit 032894
		    .d_type = type,
Packit 032894
		    .d_buf = &tmpbuf,
Packit 032894
		    .d_size = size,
Packit 032894
		    .d_version = EV_CURRENT,
Packit 032894
		  };
Packit 032894
		Elf_Data rdata =
Packit 032894
		  {
Packit 032894
		    .d_type = type,
Packit 032894
		    .d_buf = tdata->d_buf + offset,
Packit 032894
		    .d_size = size,
Packit 032894
		    .d_version = EV_CURRENT,
Packit 032894
		  };
Packit 032894
Packit 032894
		GElf_Addr value = sym->st_value;
Packit 032894
		if (is_rela)
Packit 032894
		  {
Packit 032894
		    /* For SHT_RELA sections we just take the
Packit 032894
		       given addend and add it to the value.  */
Packit 032894
		    value += addend;
Packit 032894
		    /* For ADD/SUB relocations we need to fetch the
Packit 032894
		       current section contents.  */
Packit 032894
		    if (addsub != 0)
Packit 032894
		      {
Packit 032894
			Elf_Data *d = gelf_xlatetom (elf, &tmpdata,
Packit 032894
						     &rdata,
Packit 032894
						     ehdr->e_ident[EI_DATA]);
Packit 032894
			if (d == NULL)
Packit 032894
			  INTERNAL_ERROR (fname);
Packit 032894
			assert (d == &tmpdata);
Packit 032894
		      }
Packit 032894
		  }
Packit 032894
		else
Packit 032894
		  {
Packit 032894
		    /* For SHT_REL sections we have to peek at
Packit 032894
		       what is already in the section at the given
Packit 032894
		       offset to get the addend.  */
Packit 032894
		    Elf_Data *d = gelf_xlatetom (elf, &tmpdata,
Packit 032894
						 &rdata,
Packit 032894
						 ehdr->e_ident[EI_DATA]);
Packit 032894
		    if (d == NULL)
Packit 032894
		      INTERNAL_ERROR (fname);
Packit 032894
		    assert (d == &tmpdata);
Packit 032894
		  }
Packit 032894
Packit 032894
		switch (type)
Packit 032894
		  {
Packit 032894
#define DO_TYPE(NAME, Name)					 \
Packit 032894
		    case ELF_T_##NAME:				 \
Packit 032894
		      if (addsub < 0)				 \
Packit 032894
			tmpbuf.Name -= (GElf_##Name) value;	 \
Packit 032894
		      else					 \
Packit 032894
			tmpbuf.Name += (GElf_##Name) value;	 \
Packit 032894
		      break;
Packit 032894
		    TYPES;
Packit 032894
#undef DO_TYPE
Packit 032894
		  default:
Packit 032894
		    abort ();
Packit 032894
		  }
Packit 032894
Packit 032894
		/* Now finally put in the new value.  */
Packit 032894
		Elf_Data *s = gelf_xlatetof (elf, &rdata,
Packit 032894
					     &tmpdata,
Packit 032894
					     ehdr->e_ident[EI_DATA]);
Packit 032894
		if (s == NULL)
Packit 032894
		  INTERNAL_ERROR (fname);
Packit 032894
		assert (s == &rdata);
Packit 032894
Packit 032894
		return true;
Packit 032894
	      }
Packit 032894
	    return false;
Packit 032894
	  }
Packit 032894
Packit 032894
	  if (shdr->sh_entsize == 0)
Packit 032894
	    INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
	  size_t nrels = shdr->sh_size / shdr->sh_entsize;
Packit 032894
	  size_t next = 0;
Packit 032894
	  if (shdr->sh_type == SHT_REL)
Packit 032894
	    for (size_t relidx = 0; relidx < nrels; ++relidx)
Packit 032894
	      {
Packit 032894
		GElf_Rel rel_mem;
Packit 032894
		GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
Packit 032894
		if (! relocate (r->r_offset, 0, false,
Packit 032894
				GELF_R_TYPE (r->r_info),
Packit 032894
				GELF_R_SYM (r->r_info)))
Packit 032894
		  {
Packit 032894
		    if (relidx != next)
Packit 032894
		      gelf_update_rel (reldata, next, r);
Packit 032894
		    ++next;
Packit 032894
		  }
Packit 032894
	      }
Packit 032894
	  else
Packit 032894
	    for (size_t relidx = 0; relidx < nrels; ++relidx)
Packit 032894
	      {
Packit 032894
		GElf_Rela rela_mem;
Packit 032894
		GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
Packit 032894
		if (! relocate (r->r_offset, r->r_addend, true,
Packit 032894
				GELF_R_TYPE (r->r_info),
Packit 032894
				GELF_R_SYM (r->r_info)))
Packit 032894
		  {
Packit 032894
		    if (relidx != next)
Packit 032894
		      gelf_update_rela (reldata, next, r);
Packit 032894
		    ++next;
Packit 032894
		  }
Packit 032894
	      }
Packit 032894
Packit 032894
	  nrels = next;
Packit 032894
	  shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize;
Packit 032894
	  gelf_update_shdr (scn, shdr);
Packit 032894
Packit 032894
	  if (is_gnu_compressed)
Packit 032894
	    {
Packit 032894
	      if (elf_compress_gnu (tscn, 1, ELF_CHF_FORCE) != 1)
Packit 032894
		INTERNAL_ERROR (fname);
Packit 032894
	    }
Packit 032894
	  else if (tcompress_type != 0)
Packit 032894
	    {
Packit 032894
	      if (elf_compress (tscn, tcompress_type, ELF_CHF_FORCE) != 1)
Packit 032894
		INTERNAL_ERROR (fname);
Packit 032894
	    }
Packit 032894
	}
Packit 032894
    }
Packit 032894
}
Packit 032894
Packit 032894
static int
Packit 032894
process_file (const char *fname)
Packit 032894
{
Packit 032894
  /* If we have to preserve the modify and access timestamps get them
Packit 032894
     now.  We cannot use fstat() after opening the file since the open
Packit 032894
     would change the access time.  */
Packit 032894
  struct stat pre_st;
Packit 032894
  struct timespec tv[2];
Packit 032894
 again:
Packit 032894
  if (preserve_dates)
Packit 032894
    {
Packit 032894
      if (stat (fname, &pre_st) != 0)
Packit 032894
	{
Packit 032894
	  error (0, errno, gettext ("cannot stat input file '%s'"), fname);
Packit 032894
	  return 1;
Packit 032894
	}
Packit 032894
Packit 032894
      /* If we have to preserve the timestamp, we need it in the
Packit 032894
	 format utimes() understands.  */
Packit 032894
      tv[0] = pre_st.st_atim;
Packit 032894
      tv[1] = pre_st.st_mtim;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Open the file.  */
Packit 032894
  int fd = open (fname, output_fname == NULL ? O_RDWR : O_RDONLY);
Packit 032894
  if (fd == -1)
Packit 032894
    {
Packit 032894
      error (0, errno, gettext ("while opening '%s'"), fname);
Packit 032894
      return 1;
Packit 032894
    }
Packit 032894
Packit 032894
  /* We always use fstat() even if we called stat() before.  This is
Packit 032894
     done to make sure the information returned by stat() is for the
Packit 032894
     same file.  */
Packit 032894
  struct stat st;
Packit 032894
  if (fstat (fd, &st) != 0)
Packit 032894
    {
Packit 032894
      error (0, errno, gettext ("cannot stat input file '%s'"), fname);
Packit 032894
      return 1;
Packit 032894
    }
Packit 032894
  /* Paranoid mode on.  */
Packit 032894
  if (preserve_dates
Packit 032894
      && (st.st_ino != pre_st.st_ino || st.st_dev != pre_st.st_dev))
Packit 032894
    {
Packit 032894
      /* We detected a race.  Try again.  */
Packit 032894
      close (fd);
Packit 032894
      goto again;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Now get the ELF descriptor.  */
Packit 032894
  Elf *elf = elf_begin (fd, output_fname == NULL ? ELF_C_RDWR : ELF_C_READ,
Packit 032894
			NULL);
Packit 032894
  int result;
Packit 032894
  switch (elf_kind (elf))
Packit 032894
    {
Packit 032894
    case ELF_K_ELF:
Packit 032894
      result = handle_elf (fd, elf, NULL, fname, st.st_mode & ACCESSPERMS,
Packit 032894
			   preserve_dates ? tv : NULL);
Packit 032894
      break;
Packit 032894
Packit 032894
    case ELF_K_AR:
Packit 032894
      /* It is not possible to strip the content of an archive direct
Packit 032894
	 the output to a specific file.  */
Packit 032894
      if (unlikely (output_fname != NULL || debug_fname != NULL))
Packit 032894
	{
Packit 032894
	  error (0, 0, gettext ("%s: cannot use -o or -f when stripping archive"),
Packit 032894
		 fname);
Packit 032894
	  result = 1;
Packit 032894
	}
Packit 032894
      else
Packit 032894
	{
Packit 032894
	  /* We would like to support ar archives, but currently it just
Packit 032894
	     doesn't work at all since we call elf_clone on the members
Packit 032894
	     which doesn't really support ar members.
Packit 032894
	     result = handle_ar (fd, elf, NULL, fname,
Packit 032894
				 preserve_dates ? tv : NULL);
Packit 032894
	   */
Packit 032894
	  error (0, 0, gettext ("%s: no support for stripping archive"),
Packit 032894
		 fname);
Packit 032894
	  result = 1;
Packit 032894
	}
Packit 032894
      break;
Packit 032894
Packit 032894
    default:
Packit 032894
      error (0, 0, gettext ("%s: File format not recognized"), fname);
Packit 032894
      result = 1;
Packit 032894
      break;
Packit 032894
    }
Packit 032894
Packit 032894
  if (unlikely (elf_end (elf) != 0))
Packit 032894
    INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
  close (fd);
Packit 032894
Packit 032894
  return result;
Packit 032894
}
Packit 032894
Packit 032894
/* Processing for --reloc-debug-sections-only.  */
Packit 032894
static int
Packit 032894
handle_debug_relocs (Elf *elf, Ebl *ebl, Elf *new_elf,
Packit 032894
		     GElf_Ehdr *ehdr, const char *fname, size_t shstrndx,
Packit 032894
		     GElf_Off *last_offset, GElf_Xword *last_size)
Packit 032894
{
Packit 032894
Packit 032894
  /* Copy over the ELF header.  */
Packit 032894
  if (gelf_update_ehdr (new_elf, ehdr) == 0)
Packit 032894
    {
Packit 032894
      error (0, 0, "couldn't update new ehdr: %s", elf_errmsg (-1));
Packit 032894
      return 1;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Copy over sections and record end of allocated sections.  */
Packit 032894
  GElf_Off lastoffset = 0;
Packit 032894
  Elf_Scn *scn = NULL;
Packit 032894
  while ((scn = elf_nextscn (elf, scn)) != NULL)
Packit 032894
    {
Packit 032894
      /* Get the header.  */
Packit 032894
      GElf_Shdr shdr;
Packit 032894
      if (gelf_getshdr (scn, &shdr) == NULL)
Packit 032894
	{
Packit 032894
	  error (0, 0, "couldn't get shdr: %s", elf_errmsg (-1));
Packit 032894
	  return 1;
Packit 032894
	}
Packit 032894
Packit 032894
      /* Create new section.  */
Packit 032894
      Elf_Scn *new_scn = elf_newscn (new_elf);
Packit 032894
      if (new_scn == NULL)
Packit 032894
	{
Packit 032894
	  error (0, 0, "couldn't create new section: %s", elf_errmsg (-1));
Packit 032894
	  return 1;
Packit 032894
	}
Packit 032894
Packit 032894
      if (gelf_update_shdr (new_scn, &shdr) == 0)
Packit 032894
	{
Packit 032894
	  error (0, 0, "couldn't update shdr: %s", elf_errmsg (-1));
Packit 032894
	  return 1;
Packit 032894
	}
Packit 032894
Packit 032894
      /* Copy over section data.  */
Packit 032894
      Elf_Data *data = NULL;
Packit 032894
      while ((data = elf_getdata (scn, data)) != NULL)
Packit 032894
	{
Packit 032894
	  Elf_Data *new_data = elf_newdata (new_scn);
Packit 032894
	  if (new_data == NULL)
Packit 032894
	    {
Packit 032894
	      error (0, 0, "couldn't create new section data: %s",
Packit 032894
		     elf_errmsg (-1));
Packit 032894
	      return 1;
Packit 032894
	    }
Packit 032894
	  *new_data = *data;
Packit 032894
	}
Packit 032894
Packit 032894
      /* Record last offset of allocated section.  */
Packit 032894
      if ((shdr.sh_flags & SHF_ALLOC) != 0)
Packit 032894
	{
Packit 032894
	  GElf_Off filesz = (shdr.sh_type != SHT_NOBITS
Packit 032894
			     ? shdr.sh_size : 0);
Packit 032894
	  if (lastoffset < shdr.sh_offset + filesz)
Packit 032894
	    lastoffset = shdr.sh_offset + filesz;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  /* Make sure section header name table is setup correctly, we'll
Packit 032894
     need it to determine whether to relocate sections.  */
Packit 032894
  if (update_shdrstrndx (new_elf, shstrndx) != 0)
Packit 032894
    {
Packit 032894
      error (0, 0, "error updating shdrstrndx: %s", elf_errmsg (-1));
Packit 032894
      return 1;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Adjust the relocation sections.  */
Packit 032894
  remove_debug_relocations (ebl, new_elf, ehdr, fname, shstrndx);
Packit 032894
Packit 032894
  /* Adjust the offsets of the non-allocated sections, so they come after
Packit 032894
     the allocated sections.  */
Packit 032894
  scn = NULL;
Packit 032894
  while ((scn = elf_nextscn (new_elf, scn)) != NULL)
Packit 032894
    {
Packit 032894
      /* Get the header.  */
Packit 032894
      GElf_Shdr shdr;
Packit 032894
      if (gelf_getshdr (scn, &shdr) == NULL)
Packit 032894
	{
Packit 032894
	  error (0, 0, "couldn't get shdr: %s", elf_errmsg (-1));
Packit 032894
	  return 1;
Packit 032894
	}
Packit 032894
Packit 032894
      /* Adjust non-allocated section offsets to be after any allocated.  */
Packit 032894
      if ((shdr.sh_flags & SHF_ALLOC) == 0)
Packit 032894
	{
Packit 032894
	  shdr.sh_offset = ((lastoffset + shdr.sh_addralign - 1)
Packit 032894
			    & ~((GElf_Off) (shdr.sh_addralign - 1)));
Packit 032894
	  if (gelf_update_shdr (scn, &shdr) == 0)
Packit 032894
	    {
Packit 032894
	      error (0, 0, "couldn't update shdr: %s", elf_errmsg (-1));
Packit 032894
	      return 1;
Packit 032894
	    }
Packit 032894
Packit 032894
	  GElf_Off filesz = (shdr.sh_type != SHT_NOBITS
Packit 032894
			     ? shdr.sh_size : 0);
Packit 032894
	  lastoffset = shdr.sh_offset + filesz;
Packit 032894
	  *last_offset = shdr.sh_offset;
Packit 032894
	  *last_size = filesz;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
Packit 032894
/* Maximum size of array allocated on stack.  */
Packit 032894
#define MAX_STACK_ALLOC	(400 * 1024)
Packit 032894
Packit 032894
static int
Packit 032894
handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
Packit 032894
	    mode_t mode, struct timespec tvp[2])
Packit 032894
{
Packit 032894
  size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
Packit 032894
  size_t fname_len = strlen (fname) + 1;
Packit 032894
  char *fullname = alloca (prefix_len + 1 + fname_len);
Packit 032894
  char *cp = fullname;
Packit 032894
  Elf *debugelf = NULL;
Packit 032894
  tmp_debug_fname = NULL;
Packit 032894
  int result = 0;
Packit 032894
  size_t shdridx = 0;
Packit 032894
  GElf_Off lastsec_offset = 0;
Packit 032894
  Elf64_Xword lastsec_size = 0;
Packit 032894
  size_t shstrndx;
Packit 032894
  struct shdr_info
Packit 032894
  {
Packit 032894
    Elf_Scn *scn;
Packit 032894
    GElf_Shdr shdr;
Packit 032894
    Elf_Data *data;
Packit 032894
    Elf_Data *debug_data;
Packit 032894
    const char *name;
Packit 032894
    Elf32_Word idx;		/* Index in new file.  */
Packit 032894
    Elf32_Word old_sh_link;	/* Original value of shdr.sh_link.  */
Packit 032894
    Elf32_Word symtab_idx;
Packit 032894
    Elf32_Word version_idx;
Packit 032894
    Elf32_Word group_idx;
Packit 032894
    Elf32_Word group_cnt;
Packit 032894
    Elf_Scn *newscn;
Packit 032894
    Dwelf_Strent *se;
Packit 032894
    Elf32_Word *newsymidx;
Packit 032894
  } *shdr_info = NULL;
Packit 032894
  Elf_Scn *scn;
Packit 032894
  size_t cnt;
Packit 032894
  size_t idx;
Packit 032894
  bool changes;
Packit 032894
  GElf_Ehdr newehdr_mem;
Packit 032894
  GElf_Ehdr *newehdr;
Packit 032894
  GElf_Ehdr debugehdr_mem;
Packit 032894
  GElf_Ehdr *debugehdr;
Packit 032894
  Dwelf_Strtab *shst = NULL;
Packit 032894
  Elf_Data debuglink_crc_data;
Packit 032894
  bool any_symtab_changes = false;
Packit 032894
  Elf_Data *shstrtab_data = NULL;
Packit 032894
  void *debuglink_buf = NULL;
Packit 032894
Packit 032894
  /* Create the full name of the file.  */
Packit 032894
  if (prefix != NULL)
Packit 032894
    {
Packit 032894
      cp = mempcpy (cp, prefix, prefix_len);
Packit 032894
      *cp++ = ':';
Packit 032894
    }
Packit 032894
  memcpy (cp, fname, fname_len);
Packit 032894
Packit 032894
  /* If we are not replacing the input file open a new file here.  */
Packit 032894
  if (output_fname != NULL)
Packit 032894
    {
Packit 032894
      fd = open (output_fname, O_RDWR | O_CREAT, mode);
Packit 032894
      if (unlikely (fd == -1))
Packit 032894
	{
Packit 032894
	  error (0, errno, gettext ("cannot open '%s'"), output_fname);
Packit 032894
	  return 1;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  debug_fd = -1;
Packit 032894
Packit 032894
  /* Get the EBL handling.  Removing all debugging symbols with the -g
Packit 032894
     option or resolving all relocations between debug sections with
Packit 032894
     the --reloc-debug-sections option are currently the only reasons
Packit 032894
     we need EBL so don't open the backend unless necessary.  */
Packit 032894
  Ebl *ebl = NULL;
Packit 032894
  if (remove_debug || reloc_debug || reloc_debug_only)
Packit 032894
    {
Packit 032894
      ebl = ebl_openbackend (elf);
Packit 032894
      if (ebl == NULL)
Packit 032894
	{
Packit 032894
	  error (0, errno, gettext ("cannot open EBL backend"));
Packit 032894
	  result = 1;
Packit 032894
	  goto fail;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  /* Open the additional file the debug information will be stored in.  */
Packit 032894
  if (debug_fname != NULL)
Packit 032894
    {
Packit 032894
      /* Create a temporary file name.  We do not want to overwrite
Packit 032894
	 the debug file if the file would not contain any
Packit 032894
	 information.  */
Packit 032894
      size_t debug_fname_len = strlen (debug_fname);
Packit 032894
      tmp_debug_fname = (char *) xmalloc (debug_fname_len + sizeof (".XXXXXX"));
Packit 032894
      strcpy (mempcpy (tmp_debug_fname, debug_fname, debug_fname_len),
Packit 032894
	      ".XXXXXX");
Packit 032894
Packit 032894
      debug_fd = mkstemp (tmp_debug_fname);
Packit 032894
      if (unlikely (debug_fd == -1))
Packit 032894
	{
Packit 032894
	  error (0, errno, gettext ("cannot open '%s'"), debug_fname);
Packit 032894
	  result = 1;
Packit 032894
	  goto fail;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  /* Get the information from the old file.  */
Packit 032894
  GElf_Ehdr ehdr_mem;
Packit 032894
  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
Packit 032894
  if (ehdr == NULL)
Packit 032894
    INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
  /* Get the section header string table index.  */
Packit 032894
  if (unlikely (elf_getshdrstrndx (elf, &shstrndx) < 0))
Packit 032894
    {
Packit 032894
      cleanup_debug ();
Packit 032894
      error (EXIT_FAILURE, 0,
Packit 032894
	     gettext ("cannot get section header string table index"));
Packit 032894
    }
Packit 032894
Packit 032894
  /* Get the number of phdrs in the old file.  */
Packit 032894
  size_t phnum;
Packit 032894
  if (elf_getphdrnum (elf, &phnum) != 0)
Packit 032894
    {
Packit 032894
      cleanup_debug ();
Packit 032894
      error (EXIT_FAILURE, 0, gettext ("cannot get number of phdrs"));
Packit 032894
    }
Packit 032894
Packit 032894
  /* We now create a new ELF descriptor for the same file.  We
Packit 032894
     construct it almost exactly in the same way with some information
Packit 032894
     dropped.  */
Packit 032894
  Elf *newelf;
Packit 032894
  if (output_fname != NULL)
Packit 032894
    newelf = elf_begin (fd, ELF_C_WRITE_MMAP, NULL);
Packit 032894
  else
Packit 032894
    newelf = elf_clone (elf, ELF_C_EMPTY);
Packit 032894
Packit 032894
  if (unlikely (gelf_newehdr (newelf, gelf_getclass (elf)) == 0))
Packit 032894
    {
Packit 032894
      error (0, 0, gettext ("cannot create new ehdr for file '%s': %s"),
Packit 032894
	     output_fname ?: fname, elf_errmsg (-1));
Packit 032894
      goto fail;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Copy over the old program header if needed.  */
Packit 032894
  if (phnum > 0)
Packit 032894
    {
Packit 032894
      if (unlikely (gelf_newphdr (newelf, phnum) == 0))
Packit 032894
	{
Packit 032894
	  error (0, 0, gettext ("cannot create new phdr for file '%s': %s"),
Packit 032894
		 output_fname ?: fname, elf_errmsg (-1));
Packit 032894
	  goto fail;
Packit 032894
	}
Packit 032894
Packit 032894
      for (cnt = 0; cnt < phnum; ++cnt)
Packit 032894
	{
Packit 032894
	  GElf_Phdr phdr_mem;
Packit 032894
	  GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem);
Packit 032894
	  if (phdr == NULL
Packit 032894
	      || unlikely (gelf_update_phdr (newelf, cnt, phdr) == 0))
Packit 032894
	    INTERNAL_ERROR (fname);
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  if (reloc_debug_only)
Packit 032894
    {
Packit 032894
      if (handle_debug_relocs (elf, ebl, newelf, ehdr, fname, shstrndx,
Packit 032894
			       &lastsec_offset, &lastsec_size) != 0)
Packit 032894
	{
Packit 032894
	  result = 1;
Packit 032894
	  goto fail_close;
Packit 032894
	}
Packit 032894
      idx = shstrndx;
Packit 032894
      goto done; /* Skip all actual stripping operations.  */
Packit 032894
    }
Packit 032894
Packit 032894
  if (debug_fname != NULL)
Packit 032894
    {
Packit 032894
      /* Also create an ELF descriptor for the debug file */
Packit 032894
      debugelf = elf_begin (debug_fd, ELF_C_WRITE, NULL);
Packit 032894
      if (unlikely (gelf_newehdr (debugelf, gelf_getclass (elf)) == 0))
Packit 032894
	{
Packit 032894
	  error (0, 0, gettext ("cannot create new ehdr for file '%s': %s"),
Packit 032894
		 debug_fname, elf_errmsg (-1));
Packit 032894
	  goto fail_close;
Packit 032894
	}
Packit 032894
Packit 032894
      /* Copy over the old program header if needed.  */
Packit 032894
      if (phnum > 0)
Packit 032894
	{
Packit 032894
	  if (unlikely (gelf_newphdr (debugelf, phnum) == 0))
Packit 032894
	    {
Packit 032894
	      error (0, 0, gettext ("cannot create new phdr for file '%s': %s"),
Packit 032894
		     debug_fname, elf_errmsg (-1));
Packit 032894
	      goto fail_close;
Packit 032894
	    }
Packit 032894
Packit 032894
	  for (cnt = 0; cnt < phnum; ++cnt)
Packit 032894
	    {
Packit 032894
	      GElf_Phdr phdr_mem;
Packit 032894
	      GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem);
Packit 032894
	      if (phdr == NULL
Packit 032894
		  || unlikely (gelf_update_phdr (debugelf, cnt, phdr) == 0))
Packit 032894
		INTERNAL_ERROR (fname);
Packit 032894
	    }
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  /* Number of sections.  */
Packit 032894
  size_t shnum;
Packit 032894
  if (unlikely (elf_getshdrnum (elf, &shnum) < 0))
Packit 032894
    {
Packit 032894
      error (0, 0, gettext ("cannot determine number of sections: %s"),
Packit 032894
	     elf_errmsg (-1));
Packit 032894
      goto fail_close;
Packit 032894
    }
Packit 032894
Packit 032894
  if (shstrndx >= shnum)
Packit 032894
    goto illformed;
Packit 032894
Packit 032894
#define elf_assert(test) do { if (!(test)) goto illformed; } while (0)
Packit 032894
Packit 032894
  /* Storage for section information.  We leave room for two more
Packit 032894
     entries since we unconditionally create a section header string
Packit 032894
     table.  Maybe some weird tool created an ELF file without one.
Packit 032894
     The other one is used for the debug link section.  */
Packit 032894
  if ((shnum + 2) * sizeof (struct shdr_info) > MAX_STACK_ALLOC)
Packit 032894
    shdr_info = (struct shdr_info *) xcalloc (shnum + 2,
Packit 032894
					      sizeof (struct shdr_info));
Packit 032894
  else
Packit 032894
    {
Packit 032894
      shdr_info = (struct shdr_info *) alloca ((shnum + 2)
Packit 032894
					       * sizeof (struct shdr_info));
Packit 032894
      memset (shdr_info, '\0', (shnum + 2) * sizeof (struct shdr_info));
Packit 032894
    }
Packit 032894
Packit 032894
  /* Track whether allocated sections all come before non-allocated ones.  */
Packit 032894
  bool seen_allocated = false;
Packit 032894
  bool seen_unallocated = false;
Packit 032894
  bool mixed_allocated_unallocated = false;
Packit 032894
Packit 032894
  /* Prepare section information data structure.  */
Packit 032894
  scn = NULL;
Packit 032894
  cnt = 1;
Packit 032894
  while ((scn = elf_nextscn (elf, scn)) != NULL)
Packit 032894
    {
Packit 032894
      /* This should always be true (i.e., there should not be any
Packit 032894
	 holes in the numbering).  */
Packit 032894
      elf_assert (elf_ndxscn (scn) == cnt);
Packit 032894
Packit 032894
      shdr_info[cnt].scn = scn;
Packit 032894
Packit 032894
      /* Get the header.  */
Packit 032894
      if (gelf_getshdr (scn, &shdr_info[cnt].shdr) == NULL)
Packit 032894
	INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
      /* Normally (in non-ET_REL files) we see all allocated sections first,
Packit 032894
	 then all non-allocated.  */
Packit 032894
      if ((shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0)
Packit 032894
	seen_unallocated = true;
Packit 032894
      else
Packit 032894
	{
Packit 032894
	  if (seen_unallocated && seen_allocated)
Packit 032894
	    mixed_allocated_unallocated = true;
Packit 032894
	  seen_allocated = true;
Packit 032894
	}
Packit 032894
Packit 032894
      /* Get the name of the section.  */
Packit 032894
      shdr_info[cnt].name = elf_strptr (elf, shstrndx,
Packit 032894
					shdr_info[cnt].shdr.sh_name);
Packit 032894
      if (shdr_info[cnt].name == NULL)
Packit 032894
	{
Packit 032894
	illformed:
Packit 032894
	  error (0, 0, gettext ("illformed file '%s'"), fname);
Packit 032894
	  goto fail_close;
Packit 032894
	}
Packit 032894
Packit 032894
      /* Sanity check the user.  */
Packit 032894
      if (section_name_matches (remove_secs, shdr_info[cnt].name))
Packit 032894
	{
Packit 032894
	  if ((shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) != 0)
Packit 032894
	    {
Packit 032894
	      error (0, 0,
Packit 032894
		     gettext ("Cannot remove allocated section '%s'"),
Packit 032894
		     shdr_info[cnt].name);
Packit 032894
	      result = 1;
Packit 032894
	      goto fail_close;
Packit 032894
	    }
Packit 032894
Packit 032894
	  if (section_name_matches (keep_secs, shdr_info[cnt].name))
Packit 032894
	    {
Packit 032894
	      error (0, 0,
Packit 032894
		     gettext ("Cannot both keep and remove section '%s'"),
Packit 032894
		     shdr_info[cnt].name);
Packit 032894
	      result = 1;
Packit 032894
	      goto fail_close;
Packit 032894
	    }
Packit 032894
	}
Packit 032894
Packit 032894
      /* Mark them as present but not yet investigated.  */
Packit 032894
      shdr_info[cnt].idx = 1;
Packit 032894
Packit 032894
      /* Remember the shdr.sh_link value.  */
Packit 032894
      shdr_info[cnt].old_sh_link = shdr_info[cnt].shdr.sh_link;
Packit 032894
      if (shdr_info[cnt].old_sh_link >= shnum)
Packit 032894
	goto illformed;
Packit 032894
Packit 032894
      /* Sections in files other than relocatable object files which
Packit 032894
	 not loaded can be freely moved by us.  In theory we can also
Packit 032894
	 freely move around allocated nobits sections.  But we don't
Packit 032894
	 to keep the layout of all allocated sections as similar as
Packit 032894
	 possible to the original file.  In relocatable object files
Packit 032894
	 everything can be moved.  */
Packit 032894
      if (phnum == 0
Packit 032894
	  || (shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0)
Packit 032894
	shdr_info[cnt].shdr.sh_offset = 0;
Packit 032894
Packit 032894
      /* If this is an extended section index table store an
Packit 032894
	 appropriate reference.  */
Packit 032894
      if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX))
Packit 032894
	{
Packit 032894
	  elf_assert (shdr_info[shdr_info[cnt].shdr.sh_link].symtab_idx == 0);
Packit 032894
	  shdr_info[shdr_info[cnt].shdr.sh_link].symtab_idx = cnt;
Packit 032894
	}
Packit 032894
      else if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_GROUP))
Packit 032894
	{
Packit 032894
	  /* Cross-reference the sections contained in the section
Packit 032894
	     group.  */
Packit 032894
	  shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL);
Packit 032894
	  if (shdr_info[cnt].data == NULL
Packit 032894
	      || shdr_info[cnt].data->d_size < sizeof (Elf32_Word))
Packit 032894
	    INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
	  /* XXX Fix for unaligned access.  */
Packit 032894
	  Elf32_Word *grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf;
Packit 032894
	  size_t inner;
Packit 032894
	  for (inner = 1;
Packit 032894
	       inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word);
Packit 032894
	       ++inner)
Packit 032894
	    {
Packit 032894
	      if (grpref[inner] < shnum)
Packit 032894
		shdr_info[grpref[inner]].group_idx = cnt;
Packit 032894
	      else
Packit 032894
		goto illformed;
Packit 032894
	    }
Packit 032894
Packit 032894
	  if (inner == 1 || (inner == 2 && (grpref[0] & GRP_COMDAT) == 0))
Packit 032894
	    /* If the section group contains only one element and this
Packit 032894
	       is n COMDAT section we can drop it right away.  */
Packit 032894
	    shdr_info[cnt].idx = 0;
Packit 032894
	  else
Packit 032894
	    shdr_info[cnt].group_cnt = inner - 1;
Packit 032894
	}
Packit 032894
      else if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_GNU_versym))
Packit 032894
	{
Packit 032894
	  elf_assert (shdr_info[shdr_info[cnt].shdr.sh_link].version_idx == 0);
Packit 032894
	  shdr_info[shdr_info[cnt].shdr.sh_link].version_idx = cnt;
Packit 032894
	}
Packit 032894
Packit 032894
      /* If this section is part of a group make sure it is not
Packit 032894
	 discarded right away.  */
Packit 032894
      if ((shdr_info[cnt].shdr.sh_flags & SHF_GROUP) != 0)
Packit 032894
	{
Packit 032894
	  elf_assert (shdr_info[cnt].group_idx != 0);
Packit 032894
Packit 032894
	  if (shdr_info[shdr_info[cnt].group_idx].idx == 0)
Packit 032894
	    {
Packit 032894
	      /* The section group section might be removed.
Packit 032894
		 Don't remove the SHF_GROUP flag.  The section is
Packit 032894
		 either also removed, in which case the flag doesn't matter.
Packit 032894
		 Or it moves with the group into the debug file, then
Packit 032894
		 it will be reconnected with the new group and should
Packit 032894
		 still have the flag set.  */
Packit 032894
	      shdr_info[cnt].group_idx = 0;
Packit 032894
	    }
Packit 032894
	}
Packit 032894
Packit 032894
      /* Increment the counter.  */
Packit 032894
      ++cnt;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Now determine which sections can go away.  The general rule is that
Packit 032894
     all sections which are not used at runtime are stripped out.  But
Packit 032894
     there are a few exceptions:
Packit 032894
Packit 032894
     - special sections named ".comment" and ".note" are kept
Packit 032894
     - OS or architecture specific sections are kept since we might not
Packit 032894
       know how to handle them
Packit 032894
     - if a section is referred to from a section which is not removed
Packit 032894
       in the sh_link or sh_info element it cannot be removed either
Packit 032894
     - the user might have explicitly said to remove or keep a section
Packit 032894
  */
Packit 032894
  for (cnt = 1; cnt < shnum; ++cnt)
Packit 032894
    /* Check whether the section can be removed.  Since we will create
Packit 032894
       a new .shstrtab assume it will be removed too.  */
Packit 032894
    if (remove_shdrs ? !(shdr_info[cnt].shdr.sh_flags & SHF_ALLOC)
Packit 032894
	: (ebl_section_strip_p (ebl, &shdr_info[cnt].shdr,
Packit 032894
				shdr_info[cnt].name, remove_comment,
Packit 032894
				remove_debug)
Packit 032894
	   || cnt == shstrndx
Packit 032894
	   || section_name_matches (remove_secs, shdr_info[cnt].name)))
Packit 032894
      {
Packit 032894
	/* The user might want to explicitly keep this one.  */
Packit 032894
	if (section_name_matches (keep_secs, shdr_info[cnt].name))
Packit 032894
	  continue;
Packit 032894
Packit 032894
	/* For now assume this section will be removed.  */
Packit 032894
	shdr_info[cnt].idx = 0;
Packit 032894
Packit 032894
	idx = shdr_info[cnt].group_idx;
Packit 032894
	while (idx != 0)
Packit 032894
	  {
Packit 032894
	    /* The section group data is already loaded.  */
Packit 032894
	    elf_assert (shdr_info[idx].data != NULL
Packit 032894
			&& shdr_info[idx].data->d_buf != NULL
Packit 032894
			&& shdr_info[idx].data->d_size >= sizeof (Elf32_Word));
Packit 032894
Packit 032894
	    /* If the references section group is a normal section
Packit 032894
	       group and has one element remaining, or if it is an
Packit 032894
	       empty COMDAT section group it is removed.  */
Packit 032894
	    bool is_comdat = (((Elf32_Word *) shdr_info[idx].data->d_buf)[0]
Packit 032894
			      & GRP_COMDAT) != 0;
Packit 032894
Packit 032894
	    --shdr_info[idx].group_cnt;
Packit 032894
	    if ((!is_comdat && shdr_info[idx].group_cnt == 1)
Packit 032894
		|| (is_comdat && shdr_info[idx].group_cnt == 0))
Packit 032894
	      {
Packit 032894
		shdr_info[idx].idx = 0;
Packit 032894
		/* Continue recursively.  */
Packit 032894
		idx = shdr_info[idx].group_idx;
Packit 032894
	      }
Packit 032894
	    else
Packit 032894
	      break;
Packit 032894
	  }
Packit 032894
      }
Packit 032894
Packit 032894
  /* Mark the SHT_NULL section as handled.  */
Packit 032894
  shdr_info[0].idx = 2;
Packit 032894
Packit 032894
Packit 032894
  /* Handle exceptions: section groups and cross-references.  We might
Packit 032894
     have to repeat this a few times since the resetting of the flag
Packit 032894
     might propagate.  */
Packit 032894
  do
Packit 032894
    {
Packit 032894
      changes = false;
Packit 032894
Packit 032894
      for (cnt = 1; cnt < shnum; ++cnt)
Packit 032894
	{
Packit 032894
	  if (shdr_info[cnt].idx == 0)
Packit 032894
	    {
Packit 032894
	      /* If a relocation section is marked as being removed make
Packit 032894
		 sure the section it is relocating is removed, too.  */
Packit 032894
	      if (shdr_info[cnt].shdr.sh_type == SHT_REL
Packit 032894
		   || shdr_info[cnt].shdr.sh_type == SHT_RELA)
Packit 032894
		{
Packit 032894
		  if (shdr_info[cnt].shdr.sh_info >= shnum)
Packit 032894
		    goto illformed;
Packit 032894
		  else if (shdr_info[shdr_info[cnt].shdr.sh_info].idx != 0)
Packit 032894
		    shdr_info[cnt].idx = 1;
Packit 032894
		}
Packit 032894
Packit 032894
	      /* If a group section is marked as being removed make
Packit 032894
		 sure all the sections it contains are being removed, too.  */
Packit 032894
	      if (shdr_info[cnt].shdr.sh_type == SHT_GROUP)
Packit 032894
		{
Packit 032894
		  Elf32_Word *grpref;
Packit 032894
		  grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf;
Packit 032894
		  for (size_t in = 1;
Packit 032894
		       in < shdr_info[cnt].data->d_size / sizeof (Elf32_Word);
Packit 032894
		       ++in)
Packit 032894
		    if (grpref[in] < shnum)
Packit 032894
		      {
Packit 032894
			if (shdr_info[grpref[in]].idx != 0)
Packit 032894
			  {
Packit 032894
			    shdr_info[cnt].idx = 1;
Packit 032894
			    break;
Packit 032894
			  }
Packit 032894
		      }
Packit 032894
		    else
Packit 032894
		      goto illformed;
Packit 032894
		}
Packit 032894
	    }
Packit 032894
Packit 032894
	  if (shdr_info[cnt].idx == 1)
Packit 032894
	    {
Packit 032894
	      /* The content of symbol tables we don't remove must not
Packit 032894
		 reference any section which we do remove.  Otherwise
Packit 032894
		 we cannot remove the section.  */
Packit 032894
	      if (debug_fname != NULL
Packit 032894
		  && shdr_info[cnt].debug_data == NULL
Packit 032894
		  && (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM
Packit 032894
		      || shdr_info[cnt].shdr.sh_type == SHT_SYMTAB))
Packit 032894
		{
Packit 032894
		  /* Make sure the data is loaded.  */
Packit 032894
		  if (shdr_info[cnt].data == NULL)
Packit 032894
		    {
Packit 032894
		      shdr_info[cnt].data
Packit 032894
			= elf_getdata (shdr_info[cnt].scn, NULL);
Packit 032894
		      if (shdr_info[cnt].data == NULL)
Packit 032894
			INTERNAL_ERROR (fname);
Packit 032894
		    }
Packit 032894
		  Elf_Data *symdata = shdr_info[cnt].data;
Packit 032894
Packit 032894
		  /* If there is an extended section index table load it
Packit 032894
		     as well.  */
Packit 032894
		  if (shdr_info[cnt].symtab_idx != 0
Packit 032894
		      && shdr_info[shdr_info[cnt].symtab_idx].data == NULL)
Packit 032894
		    {
Packit 032894
		      elf_assert (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB);
Packit 032894
Packit 032894
		      shdr_info[shdr_info[cnt].symtab_idx].data
Packit 032894
			= elf_getdata (shdr_info[shdr_info[cnt].symtab_idx].scn,
Packit 032894
				       NULL);
Packit 032894
		      if (shdr_info[shdr_info[cnt].symtab_idx].data == NULL)
Packit 032894
			INTERNAL_ERROR (fname);
Packit 032894
		    }
Packit 032894
		  Elf_Data *xndxdata
Packit 032894
		    = shdr_info[shdr_info[cnt].symtab_idx].data;
Packit 032894
Packit 032894
		  /* Go through all symbols and make sure the section they
Packit 032894
		     reference is not removed.  */
Packit 032894
		  size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
Packit 032894
Packit 032894
		  for (size_t inner = 0;
Packit 032894
		       inner < shdr_info[cnt].data->d_size / elsize;
Packit 032894
		       ++inner)
Packit 032894
		    {
Packit 032894
		      GElf_Sym sym_mem;
Packit 032894
		      Elf32_Word xndx;
Packit 032894
		      GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
Packit 032894
							inner, &sym_mem,
Packit 032894
							&xndx);
Packit 032894
		      if (sym == NULL)
Packit 032894
			INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
		      size_t scnidx = sym->st_shndx;
Packit 032894
		      if (scnidx == SHN_UNDEF || scnidx >= shnum
Packit 032894
			  || (scnidx >= SHN_LORESERVE
Packit 032894
			      && scnidx <= SHN_HIRESERVE
Packit 032894
			      && scnidx != SHN_XINDEX)
Packit 032894
			  /* Don't count in the section symbols.  */
Packit 032894
			  || GELF_ST_TYPE (sym->st_info) == STT_SECTION)
Packit 032894
			/* This is no section index, leave it alone.  */
Packit 032894
			continue;
Packit 032894
		      else if (scnidx == SHN_XINDEX)
Packit 032894
			scnidx = xndx;
Packit 032894
Packit 032894
		      if (scnidx >= shnum)
Packit 032894
			goto illformed;
Packit 032894
Packit 032894
		      if (shdr_info[scnidx].idx == 0)
Packit 032894
			/* This symbol table has a real symbol in
Packit 032894
			   a discarded section.  So preserve the
Packit 032894
			   original table in the debug file.  Unless
Packit 032894
			   it is a redundant data marker to a debug
Packit 032894
			   (data only) section.  */
Packit 032894
			if (! (ebl_section_strip_p (ebl,
Packit 032894
						    &shdr_info[scnidx].shdr,
Packit 032894
						    shdr_info[scnidx].name,
Packit 032894
						    remove_comment,
Packit 032894
						    remove_debug)
Packit 032894
			       && ebl_data_marker_symbol (ebl, sym,
Packit 032894
					elf_strptr (elf,
Packit 032894
						    shdr_info[cnt].shdr.sh_link,
Packit 032894
						    sym->st_name))))
Packit 032894
			  shdr_info[cnt].debug_data = symdata;
Packit 032894
		    }
Packit 032894
		}
Packit 032894
Packit 032894
	      /* Cross referencing happens:
Packit 032894
		 - for the cases the ELF specification says.  That are
Packit 032894
		   + SHT_DYNAMIC in sh_link to string table
Packit 032894
		   + SHT_HASH in sh_link to symbol table
Packit 032894
		   + SHT_REL and SHT_RELA in sh_link to symbol table
Packit 032894
		   + SHT_SYMTAB and SHT_DYNSYM in sh_link to string table
Packit 032894
		   + SHT_GROUP in sh_link to symbol table
Packit 032894
		   + SHT_SYMTAB_SHNDX in sh_link to symbol table
Packit 032894
		   Other (OS or architecture-specific) sections might as
Packit 032894
		   well use this field so we process it unconditionally.
Packit 032894
		 - references inside section groups
Packit 032894
		 - specially marked references in sh_info if the SHF_INFO_LINK
Packit 032894
		 flag is set
Packit 032894
	      */
Packit 032894
Packit 032894
	      if (shdr_info[shdr_info[cnt].shdr.sh_link].idx == 0)
Packit 032894
		{
Packit 032894
		  shdr_info[shdr_info[cnt].shdr.sh_link].idx = 1;
Packit 032894
		  changes |= shdr_info[cnt].shdr.sh_link < cnt;
Packit 032894
		}
Packit 032894
Packit 032894
	      /* Handle references through sh_info.  */
Packit 032894
	      if (SH_INFO_LINK_P (&shdr_info[cnt].shdr))
Packit 032894
		{
Packit 032894
		  if (shdr_info[cnt].shdr.sh_info >= shnum)
Packit 032894
		    goto illformed;
Packit 032894
		  else if ( shdr_info[shdr_info[cnt].shdr.sh_info].idx == 0)
Packit 032894
		    {
Packit 032894
		      shdr_info[shdr_info[cnt].shdr.sh_info].idx = 1;
Packit 032894
		      changes |= shdr_info[cnt].shdr.sh_info < cnt;
Packit 032894
		    }
Packit 032894
		}
Packit 032894
Packit 032894
	      /* Mark the section as investigated.  */
Packit 032894
	      shdr_info[cnt].idx = 2;
Packit 032894
	    }
Packit 032894
Packit 032894
	  if (debug_fname != NULL
Packit 032894
	      && (shdr_info[cnt].idx == 0 || shdr_info[cnt].debug_data != NULL))
Packit 032894
	    {
Packit 032894
	      /* This section is being preserved in the debug file.
Packit 032894
		 Sections it refers to must be preserved there too.
Packit 032894
Packit 032894
		 In this pass we mark sections to be preserved in both
Packit 032894
		 files by setting the .debug_data pointer to the original
Packit 032894
		 file's .data pointer.  Below, we'll copy the section
Packit 032894
		 contents.  */
Packit 032894
Packit 032894
	      inline void check_preserved (size_t i)
Packit 032894
	      {
Packit 032894
		if (i != 0 && i < shnum + 2 && shdr_info[i].idx != 0
Packit 032894
		    && shdr_info[i].debug_data == NULL)
Packit 032894
		  {
Packit 032894
		    if (shdr_info[i].data == NULL)
Packit 032894
		      shdr_info[i].data = elf_getdata (shdr_info[i].scn, NULL);
Packit 032894
		    if (shdr_info[i].data == NULL)
Packit 032894
		      INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
		    shdr_info[i].debug_data = shdr_info[i].data;
Packit 032894
		    changes |= i < cnt;
Packit 032894
		  }
Packit 032894
	      }
Packit 032894
Packit 032894
	      check_preserved (shdr_info[cnt].shdr.sh_link);
Packit 032894
	      if (SH_INFO_LINK_P (&shdr_info[cnt].shdr))
Packit 032894
		check_preserved (shdr_info[cnt].shdr.sh_info);
Packit 032894
	    }
Packit 032894
	}
Packit 032894
    }
Packit 032894
  while (changes);
Packit 032894
Packit 032894
  /* Copy the removed sections to the debug output file.
Packit 032894
     The ones that are not removed in the stripped file are SHT_NOBITS.  */
Packit 032894
  if (debug_fname != NULL)
Packit 032894
    {
Packit 032894
      for (cnt = 1; cnt < shnum; ++cnt)
Packit 032894
	{
Packit 032894
	  scn = elf_newscn (debugelf);
Packit 032894
	  if (scn == NULL)
Packit 032894
	    {
Packit 032894
	      cleanup_debug ();
Packit 032894
	      error (EXIT_FAILURE, 0,
Packit 032894
		     gettext ("while generating output file: %s"),
Packit 032894
		     elf_errmsg (-1));
Packit 032894
	    }
Packit 032894
Packit 032894
	  bool discard_section = (shdr_info[cnt].idx > 0
Packit 032894
				  && shdr_info[cnt].debug_data == NULL
Packit 032894
				  && shdr_info[cnt].shdr.sh_type != SHT_NOTE
Packit 032894
				  && shdr_info[cnt].shdr.sh_type != SHT_GROUP
Packit 032894
				  && cnt != shstrndx);
Packit 032894
Packit 032894
	  /* Set the section header in the new file.  */
Packit 032894
	  GElf_Shdr debugshdr = shdr_info[cnt].shdr;
Packit 032894
	  if (discard_section)
Packit 032894
	    debugshdr.sh_type = SHT_NOBITS;
Packit 032894
Packit 032894
	  if (unlikely (gelf_update_shdr (scn, &debugshdr) == 0))
Packit 032894
	    /* There cannot be any overflows.  */
Packit 032894
	    INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
	  /* Get the data from the old file if necessary. */
Packit 032894
	  if (shdr_info[cnt].data == NULL)
Packit 032894
	    {
Packit 032894
	      shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL);
Packit 032894
	      if (shdr_info[cnt].data == NULL)
Packit 032894
		INTERNAL_ERROR (fname);
Packit 032894
	    }
Packit 032894
Packit 032894
	  /* Set the data.  This is done by copying from the old file.  */
Packit 032894
	  Elf_Data *debugdata = elf_newdata (scn);
Packit 032894
	  if (debugdata == NULL)
Packit 032894
	    INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
	  /* Copy the structure.  This data may be modified in place
Packit 032894
	     before we write out the file.  */
Packit 032894
	  *debugdata = *shdr_info[cnt].data;
Packit 032894
	  if (discard_section)
Packit 032894
	    debugdata->d_buf = NULL;
Packit 032894
	  else if (shdr_info[cnt].debug_data != NULL
Packit 032894
		   || shdr_info[cnt].shdr.sh_type == SHT_GROUP)
Packit 032894
	    {
Packit 032894
	      /* Copy the original data before it gets modified.  */
Packit 032894
	      shdr_info[cnt].debug_data = debugdata;
Packit 032894
	      if (debugdata->d_buf == NULL)
Packit 032894
		INTERNAL_ERROR (fname);
Packit 032894
	      debugdata->d_buf = memcpy (xmalloc (debugdata->d_size),
Packit 032894
					 debugdata->d_buf, debugdata->d_size);
Packit 032894
	    }
Packit 032894
	}
Packit 032894
Packit 032894
      /* Finish the ELF header.  Fill in the fields not handled by
Packit 032894
	 libelf from the old file.  */
Packit 032894
      debugehdr = gelf_getehdr (debugelf, &debugehdr_mem);
Packit 032894
      if (debugehdr == NULL)
Packit 032894
	INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
      memcpy (debugehdr->e_ident, ehdr->e_ident, EI_NIDENT);
Packit 032894
      debugehdr->e_type = ehdr->e_type;
Packit 032894
      debugehdr->e_machine = ehdr->e_machine;
Packit 032894
      debugehdr->e_version = ehdr->e_version;
Packit 032894
      debugehdr->e_entry = ehdr->e_entry;
Packit 032894
      debugehdr->e_flags = ehdr->e_flags;
Packit 032894
Packit 032894
      if (unlikely (gelf_update_ehdr (debugelf, debugehdr) == 0))
Packit 032894
	{
Packit 032894
	  error (0, 0, gettext ("%s: error while updating ELF header: %s"),
Packit 032894
		 debug_fname, elf_errmsg (-1));
Packit 032894
	  result = 1;
Packit 032894
	  goto fail_close;
Packit 032894
	}
Packit 032894
Packit 032894
      size_t shdrstrndx;
Packit 032894
      if (elf_getshdrstrndx (elf, &shdrstrndx) < 0)
Packit 032894
	{
Packit 032894
	  error (0, 0, gettext ("%s: error while getting shdrstrndx: %s"),
Packit 032894
		 fname, elf_errmsg (-1));
Packit 032894
	  result = 1;
Packit 032894
	  goto fail_close;
Packit 032894
	}
Packit 032894
Packit 032894
      if (update_shdrstrndx (debugelf, shdrstrndx) != 0)
Packit 032894
	{
Packit 032894
	  error (0, 0, gettext ("%s: error updating shdrstrndx: %s"),
Packit 032894
		 debug_fname, elf_errmsg (-1));
Packit 032894
	  result = 1;
Packit 032894
	  goto fail_close;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  /* Although we always create a new section header string table we
Packit 032894
     don't explicitly mark the existing one as unused.  It can still
Packit 032894
     be used through a symbol table section we are keeping.  If not it
Packit 032894
     will already be marked as unused.  */
Packit 032894
Packit 032894
  /* We need a string table for the section headers.  */
Packit 032894
  shst = dwelf_strtab_init (true);
Packit 032894
  if (shst == NULL)
Packit 032894
    {
Packit 032894
      cleanup_debug ();
Packit 032894
      error (EXIT_FAILURE, errno, gettext ("while preparing output for '%s'"),
Packit 032894
	     output_fname ?: fname);
Packit 032894
    }
Packit 032894
Packit 032894
  /* Assign new section numbers.  */
Packit 032894
  shdr_info[0].idx = 0;
Packit 032894
  for (cnt = idx = 1; cnt < shnum; ++cnt)
Packit 032894
    if (shdr_info[cnt].idx > 0)
Packit 032894
      {
Packit 032894
	shdr_info[cnt].idx = idx++;
Packit 032894
Packit 032894
	/* Create a new section.  */
Packit 032894
	shdr_info[cnt].newscn = elf_newscn (newelf);
Packit 032894
	if (shdr_info[cnt].newscn == NULL)
Packit 032894
	  {
Packit 032894
	    cleanup_debug ();
Packit 032894
	    error (EXIT_FAILURE, 0,
Packit 032894
		   gettext ("while generating output file: %s"),
Packit 032894
		   elf_errmsg (-1));
Packit 032894
	  }
Packit 032894
Packit 032894
	elf_assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx);
Packit 032894
Packit 032894
	/* Add this name to the section header string table.  */
Packit 032894
	shdr_info[cnt].se = dwelf_strtab_add (shst, shdr_info[cnt].name);
Packit 032894
      }
Packit 032894
Packit 032894
  /* Test whether we are doing anything at all.  Either all removable
Packit 032894
     sections are already gone.  Or the only section we would remove is
Packit 032894
     the .shstrtab section which we would add again.  */
Packit 032894
  bool removing_sections = !(cnt == idx
Packit 032894
			     || (cnt == idx + 1
Packit 032894
				 && shdr_info[shstrndx].idx == 0));
Packit 032894
  if (output_fname == NULL && !removing_sections)
Packit 032894
      goto fail_close;
Packit 032894
Packit 032894
  /* Create the reference to the file with the debug info (if any).  */
Packit 032894
  if (debug_fname != NULL && !remove_shdrs && removing_sections)
Packit 032894
    {
Packit 032894
      /* Add the section header string table section name.  */
Packit 032894
      shdr_info[cnt].se = dwelf_strtab_add_len (shst, ".gnu_debuglink", 15);
Packit 032894
      shdr_info[cnt].idx = idx++;
Packit 032894
Packit 032894
      /* Create the section header.  */
Packit 032894
      shdr_info[cnt].shdr.sh_type = SHT_PROGBITS;
Packit 032894
      shdr_info[cnt].shdr.sh_flags = 0;
Packit 032894
      shdr_info[cnt].shdr.sh_addr = 0;
Packit 032894
      shdr_info[cnt].shdr.sh_link = SHN_UNDEF;
Packit 032894
      shdr_info[cnt].shdr.sh_info = SHN_UNDEF;
Packit 032894
      shdr_info[cnt].shdr.sh_entsize = 0;
Packit 032894
      shdr_info[cnt].shdr.sh_addralign = 4;
Packit 032894
      /* We set the offset to zero here.  Before we write the ELF file the
Packit 032894
	 field must have the correct value.  This is done in the final
Packit 032894
	 loop over all section.  Then we have all the information needed.  */
Packit 032894
      shdr_info[cnt].shdr.sh_offset = 0;
Packit 032894
Packit 032894
      /* Create the section.  */
Packit 032894
      shdr_info[cnt].newscn = elf_newscn (newelf);
Packit 032894
      if (shdr_info[cnt].newscn == NULL)
Packit 032894
	{
Packit 032894
	  cleanup_debug ();
Packit 032894
	  error (EXIT_FAILURE, 0,
Packit 032894
		 gettext ("while create section header section: %s"),
Packit 032894
		 elf_errmsg (-1));
Packit 032894
	}
Packit 032894
      elf_assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx);
Packit 032894
Packit 032894
      shdr_info[cnt].data = elf_newdata (shdr_info[cnt].newscn);
Packit 032894
      if (shdr_info[cnt].data == NULL)
Packit 032894
	{
Packit 032894
	  cleanup_debug ();
Packit 032894
	  error (EXIT_FAILURE, 0, gettext ("cannot allocate section data: %s"),
Packit 032894
		 elf_errmsg (-1));
Packit 032894
	}
Packit 032894
Packit 032894
      char *debug_basename = basename (debug_fname_embed ?: debug_fname);
Packit 032894
      off_t crc_offset = strlen (debug_basename) + 1;
Packit 032894
      /* Align to 4 byte boundary */
Packit 032894
      crc_offset = ((crc_offset - 1) & ~3) + 4;
Packit 032894
Packit 032894
      shdr_info[cnt].data->d_align = 4;
Packit 032894
      shdr_info[cnt].shdr.sh_size = shdr_info[cnt].data->d_size
Packit 032894
	= crc_offset + 4;
Packit 032894
      debuglink_buf = xcalloc (1, shdr_info[cnt].data->d_size);
Packit 032894
      shdr_info[cnt].data->d_buf = debuglink_buf;
Packit 032894
Packit 032894
      strcpy (shdr_info[cnt].data->d_buf, debug_basename);
Packit 032894
Packit 032894
      /* Cache this Elf_Data describing the CRC32 word in the section.
Packit 032894
	 We'll fill this in when we have written the debug file.  */
Packit 032894
      debuglink_crc_data = *shdr_info[cnt].data;
Packit 032894
      debuglink_crc_data.d_buf = ((char *) debuglink_crc_data.d_buf
Packit 032894
				  + crc_offset);
Packit 032894
      debuglink_crc_data.d_size = 4;
Packit 032894
Packit 032894
      /* One more section done.  */
Packit 032894
      ++cnt;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Index of the section header table in the shdr_info array.  */
Packit 032894
  shdridx = cnt;
Packit 032894
Packit 032894
  /* Add the section header string table section name.  */
Packit 032894
  shdr_info[cnt].se = dwelf_strtab_add_len (shst, ".shstrtab", 10);
Packit 032894
  shdr_info[cnt].idx = idx;
Packit 032894
Packit 032894
  /* Create the section header.  */
Packit 032894
  shdr_info[cnt].shdr.sh_type = SHT_STRTAB;
Packit 032894
  shdr_info[cnt].shdr.sh_flags = 0;
Packit 032894
  shdr_info[cnt].shdr.sh_addr = 0;
Packit 032894
  shdr_info[cnt].shdr.sh_link = SHN_UNDEF;
Packit 032894
  shdr_info[cnt].shdr.sh_info = SHN_UNDEF;
Packit 032894
  shdr_info[cnt].shdr.sh_entsize = 0;
Packit 032894
  /* We set the offset to zero here.  Before we write the ELF file the
Packit 032894
     field must have the correct value.  This is done in the final
Packit 032894
     loop over all section.  Then we have all the information needed.  */
Packit 032894
  shdr_info[cnt].shdr.sh_offset = 0;
Packit 032894
  shdr_info[cnt].shdr.sh_addralign = 1;
Packit 032894
Packit 032894
  /* Create the section.  */
Packit 032894
  shdr_info[cnt].newscn = elf_newscn (newelf);
Packit 032894
  if (shdr_info[cnt].newscn == NULL)
Packit 032894
    {
Packit 032894
      cleanup_debug ();
Packit 032894
      error (EXIT_FAILURE, 0,
Packit 032894
	     gettext ("while create section header section: %s"),
Packit 032894
	     elf_errmsg (-1));
Packit 032894
    }
Packit 032894
  elf_assert (elf_ndxscn (shdr_info[cnt].newscn) == idx);
Packit 032894
Packit 032894
  /* Finalize the string table and fill in the correct indices in the
Packit 032894
     section headers.  */
Packit 032894
  shstrtab_data = elf_newdata (shdr_info[cnt].newscn);
Packit 032894
  if (shstrtab_data == NULL)
Packit 032894
    {
Packit 032894
      cleanup_debug ();
Packit 032894
      error (EXIT_FAILURE, 0,
Packit 032894
	     gettext ("while create section header string table: %s"),
Packit 032894
	     elf_errmsg (-1));
Packit 032894
    }
Packit 032894
  if (dwelf_strtab_finalize (shst, shstrtab_data) == NULL)
Packit 032894
    {
Packit 032894
      cleanup_debug ();
Packit 032894
      error (EXIT_FAILURE, 0,
Packit 032894
	     gettext ("no memory to create section header string table"));
Packit 032894
    }
Packit 032894
Packit 032894
  /* We have to set the section size.  */
Packit 032894
  shdr_info[cnt].shdr.sh_size = shstrtab_data->d_size;
Packit 032894
Packit 032894
  /* Update the section information.  */
Packit 032894
  GElf_Off lastoffset = 0;
Packit 032894
  for (cnt = 1; cnt <= shdridx; ++cnt)
Packit 032894
    if (shdr_info[cnt].idx > 0)
Packit 032894
      {
Packit 032894
	Elf_Data *newdata;
Packit 032894
Packit 032894
	scn = elf_getscn (newelf, shdr_info[cnt].idx);
Packit 032894
	elf_assert (scn != NULL);
Packit 032894
Packit 032894
	/* Update the name.  */
Packit 032894
	shdr_info[cnt].shdr.sh_name = dwelf_strent_off (shdr_info[cnt].se);
Packit 032894
Packit 032894
	/* Update the section header from the input file.  Some fields
Packit 032894
	   might be section indeces which now have to be adjusted.  Keep
Packit 032894
	   the index to the "current" sh_link in case we need it to lookup
Packit 032894
	   symbol table names.  */
Packit 032894
	size_t sh_link = shdr_info[cnt].shdr.sh_link;
Packit 032894
	if (shdr_info[cnt].shdr.sh_link != 0)
Packit 032894
	  shdr_info[cnt].shdr.sh_link =
Packit 032894
	    shdr_info[shdr_info[cnt].shdr.sh_link].idx;
Packit 032894
Packit 032894
	if (shdr_info[cnt].shdr.sh_type == SHT_GROUP)
Packit 032894
	  {
Packit 032894
	    elf_assert (shdr_info[cnt].data != NULL
Packit 032894
			&& shdr_info[cnt].data->d_buf != NULL);
Packit 032894
Packit 032894
	    Elf32_Word *grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf;
Packit 032894
	    /* First word is the section group flag.
Packit 032894
	       Followed by section indexes, that need to be renumbered.  */
Packit 032894
	    for (size_t inner = 1;
Packit 032894
		 inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word);
Packit 032894
		 ++inner)
Packit 032894
	      if (grpref[inner] < shnum)
Packit 032894
		grpref[inner] = shdr_info[grpref[inner]].idx;
Packit 032894
	      else
Packit 032894
		goto illformed;
Packit 032894
	  }
Packit 032894
Packit 032894
	/* Handle the SHT_REL, SHT_RELA, and SHF_INFO_LINK flag.  */
Packit 032894
	if (SH_INFO_LINK_P (&shdr_info[cnt].shdr))
Packit 032894
	  shdr_info[cnt].shdr.sh_info =
Packit 032894
	    shdr_info[shdr_info[cnt].shdr.sh_info].idx;
Packit 032894
Packit 032894
	/* Get the data from the old file if necessary.  We already
Packit 032894
	   created the data for the section header string table.  */
Packit 032894
	if (cnt < shnum)
Packit 032894
	  {
Packit 032894
	    if (shdr_info[cnt].data == NULL)
Packit 032894
	      {
Packit 032894
		shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL);
Packit 032894
		if (shdr_info[cnt].data == NULL)
Packit 032894
		  INTERNAL_ERROR (fname);
Packit 032894
	      }
Packit 032894
Packit 032894
	    /* Set the data.  This is done by copying from the old file.  */
Packit 032894
	    newdata = elf_newdata (scn);
Packit 032894
	    if (newdata == NULL)
Packit 032894
	      INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
	    /* Copy the structure.  */
Packit 032894
	    *newdata = *shdr_info[cnt].data;
Packit 032894
Packit 032894
	    /* We know the size.  */
Packit 032894
	    shdr_info[cnt].shdr.sh_size = shdr_info[cnt].data->d_size;
Packit 032894
Packit 032894
	    /* We have to adjust symbol tables.  The st_shndx member might
Packit 032894
	       have to be updated.  */
Packit 032894
	    if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM
Packit 032894
		|| shdr_info[cnt].shdr.sh_type == SHT_SYMTAB)
Packit 032894
	      {
Packit 032894
		Elf_Data *versiondata = NULL;
Packit 032894
		Elf_Data *shndxdata = NULL;
Packit 032894
Packit 032894
		size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
Packit 032894
Packit 032894
		if (shdr_info[cnt].symtab_idx != 0)
Packit 032894
		  {
Packit 032894
		    elf_assert (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX);
Packit 032894
		    /* This section has extended section information.
Packit 032894
		       We have to modify that information, too.  */
Packit 032894
		    shndxdata = elf_getdata (shdr_info[shdr_info[cnt].symtab_idx].scn,
Packit 032894
					     NULL);
Packit 032894
Packit 032894
		    elf_assert (shndxdata != NULL
Packit 032894
				&& shndxdata->d_buf != NULL
Packit 032894
				&& ((shndxdata->d_size / sizeof (Elf32_Word))
Packit 032894
				    >= shdr_info[cnt].data->d_size / elsize));
Packit 032894
		  }
Packit 032894
Packit 032894
		if (shdr_info[cnt].version_idx != 0)
Packit 032894
		  {
Packit 032894
		    elf_assert (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM);
Packit 032894
		    /* This section has associated version
Packit 032894
		       information.  We have to modify that
Packit 032894
		       information, too.  */
Packit 032894
		    versiondata = elf_getdata (shdr_info[shdr_info[cnt].version_idx].scn,
Packit 032894
					       NULL);
Packit 032894
Packit 032894
		    elf_assert (versiondata != NULL
Packit 032894
				&& versiondata->d_buf != NULL
Packit 032894
				&& ((versiondata->d_size / sizeof (GElf_Versym))
Packit 032894
				    >= shdr_info[cnt].data->d_size / elsize));
Packit 032894
		  }
Packit 032894
Packit 032894
		shdr_info[cnt].newsymidx
Packit 032894
		  = (Elf32_Word *) xcalloc (shdr_info[cnt].data->d_size
Packit 032894
					    / elsize, sizeof (Elf32_Word));
Packit 032894
Packit 032894
		bool last_was_local = true;
Packit 032894
		size_t destidx;
Packit 032894
		size_t inner;
Packit 032894
		for (destidx = inner = 1;
Packit 032894
		     inner < shdr_info[cnt].data->d_size / elsize;
Packit 032894
		     ++inner)
Packit 032894
		  {
Packit 032894
		    Elf32_Word sec;
Packit 032894
		    GElf_Sym sym_mem;
Packit 032894
		    Elf32_Word xshndx;
Packit 032894
		    GElf_Sym *sym = gelf_getsymshndx (shdr_info[cnt].data,
Packit 032894
						      shndxdata, inner,
Packit 032894
						      &sym_mem, &xshndx);
Packit 032894
		    if (sym == NULL)
Packit 032894
		      INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
		    if (sym->st_shndx == SHN_UNDEF
Packit 032894
			|| (sym->st_shndx >= SHN_LORESERVE
Packit 032894
			    && sym->st_shndx != SHN_XINDEX))
Packit 032894
		      {
Packit 032894
			/* This is no section index, leave it alone
Packit 032894
			   unless it is moved.  */
Packit 032894
			if (destidx != inner
Packit 032894
			    && gelf_update_symshndx (shdr_info[cnt].data,
Packit 032894
						     shndxdata,
Packit 032894
						     destidx, sym,
Packit 032894
						     xshndx) == 0)
Packit 032894
			  INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
			shdr_info[cnt].newsymidx[inner] = destidx++;
Packit 032894
Packit 032894
			if (last_was_local
Packit 032894
			    && GELF_ST_BIND (sym->st_info) != STB_LOCAL)
Packit 032894
			  {
Packit 032894
			    last_was_local = false;
Packit 032894
			    shdr_info[cnt].shdr.sh_info = destidx - 1;
Packit 032894
			  }
Packit 032894
Packit 032894
			continue;
Packit 032894
		      }
Packit 032894
Packit 032894
		    /* Get the full section index, if necessary from the
Packit 032894
		       XINDEX table.  */
Packit 032894
		    if (sym->st_shndx == SHN_XINDEX)
Packit 032894
		      elf_assert (shndxdata != NULL
Packit 032894
				  && shndxdata->d_buf != NULL);
Packit 032894
		    size_t sidx = (sym->st_shndx != SHN_XINDEX
Packit 032894
				   ? sym->st_shndx : xshndx);
Packit 032894
		    elf_assert (sidx < shnum);
Packit 032894
		    sec = shdr_info[sidx].idx;
Packit 032894
Packit 032894
		    if (sec != 0)
Packit 032894
		      {
Packit 032894
			GElf_Section nshndx;
Packit 032894
			Elf32_Word nxshndx;
Packit 032894
Packit 032894
			if (sec < SHN_LORESERVE)
Packit 032894
			  {
Packit 032894
			    nshndx = sec;
Packit 032894
			    nxshndx = 0;
Packit 032894
			  }
Packit 032894
			else
Packit 032894
			  {
Packit 032894
			    nshndx = SHN_XINDEX;
Packit 032894
			    nxshndx = sec;
Packit 032894
			  }
Packit 032894
Packit 032894
			elf_assert (sec < SHN_LORESERVE || shndxdata != NULL);
Packit 032894
Packit 032894
			if ((inner != destidx || nshndx != sym->st_shndx
Packit 032894
			     || (shndxdata != NULL && nxshndx != xshndx))
Packit 032894
			    && (sym->st_shndx = nshndx,
Packit 032894
				gelf_update_symshndx (shdr_info[cnt].data,
Packit 032894
						      shndxdata,
Packit 032894
						      destidx, sym,
Packit 032894
						      nxshndx) == 0))
Packit 032894
			  INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
			shdr_info[cnt].newsymidx[inner] = destidx++;
Packit 032894
Packit 032894
			if (last_was_local
Packit 032894
			    && GELF_ST_BIND (sym->st_info) != STB_LOCAL)
Packit 032894
			  {
Packit 032894
			    last_was_local = false;
Packit 032894
			    shdr_info[cnt].shdr.sh_info = destidx - 1;
Packit 032894
			  }
Packit 032894
		      }
Packit 032894
		    else if ((shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) != 0
Packit 032894
			     && GELF_ST_TYPE (sym->st_info) != STT_SECTION
Packit 032894
			     && shdr_info[sidx].shdr.sh_type != SHT_GROUP)
Packit 032894
		      {
Packit 032894
			/* Removing a real symbol from an allocated
Packit 032894
			   symbol table is hard and probably a
Packit 032894
			   mistake.  Really removing it means
Packit 032894
			   rewriting the dynamic segment and hash
Packit 032894
			   sections.  Just warn and set the symbol
Packit 032894
			   section to UNDEF.  */
Packit 032894
			error (0, 0,
Packit 032894
			       gettext ("Cannot remove symbol [%zd] from allocated symbol table [%zd]"), inner, cnt);
Packit 032894
			sym->st_shndx = SHN_UNDEF;
Packit 032894
			if (gelf_update_sym (shdr_info[cnt].data, destidx,
Packit 032894
					     sym) == 0)
Packit 032894
			  INTERNAL_ERROR (fname);
Packit 032894
			shdr_info[cnt].newsymidx[inner] = destidx++;
Packit 032894
		      }
Packit 032894
		    else if (debug_fname != NULL
Packit 032894
			     && shdr_info[cnt].debug_data == NULL)
Packit 032894
		      /* The symbol points to a section that is discarded
Packit 032894
			 but isn't preserved in the debug file. Check that
Packit 032894
			 this is a section or group signature symbol
Packit 032894
			 for a section which has been removed.  Or a special
Packit 032894
			 data marker symbol to a debug section.  */
Packit 032894
		      {
Packit 032894
			elf_assert (GELF_ST_TYPE (sym->st_info) == STT_SECTION
Packit 032894
				    || ((shdr_info[sidx].shdr.sh_type
Packit 032894
					 == SHT_GROUP)
Packit 032894
					&& (shdr_info[sidx].shdr.sh_info
Packit 032894
					    == inner))
Packit 032894
				    || ebl_data_marker_symbol (ebl, sym,
Packit 032894
						elf_strptr (elf, sh_link,
Packit 032894
							    sym->st_name)));
Packit 032894
		      }
Packit 032894
		  }
Packit 032894
Packit 032894
		if (destidx != inner)
Packit 032894
		  {
Packit 032894
		    /* The size of the symbol table changed.  */
Packit 032894
		    shdr_info[cnt].shdr.sh_size = newdata->d_size
Packit 032894
		      = destidx * elsize;
Packit 032894
		    any_symtab_changes = true;
Packit 032894
		  }
Packit 032894
		else
Packit 032894
		  {
Packit 032894
		    /* The symbol table didn't really change.  */
Packit 032894
		    free (shdr_info[cnt].newsymidx);
Packit 032894
		    shdr_info[cnt].newsymidx = NULL;
Packit 032894
		  }
Packit 032894
	      }
Packit 032894
	  }
Packit 032894
Packit 032894
	/* If we have to, compute the offset of the section.
Packit 032894
	   If allocate and unallocated sections are mixed, we only update
Packit 032894
	   the allocated ones now.  The unallocated ones come second.  */
Packit 032894
	if (! mixed_allocated_unallocated
Packit 032894
	    || (shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) != 0)
Packit 032894
	  {
Packit 032894
	    if (shdr_info[cnt].shdr.sh_offset == 0)
Packit 032894
	      shdr_info[cnt].shdr.sh_offset
Packit 032894
		= ((lastoffset + shdr_info[cnt].shdr.sh_addralign - 1)
Packit 032894
		   & ~((GElf_Off) (shdr_info[cnt].shdr.sh_addralign - 1)));
Packit 032894
Packit 032894
	    /* Set the section header in the new file.  */
Packit 032894
	    if (unlikely (gelf_update_shdr (scn, &shdr_info[cnt].shdr) == 0))
Packit 032894
	      /* There cannot be any overflows.  */
Packit 032894
	      INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
	    /* Remember the last section written so far.  */
Packit 032894
	    GElf_Off filesz = (shdr_info[cnt].shdr.sh_type != SHT_NOBITS
Packit 032894
			       ? shdr_info[cnt].shdr.sh_size : 0);
Packit 032894
	    if (lastoffset < shdr_info[cnt].shdr.sh_offset + filesz)
Packit 032894
	      lastoffset = shdr_info[cnt].shdr.sh_offset + filesz;
Packit 032894
	  }
Packit 032894
      }
Packit 032894
Packit 032894
  /* We might have to update the unallocated sections after we done the
Packit 032894
     allocated ones.  lastoffset is set to right after the last allocated
Packit 032894
     section.  */
Packit 032894
  if (mixed_allocated_unallocated)
Packit 032894
    for (cnt = 1; cnt <= shdridx; ++cnt)
Packit 032894
      if (shdr_info[cnt].idx > 0)
Packit 032894
	{
Packit 032894
	  scn = elf_getscn (newelf, shdr_info[cnt].idx);
Packit 032894
	  if ((shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0)
Packit 032894
	    {
Packit 032894
	      if (shdr_info[cnt].shdr.sh_offset == 0)
Packit 032894
		shdr_info[cnt].shdr.sh_offset
Packit 032894
		  = ((lastoffset + shdr_info[cnt].shdr.sh_addralign - 1)
Packit 032894
		     & ~((GElf_Off) (shdr_info[cnt].shdr.sh_addralign - 1)));
Packit 032894
Packit 032894
	      /* Set the section header in the new file.  */
Packit 032894
	      if (unlikely (gelf_update_shdr (scn, &shdr_info[cnt].shdr) == 0))
Packit 032894
		/* There cannot be any overflows.  */
Packit 032894
		INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
	      /* Remember the last section written so far.  */
Packit 032894
	      GElf_Off filesz = (shdr_info[cnt].shdr.sh_type != SHT_NOBITS
Packit 032894
				 ? shdr_info[cnt].shdr.sh_size : 0);
Packit 032894
	      if (lastoffset < shdr_info[cnt].shdr.sh_offset + filesz)
Packit 032894
		lastoffset = shdr_info[cnt].shdr.sh_offset + filesz;
Packit 032894
	    }
Packit 032894
	}
Packit 032894
Packit 032894
  /* Adjust symbol references if symbol tables changed.  */
Packit 032894
  if (any_symtab_changes)
Packit 032894
    /* Find all relocation sections which use this symbol table.  */
Packit 032894
    for (cnt = 1; cnt <= shdridx; ++cnt)
Packit 032894
      {
Packit 032894
	/* Update section headers when the data size has changed.
Packit 032894
	   We also update the SHT_NOBITS section in the debug
Packit 032894
	   file so that the section headers match in sh_size.  */
Packit 032894
	inline void update_section_size (const Elf_Data *newdata)
Packit 032894
	{
Packit 032894
	  GElf_Shdr shdr_mem;
Packit 032894
	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Packit 032894
	  shdr->sh_size = newdata->d_size;
Packit 032894
	  (void) gelf_update_shdr (scn, shdr);
Packit 032894
	  if (debugelf != NULL)
Packit 032894
	    {
Packit 032894
	      /* libelf will use d_size to set sh_size.  */
Packit 032894
	      Elf_Data *debugdata = elf_getdata (elf_getscn (debugelf,
Packit 032894
							     cnt), NULL);
Packit 032894
	      if (debugdata == NULL)
Packit 032894
		INTERNAL_ERROR (fname);
Packit 032894
	      debugdata->d_size = newdata->d_size;
Packit 032894
	    }
Packit 032894
	}
Packit 032894
Packit 032894
	if (shdr_info[cnt].idx == 0 && debug_fname == NULL)
Packit 032894
	  /* Ignore sections which are discarded.  When we are saving a
Packit 032894
	     relocation section in a separate debug file, we must fix up
Packit 032894
	     the symbol table references.  */
Packit 032894
	  continue;
Packit 032894
Packit 032894
	const Elf32_Word symtabidx = shdr_info[cnt].old_sh_link;
Packit 032894
	elf_assert (symtabidx < shnum + 2);
Packit 032894
	const Elf32_Word *const newsymidx = shdr_info[symtabidx].newsymidx;
Packit 032894
	switch (shdr_info[cnt].shdr.sh_type)
Packit 032894
	  {
Packit 032894
	    inline bool no_symtab_updates (void)
Packit 032894
	    {
Packit 032894
	      /* If the symbol table hasn't changed, do not do anything.  */
Packit 032894
	      if (shdr_info[symtabidx].newsymidx == NULL)
Packit 032894
		return true;
Packit 032894
Packit 032894
	      /* If the symbol table is not discarded, but additionally
Packit 032894
		 duplicated in the separate debug file and this section
Packit 032894
		 is discarded, don't adjust anything.  */
Packit 032894
	      return (shdr_info[cnt].idx == 0
Packit 032894
		      && shdr_info[symtabidx].debug_data != NULL);
Packit 032894
	    }
Packit 032894
Packit 032894
	  case SHT_REL:
Packit 032894
	  case SHT_RELA:
Packit 032894
	    if (no_symtab_updates ())
Packit 032894
	      break;
Packit 032894
Packit 032894
	    Elf_Data *d = elf_getdata (shdr_info[cnt].idx == 0
Packit 032894
				       ? elf_getscn (debugelf, cnt)
Packit 032894
				       : elf_getscn (newelf,
Packit 032894
						     shdr_info[cnt].idx),
Packit 032894
				       NULL);
Packit 032894
	    elf_assert (d != NULL && d->d_buf != NULL
Packit 032894
			&& shdr_info[cnt].shdr.sh_entsize != 0);
Packit 032894
	    size_t nrels = (shdr_info[cnt].shdr.sh_size
Packit 032894
			    / shdr_info[cnt].shdr.sh_entsize);
Packit 032894
Packit 032894
	    size_t symsize = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
Packit 032894
	    const Elf32_Word symidxn = (shdr_info[symtabidx].data->d_size
Packit 032894
					/ symsize);
Packit 032894
	    if (shdr_info[cnt].shdr.sh_type == SHT_REL)
Packit 032894
	      for (size_t relidx = 0; relidx < nrels; ++relidx)
Packit 032894
		{
Packit 032894
		  GElf_Rel rel_mem;
Packit 032894
		  if (gelf_getrel (d, relidx, &rel_mem) == NULL)
Packit 032894
		    INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
		  size_t symidx = GELF_R_SYM (rel_mem.r_info);
Packit 032894
		  elf_assert (symidx < symidxn);
Packit 032894
		  if (newsymidx[symidx] != symidx)
Packit 032894
		    {
Packit 032894
		      rel_mem.r_info
Packit 032894
			= GELF_R_INFO (newsymidx[symidx],
Packit 032894
				       GELF_R_TYPE (rel_mem.r_info));
Packit 032894
Packit 032894
		      if (gelf_update_rel (d, relidx, &rel_mem) == 0)
Packit 032894
			INTERNAL_ERROR (fname);
Packit 032894
		    }
Packit 032894
		}
Packit 032894
	    else
Packit 032894
	      for (size_t relidx = 0; relidx < nrels; ++relidx)
Packit 032894
		{
Packit 032894
		  GElf_Rela rel_mem;
Packit 032894
		  if (gelf_getrela (d, relidx, &rel_mem) == NULL)
Packit 032894
		    INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
		  size_t symidx = GELF_R_SYM (rel_mem.r_info);
Packit 032894
		  elf_assert (symidx < symidxn);
Packit 032894
		  if (newsymidx[symidx] != symidx)
Packit 032894
		    {
Packit 032894
		      rel_mem.r_info
Packit 032894
			= GELF_R_INFO (newsymidx[symidx],
Packit 032894
				       GELF_R_TYPE (rel_mem.r_info));
Packit 032894
Packit 032894
		      if (gelf_update_rela (d, relidx, &rel_mem) == 0)
Packit 032894
			INTERNAL_ERROR (fname);
Packit 032894
		    }
Packit 032894
		}
Packit 032894
	    break;
Packit 032894
Packit 032894
	  case SHT_HASH:
Packit 032894
	    if (no_symtab_updates ())
Packit 032894
	      break;
Packit 032894
Packit 032894
	    /* We have to recompute the hash table.  */
Packit 032894
Packit 032894
	    elf_assert (shdr_info[cnt].idx > 0);
Packit 032894
Packit 032894
	    /* The hash section in the new file.  */
Packit 032894
	    scn = elf_getscn (newelf, shdr_info[cnt].idx);
Packit 032894
Packit 032894
	    /* The symbol table data.  */
Packit 032894
	    Elf_Data *symd = elf_getdata (elf_getscn (newelf,
Packit 032894
						      shdr_info[symtabidx].idx),
Packit 032894
					  NULL);
Packit 032894
	    elf_assert (symd != NULL && symd->d_buf != NULL);
Packit 032894
Packit 032894
	    /* The hash table data.  */
Packit 032894
	    Elf_Data *hashd = elf_getdata (scn, NULL);
Packit 032894
	    elf_assert (hashd != NULL && hashd->d_buf != NULL);
Packit 032894
Packit 032894
	    if (shdr_info[cnt].shdr.sh_entsize == sizeof (Elf32_Word))
Packit 032894
	      {
Packit 032894
		/* Sane arches first.  */
Packit 032894
		elf_assert (hashd->d_size >= 2 * sizeof (Elf32_Word));
Packit 032894
		Elf32_Word *bucket = (Elf32_Word *) hashd->d_buf;
Packit 032894
Packit 032894
		size_t strshndx = shdr_info[symtabidx].old_sh_link;
Packit 032894
		size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
Packit 032894
Packit 032894
		Elf32_Word nchain = bucket[1];
Packit 032894
		Elf32_Word nbucket = bucket[0];
Packit 032894
		uint64_t used_buf = ((2ULL + nchain + nbucket)
Packit 032894
				     * sizeof (Elf32_Word));
Packit 032894
		elf_assert (used_buf <= hashd->d_size);
Packit 032894
Packit 032894
		/* Adjust the nchain value.  The symbol table size
Packit 032894
		   changed.  We keep the same size for the bucket array.  */
Packit 032894
		bucket[1] = symd->d_size / elsize;
Packit 032894
		bucket += 2;
Packit 032894
		Elf32_Word *chain = bucket + nbucket;
Packit 032894
Packit 032894
		/* New size of the section.  */
Packit 032894
		size_t n_size = ((2 + symd->d_size / elsize + nbucket)
Packit 032894
				 * sizeof (Elf32_Word));
Packit 032894
		elf_assert (n_size <= hashd->d_size);
Packit 032894
		hashd->d_size = n_size;
Packit 032894
		update_section_size (hashd);
Packit 032894
Packit 032894
		/* Clear the arrays.  */
Packit 032894
		memset (bucket, '\0',
Packit 032894
			(symd->d_size / elsize + nbucket)
Packit 032894
			* sizeof (Elf32_Word));
Packit 032894
Packit 032894
		for (size_t inner = shdr_info[symtabidx].shdr.sh_info;
Packit 032894
		     inner < symd->d_size / elsize; ++inner)
Packit 032894
		  {
Packit 032894
		    GElf_Sym sym_mem;
Packit 032894
		    GElf_Sym *sym = gelf_getsym (symd, inner, &sym_mem);
Packit 032894
		    elf_assert (sym != NULL);
Packit 032894
Packit 032894
		    const char *name = elf_strptr (elf, strshndx,
Packit 032894
						   sym->st_name);
Packit 032894
		    elf_assert (name != NULL && nbucket != 0);
Packit 032894
		    size_t hidx = elf_hash (name) % nbucket;
Packit 032894
Packit 032894
		    if (bucket[hidx] == 0)
Packit 032894
		      bucket[hidx] = inner;
Packit 032894
		    else
Packit 032894
		      {
Packit 032894
			hidx = bucket[hidx];
Packit 032894
Packit 032894
			while (chain[hidx] != 0 && chain[hidx] < nchain)
Packit 032894
			  hidx = chain[hidx];
Packit 032894
Packit 032894
			chain[hidx] = inner;
Packit 032894
		      }
Packit 032894
		  }
Packit 032894
	      }
Packit 032894
	    else
Packit 032894
	      {
Packit 032894
		/* Alpha and S390 64-bit use 64-bit SHT_HASH entries.  */
Packit 032894
		elf_assert (shdr_info[cnt].shdr.sh_entsize
Packit 032894
			    == sizeof (Elf64_Xword));
Packit 032894
Packit 032894
		Elf64_Xword *bucket = (Elf64_Xword *) hashd->d_buf;
Packit 032894
Packit 032894
		size_t strshndx = shdr_info[symtabidx].old_sh_link;
Packit 032894
		size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
Packit 032894
Packit 032894
		elf_assert (symd->d_size >= 2 * sizeof (Elf64_Xword));
Packit 032894
		Elf64_Xword nbucket = bucket[0];
Packit 032894
		Elf64_Xword nchain = bucket[1];
Packit 032894
		uint64_t maxwords = hashd->d_size / sizeof (Elf64_Xword);
Packit 032894
		elf_assert (maxwords >= 2
Packit 032894
			    && maxwords - 2 >= nbucket
Packit 032894
			    && maxwords - 2 - nbucket >= nchain);
Packit 032894
Packit 032894
		/* Adjust the nchain value.  The symbol table size
Packit 032894
		   changed.  We keep the same size for the bucket array.  */
Packit 032894
		bucket[1] = symd->d_size / elsize;
Packit 032894
		bucket += 2;
Packit 032894
		Elf64_Xword *chain = bucket + nbucket;
Packit 032894
Packit 032894
		/* New size of the section.  */
Packit 032894
		size_t n_size = ((2 + symd->d_size / elsize + nbucket)
Packit 032894
				 * sizeof (Elf64_Xword));
Packit 032894
		elf_assert (n_size <= hashd->d_size);
Packit 032894
		hashd->d_size = n_size;
Packit 032894
		update_section_size (hashd);
Packit 032894
Packit 032894
		/* Clear the arrays.  */
Packit 032894
		memset (bucket, '\0',
Packit 032894
			(symd->d_size / elsize + nbucket)
Packit 032894
			* sizeof (Elf64_Xword));
Packit 032894
Packit 032894
		for (size_t inner = shdr_info[symtabidx].shdr.sh_info;
Packit 032894
		     inner < symd->d_size / elsize; ++inner)
Packit 032894
		  {
Packit 032894
		    GElf_Sym sym_mem;
Packit 032894
		    GElf_Sym *sym = gelf_getsym (symd, inner, &sym_mem);
Packit 032894
		    elf_assert (sym != NULL);
Packit 032894
Packit 032894
		    const char *name = elf_strptr (elf, strshndx,
Packit 032894
						   sym->st_name);
Packit 032894
		    elf_assert (name != NULL && nbucket != 0);
Packit 032894
		    size_t hidx = elf_hash (name) % nbucket;
Packit 032894
Packit 032894
		    if (bucket[hidx] == 0)
Packit 032894
		      bucket[hidx] = inner;
Packit 032894
		    else
Packit 032894
		      {
Packit 032894
			hidx = bucket[hidx];
Packit 032894
Packit 032894
			while (chain[hidx] != 0 && chain[hidx] < nchain)
Packit 032894
			  hidx = chain[hidx];
Packit 032894
Packit 032894
			chain[hidx] = inner;
Packit 032894
		      }
Packit 032894
		  }
Packit 032894
	      }
Packit 032894
	    break;
Packit 032894
Packit 032894
	  case SHT_GNU_versym:
Packit 032894
	    /* If the symbol table changed we have to adjust the entries.  */
Packit 032894
	    if (no_symtab_updates ())
Packit 032894
	      break;
Packit 032894
Packit 032894
	    elf_assert (shdr_info[cnt].idx > 0);
Packit 032894
Packit 032894
	    /* The symbol version section in the new file.  */
Packit 032894
	    scn = elf_getscn (newelf, shdr_info[cnt].idx);
Packit 032894
Packit 032894
	    /* The symbol table data.  */
Packit 032894
	    symd = elf_getdata (elf_getscn (newelf, shdr_info[symtabidx].idx),
Packit 032894
				NULL);
Packit 032894
	    elf_assert (symd != NULL && symd->d_buf != NULL);
Packit 032894
	    size_t symz = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
Packit 032894
	    const Elf32_Word syms = (shdr_info[symtabidx].data->d_size / symz);
Packit 032894
Packit 032894
	    /* The version symbol data.  */
Packit 032894
	    Elf_Data *verd = elf_getdata (scn, NULL);
Packit 032894
	    elf_assert (verd != NULL && verd->d_buf != NULL);
Packit 032894
Packit 032894
	    /* The symbol version array.  */
Packit 032894
	    GElf_Half *verstab = (GElf_Half *) verd->d_buf;
Packit 032894
Packit 032894
	    /* Walk through the list and */
Packit 032894
	    size_t elsize = gelf_fsize (elf, verd->d_type, 1, EV_CURRENT);
Packit 032894
	    Elf32_Word vers = verd->d_size / elsize;
Packit 032894
	    for (size_t inner = 1; inner < vers && inner < syms; ++inner)
Packit 032894
	      if (newsymidx[inner] != 0 && newsymidx[inner] < vers)
Packit 032894
		/* Overwriting the same array works since the
Packit 032894
		   reordering can only move entries to lower indices
Packit 032894
		   in the array.  */
Packit 032894
		verstab[newsymidx[inner]] = verstab[inner];
Packit 032894
Packit 032894
	    /* New size of the section.  */
Packit 032894
	    verd->d_size = gelf_fsize (newelf, verd->d_type,
Packit 032894
				       symd->d_size
Packit 032894
				       / gelf_fsize (elf, symd->d_type, 1,
Packit 032894
						     EV_CURRENT),
Packit 032894
				       EV_CURRENT);
Packit 032894
	    update_section_size (verd);
Packit 032894
	    break;
Packit 032894
Packit 032894
	  case SHT_GROUP:
Packit 032894
	    if (no_symtab_updates ())
Packit 032894
	      break;
Packit 032894
Packit 032894
	    /* Yes, the symbol table changed.
Packit 032894
	       Update the section header of the section group.  */
Packit 032894
	    scn = elf_getscn (newelf, shdr_info[cnt].idx);
Packit 032894
	    GElf_Shdr shdr_mem;
Packit 032894
	    GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Packit 032894
	    elf_assert (shdr != NULL);
Packit 032894
Packit 032894
	    size_t symsz = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
Packit 032894
	    const Elf32_Word symn = (shdr_info[symtabidx].data->d_size
Packit 032894
				     / symsz);
Packit 032894
	    elf_assert (shdr->sh_info < symn);
Packit 032894
	    shdr->sh_info = newsymidx[shdr->sh_info];
Packit 032894
Packit 032894
	    (void) gelf_update_shdr (scn, shdr);
Packit 032894
	    break;
Packit 032894
	  }
Packit 032894
      }
Packit 032894
Packit 032894
  /* Remove any relocations between debug sections in ET_REL
Packit 032894
     for the debug file when requested.  These relocations are always
Packit 032894
     zero based between the unallocated sections.  */
Packit 032894
  if (debug_fname != NULL && removing_sections
Packit 032894
      && reloc_debug && ehdr->e_type == ET_REL)
Packit 032894
    remove_debug_relocations (ebl, debugelf, ehdr, fname, shstrndx);
Packit 032894
Packit 032894
  /* Now that we have done all adjustments to the data,
Packit 032894
     we can actually write out the debug file.  */
Packit 032894
  if (debug_fname != NULL && removing_sections)
Packit 032894
    {
Packit 032894
      /* Finally write the file.  */
Packit 032894
      if (unlikely (elf_update (debugelf, ELF_C_WRITE) == -1))
Packit 032894
	{
Packit 032894
	  error (0, 0, gettext ("while writing '%s': %s"),
Packit 032894
		 tmp_debug_fname, elf_errmsg (-1));
Packit 032894
	  result = 1;
Packit 032894
	  goto fail_close;
Packit 032894
	}
Packit 032894
Packit 032894
      /* Create the real output file.  First rename, then change the
Packit 032894
	 mode.  */
Packit 032894
      if (rename (tmp_debug_fname, debug_fname) != 0
Packit 032894
	  || fchmod (debug_fd, mode) != 0)
Packit 032894
	{
Packit 032894
	  error (0, errno, gettext ("while creating '%s'"), debug_fname);
Packit 032894
	  result = 1;
Packit 032894
	  goto fail_close;
Packit 032894
	}
Packit 032894
Packit 032894
      /* The temporary file does not exist anymore.  */
Packit 032894
      free (tmp_debug_fname);
Packit 032894
      tmp_debug_fname = NULL;
Packit 032894
Packit 032894
      if (!remove_shdrs)
Packit 032894
	{
Packit 032894
	  uint32_t debug_crc;
Packit 032894
	  Elf_Data debug_crc_data =
Packit 032894
	    {
Packit 032894
	      .d_type = ELF_T_WORD,
Packit 032894
	      .d_buf = &debug_crc,
Packit 032894
	      .d_size = sizeof (debug_crc),
Packit 032894
	      .d_version = EV_CURRENT
Packit 032894
	    };
Packit 032894
Packit 032894
	  /* Compute the checksum which we will add to the executable.  */
Packit 032894
	  if (crc32_file (debug_fd, &debug_crc) != 0)
Packit 032894
	    {
Packit 032894
	      error (0, errno, gettext ("\
Packit 032894
while computing checksum for debug information"));
Packit 032894
	      unlink (debug_fname);
Packit 032894
	      result = 1;
Packit 032894
	      goto fail_close;
Packit 032894
	    }
Packit 032894
Packit 032894
	  /* Store it in the debuglink section data.  */
Packit 032894
	  if (unlikely (gelf_xlatetof (newelf, &debuglink_crc_data,
Packit 032894
				       &debug_crc_data, ehdr->e_ident[EI_DATA])
Packit 032894
			!= &debuglink_crc_data))
Packit 032894
	    INTERNAL_ERROR (fname);
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  lastsec_offset = shdr_info[shdridx].shdr.sh_offset;
Packit 032894
  lastsec_size = shdr_info[shdridx].shdr.sh_size;
Packit 032894
Packit 032894
 done:
Packit 032894
  /* Finally finish the ELF header.  Fill in the fields not handled by
Packit 032894
     libelf from the old file.  */
Packit 032894
  newehdr = gelf_getehdr (newelf, &newehdr_mem);
Packit 032894
  if (newehdr == NULL)
Packit 032894
    INTERNAL_ERROR (fname);
Packit 032894
Packit 032894
  memcpy (newehdr->e_ident, ehdr->e_ident, EI_NIDENT);
Packit 032894
  newehdr->e_type = ehdr->e_type;
Packit 032894
  newehdr->e_machine = ehdr->e_machine;
Packit 032894
  newehdr->e_version = ehdr->e_version;
Packit 032894
  newehdr->e_entry = ehdr->e_entry;
Packit 032894
  newehdr->e_flags = ehdr->e_flags;
Packit 032894
  newehdr->e_phoff = ehdr->e_phoff;
Packit 032894
Packit 032894
  /* We need to position the section header table.  */
Packit 032894
  const size_t offsize = gelf_fsize (elf, ELF_T_OFF, 1, EV_CURRENT);
Packit 032894
  newehdr->e_shoff = ((lastsec_offset + lastsec_size + offsize - 1)
Packit 032894
		      & ~((GElf_Off) (offsize - 1)));
Packit 032894
  newehdr->e_shentsize = gelf_fsize (elf, ELF_T_SHDR, 1, EV_CURRENT);
Packit 032894
Packit 032894
  if (gelf_update_ehdr (newelf, newehdr) == 0)
Packit 032894
    {
Packit 032894
      error (0, 0, gettext ("%s: error while creating ELF header: %s"),
Packit 032894
	     output_fname ?: fname, elf_errmsg (-1));
Packit 032894
      cleanup_debug ();
Packit 032894
      return 1;
Packit 032894
    }
Packit 032894
Packit 032894
  /* The new section header string table index.  */
Packit 032894
  if (update_shdrstrndx (newelf, idx) != 0)
Packit 032894
    {
Packit 032894
      error (0, 0, gettext ("%s: error updating shdrstrndx: %s"),
Packit 032894
	     output_fname ?: fname, elf_errmsg (-1));
Packit 032894
      cleanup_debug ();
Packit 032894
      return 1;
Packit 032894
    }
Packit 032894
Packit 032894
  /* We have everything from the old file.  */
Packit 032894
  if (elf_cntl (elf, ELF_C_FDDONE) != 0)
Packit 032894
    {
Packit 032894
      error (0, 0, gettext ("%s: error while reading the file: %s"),
Packit 032894
	     fname, elf_errmsg (-1));
Packit 032894
      cleanup_debug ();
Packit 032894
      return 1;
Packit 032894
    }
Packit 032894
Packit 032894
  /* The ELF library better follows our layout when this is not a
Packit 032894
     relocatable object file.  */
Packit 032894
  elf_flagelf (newelf, ELF_C_SET,
Packit 032894
	       (phnum > 0 ? ELF_F_LAYOUT : 0)
Packit 032894
	       | (permissive ? ELF_F_PERMISSIVE : 0));
Packit 032894
Packit 032894
  /* Finally write the file.  */
Packit 032894
  if (elf_update (newelf, ELF_C_WRITE) == -1)
Packit 032894
    {
Packit 032894
      error (0, 0, gettext ("while writing '%s': %s"),
Packit 032894
	     output_fname ?: fname, elf_errmsg (-1));
Packit 032894
      result = 1;
Packit 032894
    }
Packit 032894
Packit 032894
  if (remove_shdrs)
Packit 032894
    {
Packit 032894
      /* libelf can't cope without the section headers being properly intact.
Packit 032894
	 So we just let it write them normally, and then we nuke them later.  */
Packit 032894
Packit 032894
      if (newehdr->e_ident[EI_CLASS] == ELFCLASS32)
Packit 032894
	{
Packit 032894
	  assert (offsetof (Elf32_Ehdr, e_shentsize) + sizeof (Elf32_Half)
Packit 032894
		  == offsetof (Elf32_Ehdr, e_shnum));
Packit 032894
	  assert (offsetof (Elf32_Ehdr, e_shnum) + sizeof (Elf32_Half)
Packit 032894
		  == offsetof (Elf32_Ehdr, e_shstrndx));
Packit 032894
	  const Elf32_Off zero_off = 0;
Packit 032894
	  const Elf32_Half zero[3] = { 0, 0, SHN_UNDEF };
Packit 032894
	  if (pwrite_retry (fd, &zero_off, sizeof zero_off,
Packit 032894
			    offsetof (Elf32_Ehdr, e_shoff)) != sizeof zero_off
Packit 032894
	      || (pwrite_retry (fd, zero, sizeof zero,
Packit 032894
				offsetof (Elf32_Ehdr, e_shentsize))
Packit 032894
		  != sizeof zero)
Packit 032894
	      || ftruncate (fd, lastsec_offset) < 0)
Packit 032894
	    {
Packit 032894
	      error (0, errno, gettext ("while writing '%s'"),
Packit 032894
		     output_fname ?: fname);
Packit 032894
	      result = 1;
Packit 032894
	    }
Packit 032894
	}
Packit 032894
      else
Packit 032894
	{
Packit 032894
	  assert (offsetof (Elf64_Ehdr, e_shentsize) + sizeof (Elf64_Half)
Packit 032894
		  == offsetof (Elf64_Ehdr, e_shnum));
Packit 032894
	  assert (offsetof (Elf64_Ehdr, e_shnum) + sizeof (Elf64_Half)
Packit 032894
		  == offsetof (Elf64_Ehdr, e_shstrndx));
Packit 032894
	  const Elf64_Off zero_off = 0;
Packit 032894
	  const Elf64_Half zero[3] = { 0, 0, SHN_UNDEF };
Packit 032894
	  if (pwrite_retry (fd, &zero_off, sizeof zero_off,
Packit 032894
			    offsetof (Elf64_Ehdr, e_shoff)) != sizeof zero_off
Packit 032894
	      || (pwrite_retry (fd, zero, sizeof zero,
Packit 032894
				offsetof (Elf64_Ehdr, e_shentsize))
Packit 032894
		  != sizeof zero)
Packit 032894
	      || ftruncate (fd, lastsec_offset) < 0)
Packit 032894
	    {
Packit 032894
	      error (0, errno, gettext ("while writing '%s'"),
Packit 032894
		     output_fname ?: fname);
Packit 032894
	      result = 1;
Packit 032894
	    }
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
 fail_close:
Packit 032894
  if (shdr_info != NULL)
Packit 032894
    {
Packit 032894
      /* For some sections we might have created an table to map symbol
Packit 032894
	 table indices.  Or we might kept (original) data around to put
Packit 032894
	 into the .debug file.  */
Packit 032894
      for (cnt = 1; cnt <= shdridx; ++cnt)
Packit 032894
	{
Packit 032894
	  free (shdr_info[cnt].newsymidx);
Packit 032894
	  if (shdr_info[cnt].debug_data != NULL)
Packit 032894
	    free (shdr_info[cnt].debug_data->d_buf);
Packit 032894
	}
Packit 032894
Packit 032894
      /* Free data we allocated for the .gnu_debuglink section. */
Packit 032894
      free (debuglink_buf);
Packit 032894
Packit 032894
      /* Free the memory.  */
Packit 032894
      if ((shnum + 2) * sizeof (struct shdr_info) > MAX_STACK_ALLOC)
Packit 032894
	free (shdr_info);
Packit 032894
    }
Packit 032894
Packit 032894
  /* Free other resources.  */
Packit 032894
  if (shstrtab_data != NULL)
Packit 032894
    free (shstrtab_data->d_buf);
Packit 032894
  if (shst != NULL)
Packit 032894
    dwelf_strtab_free (shst);
Packit 032894
Packit 032894
  /* That was it.  Close the descriptors.  */
Packit 032894
  if (elf_end (newelf) != 0)
Packit 032894
    {
Packit 032894
      error (0, 0, gettext ("error while finishing '%s': %s"),
Packit 032894
	     output_fname ?: fname, elf_errmsg (-1));
Packit 032894
      result = 1;
Packit 032894
    }
Packit 032894
Packit 032894
  if (debugelf != NULL && elf_end (debugelf) != 0)
Packit 032894
    {
Packit 032894
      error (0, 0, gettext ("error while finishing '%s': %s"), debug_fname,
Packit 032894
	     elf_errmsg (-1));
Packit 032894
      result = 1;
Packit 032894
    }
Packit 032894
Packit 032894
 fail:
Packit 032894
  /* Close the EBL backend.  */
Packit 032894
  if (ebl != NULL)
Packit 032894
    ebl_closebackend (ebl);
Packit 032894
Packit 032894
  cleanup_debug ();
Packit 032894
Packit 032894
  /* If requested, preserve the timestamp.  */
Packit 032894
  if (tvp != NULL)
Packit 032894
    {
Packit 032894
      if (futimens (fd, tvp) != 0)
Packit 032894
	{
Packit 032894
	  error (0, errno, gettext ("\
Packit 032894
cannot set access and modification date of '%s'"),
Packit 032894
		 output_fname ?: fname);
Packit 032894
	  result = 1;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  /* Close the file descriptor if we created a new file.  */
Packit 032894
  if (output_fname != NULL)
Packit 032894
    {
Packit 032894
      close (fd);
Packit 032894
      if (result != 0)
Packit 032894
       unlink (output_fname);
Packit 032894
    }
Packit 032894
Packit 032894
  return result;
Packit 032894
}
Packit 032894
Packit 032894
static void
Packit 032894
cleanup_debug (void)
Packit 032894
{
Packit 032894
  if (debug_fd >= 0)
Packit 032894
    {
Packit 032894
      if (tmp_debug_fname != NULL)
Packit 032894
	{
Packit 032894
	  unlink (tmp_debug_fname);
Packit 032894
	  free (tmp_debug_fname);
Packit 032894
	  tmp_debug_fname = NULL;
Packit 032894
	}
Packit 032894
      close (debug_fd);
Packit 032894
      debug_fd = -1;
Packit 032894
    }
Packit 032894
}
Packit 032894
Packit 032894
static int
Packit 032894
handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
Packit 032894
	   struct timespec tvp[2])
Packit 032894
{
Packit 032894
  size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
Packit 032894
  size_t fname_len = strlen (fname) + 1;
Packit 032894
  char new_prefix[prefix_len + 1 + fname_len];
Packit 032894
  char *cp = new_prefix;
Packit 032894
Packit 032894
  /* Create the full name of the file.  */
Packit 032894
  if (prefix != NULL)
Packit 032894
    {
Packit 032894
      cp = mempcpy (cp, prefix, prefix_len);
Packit 032894
      *cp++ = ':';
Packit 032894
    }
Packit 032894
  memcpy (cp, fname, fname_len);
Packit 032894
Packit 032894
Packit 032894
  /* Process all the files contained in the archive.  */
Packit 032894
  Elf *subelf;
Packit 032894
  Elf_Cmd cmd = ELF_C_RDWR;
Packit 032894
  int result = 0;
Packit 032894
  while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
Packit 032894
    {
Packit 032894
      /* The the header for this element.  */
Packit 032894
      Elf_Arhdr *arhdr = elf_getarhdr (subelf);
Packit 032894
Packit 032894
      if (elf_kind (subelf) == ELF_K_ELF)
Packit 032894
	result |= handle_elf (fd, subelf, new_prefix, arhdr->ar_name, 0, NULL);
Packit 032894
      else if (elf_kind (subelf) == ELF_K_AR)
Packit 032894
	result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name, NULL);
Packit 032894
Packit 032894
      /* Get next archive element.  */
Packit 032894
      cmd = elf_next (subelf);
Packit 032894
      if (unlikely (elf_end (subelf) != 0))
Packit 032894
	INTERNAL_ERROR (fname);
Packit 032894
    }
Packit 032894
Packit 032894
  if (tvp != NULL)
Packit 032894
    {
Packit 032894
      if (unlikely (futimens (fd, tvp) != 0))
Packit 032894
	{
Packit 032894
	  error (0, errno, gettext ("\
Packit 032894
cannot set access and modification date of '%s'"), fname);
Packit 032894
	  result = 1;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  if (unlikely (close (fd) != 0))
Packit 032894
    error (EXIT_FAILURE, errno, gettext ("while closing '%s'"), fname);
Packit 032894
Packit 032894
  return result;
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
#include "debugpred.h"