Blame src/strip.c

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