Blame src/unstrip.c

Packit Service 97d2fb
/* Combine stripped files with separate symbols and debug information.
Packit Service 97d2fb
   Copyright (C) 2007-2012, 2014, 2015 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
Packit Service 97d2fb
   Written by Roland McGrath <roland@redhat.com>, 2007.
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
/* TODO:
Packit Service 97d2fb
Packit Service 97d2fb
  * SHX_XINDEX
Packit Service 97d2fb
Packit Service 97d2fb
  * prelink vs .debug_* linked addresses
Packit Service 97d2fb
Packit Service 97d2fb
 */
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 <errno.h>
Packit Service 97d2fb
#include <fcntl.h>
Packit Service 97d2fb
#include <fnmatch.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 <inttypes.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
Packit Service 97d2fb
#include <gelf.h>
Packit Service 97d2fb
#include <libebl.h>
Packit Service 97d2fb
#include <libdwfl.h>
Packit Service 97d2fb
#include "system.h"
Packit Service 97d2fb
#include "libdwelf.h"
Packit Service 97d2fb
#include "libeu.h"
Packit Service 97d2fb
#include "printversion.h"
Packit Service 97d2fb
Packit Service 97d2fb
#ifndef _
Packit Service 97d2fb
# define _(str) gettext (str)
Packit Service 97d2fb
#endif
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
/* Definitions of arguments for argp functions.  */
Packit Service 97d2fb
static const struct argp_option options[] =
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Group 2 will follow group 1 from dwfl_standard_argp.  */
Packit Service 97d2fb
  { "match-file-names", 'f', NULL, 0,
Packit Service 97d2fb
    N_("Match MODULE against file names, not module names"), 2 },
Packit Service 97d2fb
  { "ignore-missing", 'i', NULL, 0, N_("Silently skip unfindable files"), 0 },
Packit Service 97d2fb
Packit Service 97d2fb
  { NULL, 0, NULL, 0, N_("Output options:"), 0 },
Packit Service 97d2fb
  { "output", 'o', "FILE", 0, N_("Place output into FILE"), 0 },
Packit Service 97d2fb
  { "output-directory", 'd', "DIRECTORY",
Packit Service 97d2fb
    0, N_("Create multiple output files under DIRECTORY"), 0 },
Packit Service 97d2fb
  { "module-names", 'm', NULL, 0, N_("Use module rather than file names"), 0 },
Packit Service 97d2fb
  { "all", 'a', NULL, 0,
Packit Service 97d2fb
    N_("Create output for modules that have no separate debug information"),
Packit Service 97d2fb
    0 },
Packit Service 97d2fb
  { "relocate", 'R', NULL, 0,
Packit Service 97d2fb
    N_("Apply relocations to section contents in ET_REL files"), 0 },
Packit Service 97d2fb
  { "list-only", 'n', NULL, 0,
Packit Service 97d2fb
    N_("Only list module and file names, build IDs"), 0 },
Packit Service 97d2fb
 { "force", 'F', NULL, 0,
Packit Service 97d2fb
    N_("Force combining files even if some ELF headers don't seem to match"),
Packit Service 97d2fb
   0 },
Packit Service 97d2fb
  { NULL, 0, NULL, 0, NULL, 0 }
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
struct arg_info
Packit Service 97d2fb
{
Packit Service 97d2fb
  const char *output_file;
Packit Service 97d2fb
  const char *output_dir;
Packit Service 97d2fb
  Dwfl *dwfl;
Packit Service 97d2fb
  char **args;
Packit Service 97d2fb
  bool list;
Packit Service 97d2fb
  bool all;
Packit Service 97d2fb
  bool ignore;
Packit Service 97d2fb
  bool modnames;
Packit Service 97d2fb
  bool match_files;
Packit Service 97d2fb
  bool relocate;
Packit Service 97d2fb
  bool force;
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
  struct arg_info *info = state->input;
Packit Service 97d2fb
Packit Service 97d2fb
  switch (key)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case ARGP_KEY_INIT:
Packit Service 97d2fb
      state->child_inputs[0] = &info->dwfl;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'o':
Packit Service 97d2fb
      if (info->output_file != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  argp_error (state, _("-o option specified twice"));
Packit Service 97d2fb
	  return EINVAL;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      info->output_file = arg;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'd':
Packit Service 97d2fb
      if (info->output_dir != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  argp_error (state, _("-d option specified twice"));
Packit Service 97d2fb
	  return EINVAL;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      info->output_dir = arg;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'm':
Packit Service 97d2fb
      info->modnames = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case 'f':
Packit Service 97d2fb
      info->match_files = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case 'a':
Packit Service 97d2fb
      info->all = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case 'i':
Packit Service 97d2fb
      info->ignore = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case 'n':
Packit Service 97d2fb
      info->list = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case 'R':
Packit Service 97d2fb
      info->relocate = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case 'F':
Packit Service 97d2fb
      info->force = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case ARGP_KEY_ARGS:
Packit Service 97d2fb
    case ARGP_KEY_NO_ARGS:
Packit Service 97d2fb
      /* We "consume" all the arguments here.  */
Packit Service 97d2fb
      info->args = &state->argv[state->next];
Packit Service 97d2fb
Packit Service 97d2fb
      if (info->output_file != NULL && info->output_dir != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  argp_error (state, _("only one of -o or -d allowed"));
Packit Service 97d2fb
	  return EINVAL;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (info->list && (info->dwfl == NULL
Packit Service 97d2fb
			 || info->output_dir != NULL
Packit Service 97d2fb
			 || info->output_file != NULL))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  argp_error (state,
Packit Service 97d2fb
		      _("-n cannot be used with explicit files or -o or -d"));
Packit Service 97d2fb
	  return EINVAL;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (info->output_dir != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  struct stat st;
Packit Service 97d2fb
	  error_t fail = 0;
Packit Service 97d2fb
	  if (stat (info->output_dir, &st) < 0)
Packit Service 97d2fb
	    fail = errno;
Packit Service 97d2fb
	  else if (!S_ISDIR (st.st_mode))
Packit Service 97d2fb
	    fail = ENOTDIR;
Packit Service 97d2fb
	  if (fail)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      argp_failure (state, EXIT_FAILURE, fail,
Packit Service 97d2fb
			    _("output directory '%s'"), info->output_dir);
Packit Service 97d2fb
	      return fail;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (info->dwfl == NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (state->next + 2 != state->argc)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      argp_error (state, _("exactly two file arguments are required"));
Packit Service 97d2fb
	      return EINVAL;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  if (info->ignore || info->all || info->modnames || info->relocate)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      argp_error (state, _("\
Packit Service 97d2fb
-m, -a, -R, and -i options not allowed with explicit files"));
Packit Service 97d2fb
	      return EINVAL;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Bail out immediately to prevent dwfl_standard_argp's parser
Packit Service 97d2fb
	     from defaulting to "-e a.out".  */
Packit Service 97d2fb
	  return ENOSYS;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else if (info->output_file == NULL && info->output_dir == NULL
Packit Service 97d2fb
	       && !info->list)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  argp_error (state,
Packit Service 97d2fb
		      _("-o or -d is required when using implicit files"));
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
#define ELF_CHECK(call, msg)						      \
Packit Service 97d2fb
  do									      \
Packit Service 97d2fb
    {									      \
Packit Service 97d2fb
      if (unlikely (!(call)))						      \
Packit Service 97d2fb
	error (EXIT_FAILURE, 0, msg, elf_errmsg (-1));			      \
Packit Service 97d2fb
    } while (0)
Packit Service 97d2fb
Packit Service 97d2fb
/* Copy INELF to newly-created OUTELF, exit via error for any problems.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
copy_elf (Elf *outelf, Elf *inelf)
Packit Service 97d2fb
{
Packit Service 97d2fb
  ELF_CHECK (gelf_newehdr (outelf, gelf_getclass (inelf)),
Packit Service 97d2fb
	     _("cannot create ELF header: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
  size_t shstrndx;
Packit Service 97d2fb
  ELF_CHECK (elf_getshdrstrndx (inelf, &shstrndx) == 0,
Packit Service 97d2fb
	     _("cannot get shdrstrndx:%s"));
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Ehdr ehdr_mem;
Packit Service 97d2fb
  GElf_Ehdr *ehdr = gelf_getehdr (inelf, &ehdr_mem);
Packit Service 97d2fb
  ELF_CHECK (ehdr != NULL, _("cannot get ELF header: %s"));
Packit Service 97d2fb
  if (shstrndx < SHN_LORESERVE)
Packit Service 97d2fb
    ehdr->e_shstrndx = shstrndx;
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      ehdr->e_shstrndx = SHN_XINDEX;
Packit Service 97d2fb
      Elf_Scn *scn0 = elf_getscn (outelf, 0);
Packit Service 97d2fb
      GElf_Shdr shdr0_mem;
Packit Service 97d2fb
      GElf_Shdr *shdr0 = gelf_getshdr (scn0, &shdr0_mem);
Packit Service 97d2fb
      ELF_CHECK (shdr0 != NULL,
Packit Service 97d2fb
		 _("cannot get new zero section: %s"));
Packit Service 97d2fb
      shdr0->sh_link = shstrndx;
Packit Service 97d2fb
      ELF_CHECK (gelf_update_shdr (scn0, shdr0),
Packit Service 97d2fb
		 _("cannot update new zero section: %s"));
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  ELF_CHECK (gelf_update_ehdr (outelf, ehdr),
Packit Service 97d2fb
	     _("cannot copy ELF header: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
  size_t phnum;
Packit Service 97d2fb
  ELF_CHECK (elf_getphdrnum (inelf, &phnum) == 0,
Packit Service 97d2fb
	     _("cannot get number of program headers: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
  if (phnum > 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      ELF_CHECK (gelf_newphdr (outelf, phnum),
Packit Service 97d2fb
		 _("cannot create program headers: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
      GElf_Phdr phdr_mem;
Packit Service 97d2fb
      for (size_t i = 0; i < phnum; ++i)
Packit Service 97d2fb
	ELF_CHECK (gelf_update_phdr (outelf, i,
Packit Service 97d2fb
				     gelf_getphdr (inelf, i, &phdr_mem)),
Packit Service 97d2fb
		   _("cannot copy program header: %s"));
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  Elf_Scn *scn = NULL;
Packit Service 97d2fb
  while ((scn = elf_nextscn (inelf, scn)) != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Elf_Scn *newscn = elf_newscn (outelf);
Packit Service 97d2fb
Packit Service 97d2fb
      GElf_Shdr shdr_mem;
Packit Service 97d2fb
      ELF_CHECK (gelf_update_shdr (newscn, gelf_getshdr (scn, &shdr_mem)),
Packit Service 97d2fb
		 _("cannot copy section header: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
      Elf_Data *data = elf_getdata (scn, NULL);
Packit Service 97d2fb
      ELF_CHECK (data != NULL, _("cannot get section data: %s"));
Packit Service 97d2fb
      Elf_Data *newdata = elf_newdata (newscn);
Packit Service 97d2fb
      ELF_CHECK (newdata != NULL, _("cannot copy section data: %s"));
Packit Service 97d2fb
      *newdata = *data;
Packit Service 97d2fb
      elf_flagdata (newdata, ELF_C_SET, ELF_F_DIRTY);
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Create directories containing PATH.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
make_directories (const char *path)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const char *lastslash = strrchr (path, '/');
Packit Service 97d2fb
  if (lastslash == NULL)
Packit Service 97d2fb
    return;
Packit Service 97d2fb
Packit Service 97d2fb
  while (lastslash > path && lastslash[-1] == '/')
Packit Service 97d2fb
    --lastslash;
Packit Service 97d2fb
  if (lastslash == path)
Packit Service 97d2fb
    return;
Packit Service 97d2fb
Packit Service 97d2fb
  char *dir = strndup (path, lastslash - path);
Packit Service 97d2fb
  if (dir == NULL)
Packit Service 97d2fb
    error(EXIT_FAILURE, errno, _("memory exhausted"));
Packit Service 97d2fb
Packit Service 97d2fb
  while (mkdir (dir, 0777) < 0 && errno != EEXIST)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (errno == ENOENT)
Packit Service 97d2fb
        make_directories (dir);
Packit Service 97d2fb
      else
Packit Service 97d2fb
        error (EXIT_FAILURE, errno, _("cannot create directory '%s'"), dir);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  free (dir);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Keep track of new section data we are creating, so we can free it
Packit Service 97d2fb
   when done.  */
Packit Service 97d2fb
struct data_list
Packit Service 97d2fb
{
Packit Service 97d2fb
  void *data;
Packit Service 97d2fb
  struct data_list *next;
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
struct data_list *new_data_list;
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
record_new_data (void *data)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct data_list *next = new_data_list;
Packit Service 97d2fb
  new_data_list = xmalloc (sizeof (struct data_list));
Packit Service 97d2fb
  new_data_list->data = data;
Packit Service 97d2fb
  new_data_list->next = next;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
free_new_data (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct data_list *list = new_data_list;
Packit Service 97d2fb
  while (list != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      struct data_list *next = list->next;
Packit Service 97d2fb
      free (list->data);
Packit Service 97d2fb
      free (list);
Packit Service 97d2fb
      list = next;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  new_data_list = NULL;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* The binutils linker leaves gratuitous section symbols in .symtab
Packit Service 97d2fb
   that strip has to remove.  Older linkers likewise include a
Packit Service 97d2fb
   symbol for every section, even unallocated ones, in .dynsym.
Packit Service 97d2fb
   Because of this, the related sections can shrink in the stripped
Packit Service 97d2fb
   file from their original size.  Older versions of strip do not
Packit Service 97d2fb
   adjust the sh_size field in the debuginfo file's SHT_NOBITS
Packit Service 97d2fb
   version of the section header, so it can appear larger.  */
Packit Service 97d2fb
static bool
Packit Service 97d2fb
section_can_shrink (const GElf_Shdr *shdr)
Packit Service 97d2fb
{
Packit Service 97d2fb
  switch (shdr->sh_type)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case SHT_SYMTAB:
Packit Service 97d2fb
    case SHT_DYNSYM:
Packit Service 97d2fb
    case SHT_HASH:
Packit Service 97d2fb
    case SHT_GNU_versym:
Packit Service 97d2fb
      return true;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return false;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* See if this symbol table has a leading section symbol for every single
Packit Service 97d2fb
   section, in order.  The binutils linker produces this.  While we're here,
Packit Service 97d2fb
   update each section symbol's st_value.  */
Packit Service 97d2fb
static size_t
Packit Service 97d2fb
symtab_count_leading_section_symbols (Elf *elf, Elf_Scn *scn, size_t shnum,
Packit Service 97d2fb
				      Elf_Data *newsymdata)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Elf_Data *data = elf_getdata (scn, NULL);
Packit Service 97d2fb
  Elf_Data *shndxdata = NULL;	/* XXX */
Packit Service 97d2fb
Packit Service 97d2fb
  for (size_t i = 1; i < shnum; ++i)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Sym sym_mem;
Packit Service 97d2fb
      GElf_Word shndx = SHN_UNDEF;
Packit Service 97d2fb
      GElf_Sym *sym = gelf_getsymshndx (data, shndxdata, i, &sym_mem, &shndx);
Packit Service 97d2fb
      ELF_CHECK (sym != NULL, _("cannot get symbol table entry: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
      GElf_Shdr shdr_mem;
Packit Service 97d2fb
      GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, i), &shdr_mem);
Packit Service 97d2fb
      ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
      if (sym->st_shndx != SHN_XINDEX)
Packit Service 97d2fb
	shndx = sym->st_shndx;
Packit Service 97d2fb
Packit Service 97d2fb
      if (shndx != i || GELF_ST_TYPE (sym->st_info) != STT_SECTION)
Packit Service 97d2fb
	return i;
Packit Service 97d2fb
Packit Service 97d2fb
      sym->st_value = shdr->sh_addr;
Packit Service 97d2fb
      if (sym->st_shndx != SHN_XINDEX)
Packit Service 97d2fb
	shndx = SHN_UNDEF;
Packit Service 97d2fb
      ELF_CHECK (gelf_update_symshndx (newsymdata, shndxdata, i, sym, shndx),
Packit Service 97d2fb
		 _("cannot update symbol table: %s"));
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return shnum;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
update_shdr (Elf_Scn *outscn, GElf_Shdr *newshdr)
Packit Service 97d2fb
{
Packit Service 97d2fb
  ELF_CHECK (gelf_update_shdr (outscn, newshdr),
Packit Service 97d2fb
	     _("cannot update section header: %s"));
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* We expanded the output section, so update its header.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
update_sh_size (Elf_Scn *outscn, const Elf_Data *data)
Packit Service 97d2fb
{
Packit Service 97d2fb
  GElf_Shdr shdr_mem;
Packit Service 97d2fb
  GElf_Shdr *newshdr = gelf_getshdr (outscn, &shdr_mem);
Packit Service 97d2fb
  ELF_CHECK (newshdr != NULL, _("cannot get section header: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
  newshdr->sh_size = data->d_size;
Packit Service 97d2fb
Packit Service 97d2fb
  update_shdr (outscn, newshdr);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Update relocation sections using the symbol table.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
Packit Service 97d2fb
	       size_t map[], size_t map_size, const GElf_Shdr *symshdr)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Elf_Data *data = elf_getdata (outscn, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
  inline void adjust_reloc (GElf_Xword *info)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      size_t ndx = GELF_R_SYM (*info);
Packit Service 97d2fb
      if (ndx != STN_UNDEF)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (ndx > map_size)
Packit Service 97d2fb
	    error (EXIT_FAILURE, 0, "bad symbol ndx section");
Packit Service 97d2fb
	  *info = GELF_R_INFO (map[ndx - 1], GELF_R_TYPE (*info));
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  switch (shdr->sh_type)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case SHT_REL:
Packit Service 97d2fb
      if (shdr->sh_entsize == 0)
Packit Service 97d2fb
	error (EXIT_FAILURE, 0, "REL section cannot have zero sh_entsize");
Packit Service 97d2fb
Packit Service 97d2fb
      for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  GElf_Rel rel_mem;
Packit Service 97d2fb
	  GElf_Rel *rel = gelf_getrel (data, i, &rel_mem);
Packit Service 97d2fb
	  adjust_reloc (&rel->r_info);
Packit Service 97d2fb
	  ELF_CHECK (gelf_update_rel (data, i, rel),
Packit Service 97d2fb
		     _("cannot update relocation: %s"));
Packit Service 97d2fb
	}
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case SHT_RELA:
Packit Service 97d2fb
      if (shdr->sh_entsize == 0)
Packit Service 97d2fb
	error (EXIT_FAILURE, 0, "RELA section cannot have zero sh_entsize");
Packit Service 97d2fb
Packit Service 97d2fb
      for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  GElf_Rela rela_mem;
Packit Service 97d2fb
	  GElf_Rela *rela = gelf_getrela (data, i, &rela_mem);
Packit Service 97d2fb
	  adjust_reloc (&rela->r_info);
Packit Service 97d2fb
	  ELF_CHECK (gelf_update_rela (data, i, rela),
Packit Service 97d2fb
		     _("cannot update relocation: %s"));
Packit Service 97d2fb
	}
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case SHT_GROUP:
Packit Service 97d2fb
      {
Packit Service 97d2fb
	GElf_Shdr shdr_mem;
Packit Service 97d2fb
	GElf_Shdr *newshdr = gelf_getshdr (outscn, &shdr_mem);
Packit Service 97d2fb
	ELF_CHECK (newshdr != NULL, _("cannot get section header: %s"));
Packit Service 97d2fb
	if (newshdr->sh_info != STN_UNDEF)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    newshdr->sh_info = map[newshdr->sh_info - 1];
Packit Service 97d2fb
	    update_shdr (outscn, newshdr);
Packit Service 97d2fb
	  }
Packit Service 97d2fb
	break;
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
    case SHT_HASH:
Packit Service 97d2fb
      /* We must expand the table and rejigger its contents.  */
Packit Service 97d2fb
      {
Packit Service 97d2fb
	if (shdr->sh_entsize == 0)
Packit Service 97d2fb
	  error (EXIT_FAILURE, 0, "HASH section cannot have zero sh_entsize");
Packit Service 97d2fb
	if (symshdr->sh_entsize == 0)
Packit Service 97d2fb
	  error (EXIT_FAILURE, 0, "Symbol table cannot have zero sh_entsize");
Packit Service 97d2fb
	const size_t nsym = symshdr->sh_size / symshdr->sh_entsize;
Packit Service 97d2fb
	const size_t onent = shdr->sh_size / shdr->sh_entsize;
Packit Service 97d2fb
	if (data->d_size != shdr->sh_size)
Packit Service 97d2fb
	  error (EXIT_FAILURE, 0, "HASH section has inconsistent size");
Packit Service 97d2fb
Packit Service 97d2fb
#define CONVERT_HASH(Hash_Word)						      \
Packit Service 97d2fb
	{								      \
Packit Service 97d2fb
	  const Hash_Word *const old_hash = data->d_buf;		      \
Packit Service 97d2fb
	  const size_t nbucket = old_hash[0];				      \
Packit Service 97d2fb
	  const size_t nchain = old_hash[1];				      \
Packit Service 97d2fb
	  const Hash_Word *const old_bucket = &old_hash[2];		      \
Packit Service 97d2fb
	  const Hash_Word *const old_chain = &old_bucket[nbucket];	      \
Packit Service 97d2fb
	  if (onent != 2 + nbucket + nchain)				      \
Packit Service 97d2fb
	    error (EXIT_FAILURE, 0, "HASH section has inconsistent entsize"); \
Packit Service 97d2fb
									      \
Packit Service 97d2fb
	  const size_t nent = 2 + nbucket + nsym;			      \
Packit Service 97d2fb
	  Hash_Word *const new_hash = xcalloc (nent, sizeof new_hash[0]);     \
Packit Service 97d2fb
	  Hash_Word *const new_bucket = &new_hash[2];			      \
Packit Service 97d2fb
	  Hash_Word *const new_chain = &new_bucket[nbucket];		      \
Packit Service 97d2fb
									      \
Packit Service 97d2fb
	  new_hash[0] = nbucket;					      \
Packit Service 97d2fb
	  new_hash[1] = nsym;						      \
Packit Service 97d2fb
	  for (size_t i = 0; i < nbucket; ++i)				      \
Packit Service 97d2fb
	    if (old_bucket[i] != STN_UNDEF)				      \
Packit Service 97d2fb
	      new_bucket[i] = map[old_bucket[i] - 1];			      \
Packit Service 97d2fb
									      \
Packit Service 97d2fb
	  for (size_t i = 1; i < nchain; ++i)				      \
Packit Service 97d2fb
	    if (old_chain[i] != STN_UNDEF)				      \
Packit Service 97d2fb
	      new_chain[map[i - 1]] = map[old_chain[i] - 1];		      \
Packit Service 97d2fb
									      \
Packit Service 97d2fb
	  record_new_data (new_hash);					\
Packit Service 97d2fb
	  data->d_buf = new_hash;					      \
Packit Service 97d2fb
	  data->d_size = nent * sizeof new_hash[0];			      \
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
	switch (shdr->sh_entsize)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	  case 4:
Packit Service 97d2fb
	    CONVERT_HASH (Elf32_Word);
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
	  case 8:
Packit Service 97d2fb
	    CONVERT_HASH (Elf64_Xword);
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
	  default:
Packit Service 97d2fb
	    abort ();
Packit Service 97d2fb
	  }
Packit Service 97d2fb
Packit Service 97d2fb
	elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY);
Packit Service 97d2fb
	update_sh_size (outscn, data);
Packit Service 97d2fb
Packit Service 97d2fb
#undef	CONVERT_HASH
Packit Service 97d2fb
      }
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case SHT_GNU_versym:
Packit Service 97d2fb
      /* We must expand the table and move its elements around.  */
Packit Service 97d2fb
      {
Packit Service 97d2fb
	if (shdr->sh_entsize == 0)
Packit Service 97d2fb
	  error (EXIT_FAILURE, 0,
Packit Service 97d2fb
		 "GNU_versym section cannot have zero sh_entsize");
Packit Service 97d2fb
	if (symshdr->sh_entsize == 0)
Packit Service 97d2fb
	  error (EXIT_FAILURE, 0, "Symbol table cannot have zero sh_entsize");
Packit Service 97d2fb
	const size_t nent = symshdr->sh_size / symshdr->sh_entsize;
Packit Service 97d2fb
	const size_t onent = shdr->sh_size / shdr->sh_entsize;
Packit Service 97d2fb
	assert (nent >= onent);
Packit Service 97d2fb
Packit Service 97d2fb
	/* We don't bother using gelf_update_versym because there is
Packit Service 97d2fb
	   really no conversion to be done.  */
Packit Service 97d2fb
	assert (sizeof (Elf32_Versym) == sizeof (GElf_Versym));
Packit Service 97d2fb
	assert (sizeof (Elf64_Versym) == sizeof (GElf_Versym));
Packit Service 97d2fb
	GElf_Versym *versym = xcalloc (nent, sizeof versym[0]);
Packit Service 97d2fb
Packit Service 97d2fb
	for (size_t i = 1; i < onent; ++i)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    GElf_Versym *v = gelf_getversym (data, i, &versym[map[i - 1]]);
Packit Service 97d2fb
	    ELF_CHECK (v != NULL, _("cannot get symbol version: %s"));
Packit Service 97d2fb
	  }
Packit Service 97d2fb
Packit Service 97d2fb
	record_new_data (versym);
Packit Service 97d2fb
	data->d_buf = versym;
Packit Service 97d2fb
	data->d_size = nent * sizeof versym[0];
Packit Service 97d2fb
	elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY);
Packit Service 97d2fb
	update_sh_size (outscn, data);
Packit Service 97d2fb
      }
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      error (EXIT_FAILURE, 0,
Packit Service 97d2fb
	     _("unexpected section type in [%zu] with sh_link to symtab"),
Packit Service 97d2fb
	     elf_ndxscn (inscn));
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Adjust all the relocation sections in the file.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
adjust_all_relocs (Elf *elf, Elf_Scn *symtab, const GElf_Shdr *symshdr,
Packit Service 97d2fb
		   size_t map[], size_t map_size)
Packit Service 97d2fb
{
Packit Service 97d2fb
  size_t new_sh_link = elf_ndxscn (symtab);
Packit Service 97d2fb
  Elf_Scn *scn = NULL;
Packit Service 97d2fb
  while ((scn = elf_nextscn (elf, scn)) != NULL)
Packit Service 97d2fb
    if (scn != symtab)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	GElf_Shdr shdr_mem;
Packit Service 97d2fb
	GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Packit Service 97d2fb
	ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
Packit Service 97d2fb
	/* Don't redo SHT_GROUP, groups are in both the stripped and debug,
Packit Service 97d2fb
	   it will already have been done by adjust_relocs for the
Packit Service 97d2fb
	   stripped_symtab.  */
Packit Service 97d2fb
	if (shdr->sh_type != SHT_NOBITS && shdr->sh_type != SHT_GROUP
Packit Service 97d2fb
	    && shdr->sh_link == new_sh_link)
Packit Service 97d2fb
	  adjust_relocs (scn, scn, shdr, map, map_size, symshdr);
Packit Service 97d2fb
      }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* The original file probably had section symbols for all of its
Packit Service 97d2fb
   sections, even the unallocated ones.  To match it as closely as
Packit Service 97d2fb
   possible, add in section symbols for the added sections.  */
Packit Service 97d2fb
static Elf_Data *
Packit Service 97d2fb
add_new_section_symbols (Elf_Scn *old_symscn, size_t old_shnum,
Packit Service 97d2fb
			 Elf *elf, bool rel, Elf_Scn *symscn, size_t shnum)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const size_t added = shnum - old_shnum;
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Shdr shdr_mem;
Packit Service 97d2fb
  GElf_Shdr *shdr = gelf_getshdr (symscn, &shdr_mem);
Packit Service 97d2fb
  ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
Packit Service 97d2fb
  if (shdr->sh_entsize == 0)
Packit Service 97d2fb
    error (EXIT_FAILURE, 0, "Symbol table section cannot have zero sh_entsize");
Packit Service 97d2fb
Packit Service 97d2fb
  const size_t nsym = shdr->sh_size / shdr->sh_entsize;
Packit Service 97d2fb
  size_t symndx_map[nsym - 1];
Packit Service 97d2fb
Packit Service 97d2fb
  shdr->sh_info += added;
Packit Service 97d2fb
  shdr->sh_size += added * shdr->sh_entsize;
Packit Service 97d2fb
  update_shdr (symscn, shdr);
Packit Service 97d2fb
Packit Service 97d2fb
  Elf_Data *symdata = elf_getdata (symscn, NULL);
Packit Service 97d2fb
  Elf_Data *shndxdata = NULL;	/* XXX */
Packit Service 97d2fb
Packit Service 97d2fb
  symdata->d_size = shdr->sh_size;
Packit Service 97d2fb
  symdata->d_buf = xmalloc (symdata->d_size);
Packit Service 97d2fb
  record_new_data (symdata->d_buf);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Copy the existing section symbols.  */
Packit Service 97d2fb
  Elf_Data *old_symdata = elf_getdata (old_symscn, NULL);
Packit Service 97d2fb
  for (size_t i = 0; i < old_shnum; ++i)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Sym sym_mem;
Packit Service 97d2fb
      GElf_Word shndx = SHN_UNDEF;
Packit Service 97d2fb
      GElf_Sym *sym = gelf_getsymshndx (old_symdata, shndxdata,
Packit Service 97d2fb
					i, &sym_mem, &shndx);
Packit Service 97d2fb
      ELF_CHECK (sym != NULL, _("cannot get symbol table entry: %s"));
Packit Service 97d2fb
      ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, i,
Packit Service 97d2fb
				       sym, shndx),
Packit Service 97d2fb
		 _("cannot update symbol table: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
      if (i > 0)
Packit Service 97d2fb
	symndx_map[i - 1] = i;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Add in the new section symbols.  */
Packit Service 97d2fb
  for (size_t i = old_shnum; i < shnum; ++i)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Shdr i_shdr_mem;
Packit Service 97d2fb
      GElf_Shdr *i_shdr = gelf_getshdr (elf_getscn (elf, i), &i_shdr_mem);
Packit Service 97d2fb
      ELF_CHECK (i_shdr != NULL, _("cannot get section header: %s"));
Packit Service 97d2fb
      GElf_Sym sym =
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  .st_value = rel ? 0 : i_shdr->sh_addr,
Packit Service 97d2fb
	  .st_info = GELF_ST_INFO (STB_LOCAL, STT_SECTION),
Packit Service 97d2fb
	  .st_shndx = i < SHN_LORESERVE ? i : SHN_XINDEX
Packit Service 97d2fb
	};
Packit Service 97d2fb
      GElf_Word shndx = i < SHN_LORESERVE ? SHN_UNDEF : i;
Packit Service 97d2fb
      ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, i,
Packit Service 97d2fb
				       &sym, shndx),
Packit Service 97d2fb
		 _("cannot update symbol table: %s"));
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Now copy the rest of the existing symbols.  */
Packit Service 97d2fb
  for (size_t i = old_shnum; i < nsym; ++i)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Sym sym_mem;
Packit Service 97d2fb
      GElf_Word shndx = SHN_UNDEF;
Packit Service 97d2fb
      GElf_Sym *sym = gelf_getsymshndx (old_symdata, shndxdata,
Packit Service 97d2fb
					i, &sym_mem, &shndx);
Packit Service 97d2fb
      ELF_CHECK (sym != NULL, _("cannot get symbol table entry: %s"));
Packit Service 97d2fb
      ELF_CHECK (gelf_update_symshndx (symdata, shndxdata,
Packit Service 97d2fb
				       i + added, sym, shndx),
Packit Service 97d2fb
		 _("cannot update symbol table: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
      symndx_map[i - 1] = i + added;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Adjust any relocations referring to the old symbol table.  */
Packit Service 97d2fb
  adjust_all_relocs (elf, symscn, shdr, symndx_map, nsym - 1);
Packit Service 97d2fb
Packit Service 97d2fb
  return symdata;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* This has the side effect of updating STT_SECTION symbols' values,
Packit Service 97d2fb
   in case of prelink adjustments.  */
Packit Service 97d2fb
static Elf_Data *
Packit Service 97d2fb
check_symtab_section_symbols (Elf *elf, bool rel, Elf_Scn *scn,
Packit Service 97d2fb
			      size_t shnum, size_t shstrndx,
Packit Service 97d2fb
			      Elf_Scn *oscn, size_t oshnum, size_t oshstrndx,
Packit Service 97d2fb
			      size_t debuglink)
Packit Service 97d2fb
{
Packit Service 97d2fb
  size_t n = symtab_count_leading_section_symbols (elf, oscn, oshnum,
Packit Service 97d2fb
						   elf_getdata (scn, NULL));
Packit Service 97d2fb
Packit Service 97d2fb
  if (n == oshnum)
Packit Service 97d2fb
    return add_new_section_symbols (oscn, n, elf, rel, scn, shnum);
Packit Service 97d2fb
Packit Service 97d2fb
  if (n == oshstrndx || (n == debuglink && n == oshstrndx - 1))
Packit Service 97d2fb
    return add_new_section_symbols (oscn, n, elf, rel, scn, shstrndx);
Packit Service 97d2fb
Packit Service 97d2fb
  return NULL;
Packit Service 97d2fb
}
Packit Service 97d2fb

Packit Service 97d2fb
struct section
Packit Service 97d2fb
{
Packit Service 97d2fb
  Elf_Scn *scn;
Packit Service 97d2fb
  const char *name;
Packit Service 97d2fb
  const char *sig;
Packit Service 97d2fb
  Elf_Scn *outscn;
Packit Service 97d2fb
  Dwelf_Strent *strent;
Packit Service 97d2fb
  GElf_Shdr shdr;
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
compare_alloc_sections (const struct section *s1, const struct section *s2,
Packit Service 97d2fb
			bool rel)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (!rel)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Sort by address.  */
Packit Service 97d2fb
      if (s1->shdr.sh_addr < s2->shdr.sh_addr)
Packit Service 97d2fb
	return -1;
Packit Service 97d2fb
      if (s1->shdr.sh_addr > s2->shdr.sh_addr)
Packit Service 97d2fb
	return 1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* At the same address, preserve original section order.  */
Packit Service 97d2fb
  return (ssize_t) elf_ndxscn (s1->scn) - (ssize_t) elf_ndxscn (s2->scn);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
compare_unalloc_sections (const GElf_Shdr *shdr1, const GElf_Shdr *shdr2,
Packit Service 97d2fb
			  const char *name1, const char *name2,
Packit Service 97d2fb
			  const char *sig1, const char *sig2)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Sort by sh_flags as an arbitrary ordering.  */
Packit Service 97d2fb
  if (shdr1->sh_flags < shdr2->sh_flags)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
  if (shdr1->sh_flags > shdr2->sh_flags)
Packit Service 97d2fb
    return 1;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Sizes should be the same.  */
Packit Service 97d2fb
  if (shdr1->sh_size < shdr2->sh_size)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
  if (shdr1->sh_size > shdr2->sh_size)
Packit Service 97d2fb
    return 1;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Are they both SHT_GROUP sections? Then compare signatures.  */
Packit Service 97d2fb
  if (sig1 != NULL && sig2 != NULL)
Packit Service 97d2fb
    return strcmp (sig1, sig2);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Sort by name as last resort.  */
Packit Service 97d2fb
  return strcmp (name1, name2);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
compare_sections (const void *a, const void *b, bool rel)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const struct section *s1 = a;
Packit Service 97d2fb
  const struct section *s2 = b;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Sort all non-allocated sections last.  */
Packit Service 97d2fb
  if ((s1->shdr.sh_flags ^ s2->shdr.sh_flags) & SHF_ALLOC)
Packit Service 97d2fb
    return (s1->shdr.sh_flags & SHF_ALLOC) ? -1 : 1;
Packit Service 97d2fb
Packit Service 97d2fb
  return ((s1->shdr.sh_flags & SHF_ALLOC)
Packit Service 97d2fb
	  ? compare_alloc_sections (s1, s2, rel)
Packit Service 97d2fb
	  : compare_unalloc_sections (&s1->shdr, &s2->shdr,
Packit Service 97d2fb
				      s1->name, s2->name,
Packit Service 97d2fb
				      s1->sig, s2->sig));
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
compare_sections_rel (const void *a, const void *b)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return compare_sections (a, b, true);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
compare_sections_nonrel (const void *a, const void *b)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return compare_sections (a, b, false);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
struct symbol
Packit Service 97d2fb
{
Packit Service 97d2fb
  size_t *map;
Packit Service 97d2fb
Packit Service 97d2fb
  union
Packit Service 97d2fb
  {
Packit Service 97d2fb
    const char *name;
Packit Service 97d2fb
    Dwelf_Strent *strent;
Packit Service 97d2fb
  };
Packit Service 97d2fb
  union
Packit Service 97d2fb
  {
Packit Service 97d2fb
    struct
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Addr value;
Packit Service 97d2fb
      GElf_Xword size;
Packit Service 97d2fb
      GElf_Word shndx;
Packit Service 97d2fb
      union
Packit Service 97d2fb
      {
Packit Service 97d2fb
	struct
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  uint8_t info;
Packit Service 97d2fb
	  uint8_t other;
Packit Service 97d2fb
	} info;
Packit Service 97d2fb
	int16_t compare;
Packit Service 97d2fb
      };
Packit Service 97d2fb
    };
Packit Service 97d2fb
Packit Service 97d2fb
    /* For a symbol discarded after first sort, this matches its better's
Packit Service 97d2fb
       map pointer.  */
Packit Service 97d2fb
    size_t *duplicate;
Packit Service 97d2fb
  };
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
/* Collect input symbols into our internal form.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
collect_symbols (Elf *outelf, bool rel, Elf_Scn *symscn, Elf_Scn *strscn,
Packit Service 97d2fb
		 const size_t nent, const GElf_Addr bias,
Packit Service 97d2fb
		 const size_t scnmap[], struct symbol *table, size_t *map,
Packit Service 97d2fb
		 struct section *split_bss)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Elf_Data *symdata = elf_getdata (symscn, NULL);
Packit Service 97d2fb
  ELF_CHECK (symdata != NULL, _("cannot get symbol section data: %s"));
Packit Service 97d2fb
  Elf_Data *strdata = elf_getdata (strscn, NULL);
Packit Service 97d2fb
  ELF_CHECK (strdata != NULL, _("cannot get string section data: %s"));
Packit Service 97d2fb
  Elf_Data *shndxdata = NULL;	/* XXX */
Packit Service 97d2fb
Packit Service 97d2fb
  for (size_t i = 1; i < nent; ++i)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Sym sym_mem;
Packit Service 97d2fb
      GElf_Word shndx = SHN_UNDEF;
Packit Service 97d2fb
      GElf_Sym *sym = gelf_getsymshndx (symdata, shndxdata, i,
Packit Service 97d2fb
					&sym_mem, &shndx);
Packit Service 97d2fb
      ELF_CHECK (sym != NULL, _("cannot get symbol table entry: %s"));
Packit Service 97d2fb
      if (sym->st_shndx != SHN_XINDEX)
Packit Service 97d2fb
	shndx = sym->st_shndx;
Packit Service 97d2fb
Packit Service 97d2fb
      if (sym->st_name >= strdata->d_size
Packit Service 97d2fb
	  || memrchr (strdata->d_buf + sym->st_name, '\0',
Packit Service 97d2fb
		      strdata->d_size - sym->st_name) == NULL)
Packit Service 97d2fb
	error (EXIT_FAILURE, 0,
Packit Service 97d2fb
	       _("invalid string offset in symbol [%zu]"), i);
Packit Service 97d2fb
Packit Service 97d2fb
      struct symbol *s = &table[i - 1];
Packit Service 97d2fb
      s->map = &map[i - 1];
Packit Service 97d2fb
      s->name = strdata->d_buf + sym->st_name;
Packit Service 97d2fb
      s->value = sym->st_value + bias;
Packit Service 97d2fb
      s->size = sym->st_size;
Packit Service 97d2fb
      s->shndx = shndx;
Packit Service 97d2fb
      s->info.info = sym->st_info;
Packit Service 97d2fb
      s->info.other = sym->st_other;
Packit Service 97d2fb
Packit Service 97d2fb
      if (scnmap != NULL && shndx != SHN_UNDEF && shndx < SHN_LORESERVE)
Packit Service 97d2fb
	s->shndx = scnmap[shndx - 1];
Packit Service 97d2fb
Packit Service 97d2fb
      if (GELF_ST_TYPE (s->info.info) == STT_SECTION && !rel)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Update the value to match the output section.  */
Packit Service 97d2fb
	  GElf_Shdr shdr_mem;
Packit Service 97d2fb
	  GElf_Shdr *shdr = gelf_getshdr (elf_getscn (outelf, s->shndx),
Packit Service 97d2fb
					  &shdr_mem);
Packit Service 97d2fb
	  ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
Packit Service 97d2fb
	  s->value = shdr->sh_addr;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else if (split_bss != NULL
Packit Service 97d2fb
	       && s->value < split_bss->shdr.sh_addr
Packit Service 97d2fb
	       && s->value >= split_bss[-1].shdr.sh_addr
Packit Service 97d2fb
	       && shndx == elf_ndxscn (split_bss->outscn))
Packit Service 97d2fb
	/* This symbol was in .bss and was split into .dynbss.  */
Packit Service 97d2fb
	s->shndx = elf_ndxscn (split_bss[-1].outscn);
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
#define CMP(value)							      \
Packit Service 97d2fb
  if (s1->value < s2->value)						      \
Packit Service 97d2fb
    return -1;								      \
Packit Service 97d2fb
  if (s1->value > s2->value)						      \
Packit Service 97d2fb
    return 1
Packit Service 97d2fb
Packit Service 97d2fb
/* Compare symbols with a consistent ordering,
Packit Service 97d2fb
   but one only meaningful for equality.  */
Packit Service 97d2fb
static int
Packit Service 97d2fb
compare_symbols (const void *a, const void *b)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const struct symbol *s1 = a;
Packit Service 97d2fb
  const struct symbol *s2 = b;
Packit Service 97d2fb
Packit Service 97d2fb
  CMP (value);
Packit Service 97d2fb
  CMP (size);
Packit Service 97d2fb
  CMP (shndx);
Packit Service 97d2fb
Packit Service 97d2fb
  return (s1->compare - s2->compare) ?: strcmp (s1->name, s2->name);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Compare symbols for output order after slots have been assigned.  */
Packit Service 97d2fb
static int
Packit Service 97d2fb
compare_symbols_output (const void *a, const void *b)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const struct symbol *s1 = a;
Packit Service 97d2fb
  const struct symbol *s2 = b;
Packit Service 97d2fb
  int cmp;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Sort discarded symbols last.  */
Packit Service 97d2fb
  cmp = (s1->name == NULL) - (s2->name == NULL);
Packit Service 97d2fb
Packit Service 97d2fb
  if (cmp == 0)
Packit Service 97d2fb
    /* Local symbols must come first.  */
Packit Service 97d2fb
    cmp = ((GELF_ST_BIND (s2->info.info) == STB_LOCAL)
Packit Service 97d2fb
	   - (GELF_ST_BIND (s1->info.info) == STB_LOCAL));
Packit Service 97d2fb
Packit Service 97d2fb
  if (cmp == 0)
Packit Service 97d2fb
    /* binutils always puts section symbols first.  */
Packit Service 97d2fb
    cmp = ((GELF_ST_TYPE (s2->info.info) == STT_SECTION)
Packit Service 97d2fb
	   - (GELF_ST_TYPE (s1->info.info) == STT_SECTION));
Packit Service 97d2fb
Packit Service 97d2fb
  if (cmp == 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (GELF_ST_TYPE (s1->info.info) == STT_SECTION)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* binutils always puts section symbols in section index order.  */
Packit Service 97d2fb
	  CMP (shndx);
Packit Service 97d2fb
	  else if (s1 != s2)
Packit Service 97d2fb
	    error (EXIT_FAILURE, 0, "section symbols in unexpected order");
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Nothing really matters, so preserve the original order.  */
Packit Service 97d2fb
      CMP (map);
Packit Service 97d2fb
      else if (s1 != s2)
Packit Service 97d2fb
	error (EXIT_FAILURE, 0, "found two identical symbols");
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return cmp;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
#undef CMP
Packit Service 97d2fb
Packit Service 97d2fb
/* Return true if the flags of the sections match, ignoring the SHF_INFO_LINK
Packit Service 97d2fb
   flag if the section contains relocation information.  */
Packit Service 97d2fb
static bool
Packit Service 97d2fb
sections_flags_match (Elf64_Xword sh_flags1, Elf64_Xword sh_flags2,
Packit Service 97d2fb
		      Elf64_Word sh_type)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (sh_type == SHT_REL || sh_type == SHT_RELA)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      sh_flags1 &= ~SHF_INFO_LINK;
Packit Service 97d2fb
      sh_flags2 &= ~SHF_INFO_LINK;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return sh_flags1 == sh_flags2;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Return true iff the flags, size, and name match.  */
Packit Service 97d2fb
static bool
Packit Service 97d2fb
sections_match (const struct section *sections, size_t i,
Packit Service 97d2fb
		const GElf_Shdr *shdr, const char *name)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return (sections_flags_match (sections[i].shdr.sh_flags, shdr->sh_flags,
Packit Service 97d2fb
				sections[i].shdr.sh_type)
Packit Service 97d2fb
	  && (sections[i].shdr.sh_size == shdr->sh_size
Packit Service 97d2fb
	      || (sections[i].shdr.sh_size < shdr->sh_size
Packit Service 97d2fb
		  && section_can_shrink (&sections[i].shdr)))
Packit Service 97d2fb
	  && !strcmp (sections[i].name, name));
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Locate a matching allocated section in SECTIONS.  */
Packit Service 97d2fb
static struct section *
Packit Service 97d2fb
find_alloc_section (const GElf_Shdr *shdr, GElf_Addr bias, const char *name,
Packit Service 97d2fb
		    struct section sections[], size_t nalloc)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const GElf_Addr addr = shdr->sh_addr + bias;
Packit Service 97d2fb
  size_t l = 0, u = nalloc;
Packit Service 97d2fb
  while (l < u)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      size_t i = (l + u) / 2;
Packit Service 97d2fb
      if (addr < sections[i].shdr.sh_addr)
Packit Service 97d2fb
	u = i;
Packit Service 97d2fb
      else if (addr > sections[i].shdr.sh_addr)
Packit Service 97d2fb
	l = i + 1;
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* We've found allocated sections with this address.
Packit Service 97d2fb
	     Find one with matching size, flags, and name.  */
Packit Service 97d2fb
	  while (i > 0 && sections[i - 1].shdr.sh_addr == addr)
Packit Service 97d2fb
	    --i;
Packit Service 97d2fb
	  for (; i < nalloc && sections[i].shdr.sh_addr == addr;
Packit Service 97d2fb
	       ++i)
Packit Service 97d2fb
	    if (sections_match (sections, i, shdr, name))
Packit Service 97d2fb
	      return &sections[i];
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return NULL;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static inline const char *
Packit Service 97d2fb
get_section_name (size_t ndx, const GElf_Shdr *shdr, const Elf_Data *shstrtab)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (shdr->sh_name >= shstrtab->d_size)
Packit Service 97d2fb
    error (EXIT_FAILURE, 0, _("cannot read section [%zu] name: %s"),
Packit Service 97d2fb
	   ndx, elf_errmsg (-1));
Packit Service 97d2fb
  return shstrtab->d_buf + shdr->sh_name;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Returns the signature of a group section, or NULL if the given
Packit Service 97d2fb
   section isn't a group.  */
Packit Service 97d2fb
static const char *
Packit Service 97d2fb
get_group_sig (Elf *elf, GElf_Shdr *shdr)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (shdr->sh_type != SHT_GROUP)
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  Elf_Scn *symscn = elf_getscn (elf, shdr->sh_link);
Packit Service 97d2fb
  if (symscn == NULL)
Packit Service 97d2fb
    error (EXIT_FAILURE, 0, _("bad sh_link for group section: %s"),
Packit Service 97d2fb
	   elf_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Shdr symshdr_mem;
Packit Service 97d2fb
  GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
Packit Service 97d2fb
  if (symshdr == NULL)
Packit Service 97d2fb
    error (EXIT_FAILURE, 0, _("couldn't get shdr for group section: %s"),
Packit Service 97d2fb
	   elf_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
  Elf_Data *symdata = elf_getdata (symscn, NULL);
Packit Service 97d2fb
  if (symdata == NULL)
Packit Service 97d2fb
    error (EXIT_FAILURE, 0, _("bad data for group symbol section: %s"),
Packit Service 97d2fb
	   elf_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Sym sym_mem;
Packit Service 97d2fb
  GElf_Sym *sym = gelf_getsym (symdata, shdr->sh_info, &sym_mem);
Packit Service 97d2fb
  if (sym == NULL)
Packit Service 97d2fb
    error (EXIT_FAILURE, 0, _("couldn't get symbol for group section: %s"),
Packit Service 97d2fb
	   elf_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
  const char *sig = elf_strptr (elf, symshdr->sh_link, sym->st_name);
Packit Service 97d2fb
  if (sig == NULL)
Packit Service 97d2fb
    error (EXIT_FAILURE, 0, _("bad symbol name for group section: %s"),
Packit Service 97d2fb
	   elf_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
  return sig;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Fix things up when prelink has moved some allocated sections around
Packit Service 97d2fb
   and the debuginfo file's section headers no longer match up.
Packit Service 97d2fb
   This fills in SECTIONS[0..NALLOC-1].outscn or exits.
Packit Service 97d2fb
   If there was a .bss section that was split into two sections
Packit Service 97d2fb
   with the new one preceding it in sh_addr, we return that pointer.  */
Packit Service 97d2fb
static struct section *
Packit Service 97d2fb
find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
Packit Service 97d2fb
			     Elf *main, const GElf_Ehdr *main_ehdr,
Packit Service 97d2fb
			     Elf_Data *main_shstrtab, GElf_Addr bias,
Packit Service 97d2fb
			     struct section *sections,
Packit Service 97d2fb
			     size_t nalloc, size_t nsections)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Elf_Scn *undo = NULL;
Packit Service 97d2fb
  for (size_t i = nalloc; i < nsections; ++i)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      const struct section *sec = &sections[i];
Packit Service 97d2fb
      if (sec->shdr.sh_type == SHT_PROGBITS
Packit Service 97d2fb
	  && !(sec->shdr.sh_flags & SHF_ALLOC)
Packit Service 97d2fb
	  && !strcmp (sec->name, ".gnu.prelink_undo"))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  undo = sec->scn;
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Find the original allocated sections before prelinking.  */
Packit Service 97d2fb
  struct section *undo_sections = NULL;
Packit Service 97d2fb
  size_t undo_nalloc = 0;
Packit Service 97d2fb
  if (undo != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Clear assignments that might have been bogus.  */
Packit Service 97d2fb
      for (size_t i = 0; i < nalloc; ++i)
Packit Service 97d2fb
	sections[i].outscn = NULL;
Packit Service 97d2fb
Packit Service 97d2fb
      Elf_Data *undodata = elf_rawdata (undo, NULL);
Packit Service 97d2fb
      ELF_CHECK (undodata != NULL,
Packit Service 97d2fb
		 _("cannot read '.gnu.prelink_undo' section: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
      union
Packit Service 97d2fb
      {
Packit Service 97d2fb
	Elf32_Ehdr e32;
Packit Service 97d2fb
	Elf64_Ehdr e64;
Packit Service 97d2fb
      } ehdr;
Packit Service 97d2fb
      Elf_Data dst =
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  .d_buf = &ehdr,
Packit Service 97d2fb
	  .d_size = sizeof ehdr,
Packit Service 97d2fb
	  .d_type = ELF_T_EHDR,
Packit Service 97d2fb
	  .d_version = EV_CURRENT
Packit Service 97d2fb
	};
Packit Service 97d2fb
      Elf_Data src = *undodata;
Packit Service 97d2fb
      src.d_size = gelf_fsize (main, ELF_T_EHDR, 1, EV_CURRENT);
Packit Service 97d2fb
      src.d_type = ELF_T_EHDR;
Packit Service 97d2fb
      ELF_CHECK (gelf_xlatetom (main, &dst, &src,
Packit Service 97d2fb
				main_ehdr->e_ident[EI_DATA]) != NULL,
Packit Service 97d2fb
		 _("cannot read '.gnu.prelink_undo' section: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
      uint_fast16_t phnum;
Packit Service 97d2fb
      uint_fast16_t shnum;  /* prelink doesn't handle > SHN_LORESERVE.  */
Packit Service 97d2fb
      if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  phnum = ehdr.e32.e_phnum;
Packit Service 97d2fb
	  shnum = ehdr.e32.e_shnum;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  phnum = ehdr.e64.e_phnum;
Packit Service 97d2fb
	  shnum = ehdr.e64.e_shnum;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      bool class32 = ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32;
Packit Service 97d2fb
      size_t shsize = class32 ? sizeof (Elf32_Shdr) : sizeof (Elf64_Shdr);
Packit Service 97d2fb
      if (unlikely (shnum == 0 || shnum > SIZE_MAX / shsize + 1))
Packit Service 97d2fb
	error (EXIT_FAILURE, 0, _("overflow with shnum = %zu in '%s' section"),
Packit Service 97d2fb
	       (size_t) shnum, ".gnu.prelink_undo");
Packit Service 97d2fb
Packit Service 97d2fb
      --shnum;
Packit Service 97d2fb
Packit Service 97d2fb
      size_t phsize = gelf_fsize (main, ELF_T_PHDR, phnum, EV_CURRENT);
Packit Service 97d2fb
      src.d_buf += src.d_size + phsize;
Packit Service 97d2fb
      src.d_size = gelf_fsize (main, ELF_T_SHDR, shnum, EV_CURRENT);
Packit Service 97d2fb
      src.d_type = ELF_T_SHDR;
Packit Service 97d2fb
      if ((size_t) (src.d_buf - undodata->d_buf) > undodata->d_size
Packit Service 97d2fb
	  || undodata->d_size - (src.d_buf - undodata->d_buf) != src.d_size)
Packit Service 97d2fb
	error (EXIT_FAILURE, 0, _("invalid contents in '%s' section"),
Packit Service 97d2fb
	       ".gnu.prelink_undo");
Packit Service 97d2fb
Packit Service 97d2fb
      const size_t shdr_bytes = shnum * shsize;
Packit Service 97d2fb
      void *shdr = xmalloc (shdr_bytes);
Packit Service 97d2fb
      dst.d_buf = shdr;
Packit Service 97d2fb
      dst.d_size = shdr_bytes;
Packit Service 97d2fb
      ELF_CHECK (gelf_xlatetom (main, &dst, &src,
Packit Service 97d2fb
				main_ehdr->e_ident[EI_DATA]) != NULL,
Packit Service 97d2fb
		 _("cannot read '.gnu.prelink_undo' section: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
      undo_sections = xmalloc (shnum * sizeof undo_sections[0]);
Packit Service 97d2fb
      for (size_t i = 0; i < shnum; ++i)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  struct section *sec = &undo_sections[undo_nalloc];
Packit Service 97d2fb
	  Elf32_Shdr (*s32)[shnum] = shdr;
Packit Service 97d2fb
	  Elf64_Shdr (*s64)[shnum] = shdr;
Packit Service 97d2fb
	  if (class32)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
#define COPY(field) sec->shdr.field = (*s32)[i].field
Packit Service 97d2fb
	      COPY (sh_name);
Packit Service 97d2fb
	      COPY (sh_type);
Packit Service 97d2fb
	      COPY (sh_flags);
Packit Service 97d2fb
	      COPY (sh_addr);
Packit Service 97d2fb
	      COPY (sh_offset);
Packit Service 97d2fb
	      COPY (sh_size);
Packit Service 97d2fb
	      COPY (sh_link);
Packit Service 97d2fb
	      COPY (sh_info);
Packit Service 97d2fb
	      COPY (sh_addralign);
Packit Service 97d2fb
	      COPY (sh_entsize);
Packit Service 97d2fb
#undef	COPY
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    sec->shdr = (*s64)[i];
Packit Service 97d2fb
	  if (sec->shdr.sh_flags & SHF_ALLOC)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      sec->shdr.sh_addr += bias;
Packit Service 97d2fb
	      sec->name = get_section_name (i + 1, &sec->shdr, main_shstrtab);
Packit Service 97d2fb
	      sec->scn = elf_getscn (main, i + 1); /* Really just for ndx.  */
Packit Service 97d2fb
	      sec->outscn = NULL;
Packit Service 97d2fb
	      sec->strent = NULL;
Packit Service 97d2fb
	      sec->sig = get_group_sig (main, &sec->shdr);
Packit Service 97d2fb
	      ++undo_nalloc;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
      qsort (undo_sections, undo_nalloc,
Packit Service 97d2fb
	     sizeof undo_sections[0], compare_sections_nonrel);
Packit Service 97d2fb
      free (shdr);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  bool fail = false;
Packit Service 97d2fb
  inline void check_match (bool match, Elf_Scn *scn, const char *name)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (!match)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  fail = true;
Packit Service 97d2fb
	  error (0, 0, _("cannot find matching section for [%zu] '%s'"),
Packit Service 97d2fb
		 elf_ndxscn (scn), name);
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  Elf_Scn *scn = NULL;
Packit Service 97d2fb
  while ((scn = elf_nextscn (debug, scn)) != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Shdr shdr_mem;
Packit Service 97d2fb
      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Packit Service 97d2fb
      ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
      if (!(shdr->sh_flags & SHF_ALLOC))
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
Packit Service 97d2fb
      const char *name = get_section_name (elf_ndxscn (scn), shdr,
Packit Service 97d2fb
					   debug_shstrtab);
Packit Service 97d2fb
Packit Service 97d2fb
      if (undo_sections != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  struct section *sec = find_alloc_section (shdr, 0, name,
Packit Service 97d2fb
						    undo_sections,
Packit Service 97d2fb
						    undo_nalloc);
Packit Service 97d2fb
	  if (sec != NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      sec->outscn = scn;
Packit Service 97d2fb
	      continue;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* If there is no prelink info, we are just here to find
Packit Service 97d2fb
	 the sections to give error messages about.  */
Packit Service 97d2fb
      for (size_t i = 0; shdr != NULL && i < nalloc; ++i)
Packit Service 97d2fb
	if (sections[i].outscn == scn)
Packit Service 97d2fb
	  shdr = NULL;
Packit Service 97d2fb
      check_match (shdr == NULL, scn, name);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (fail)
Packit Service 97d2fb
    exit (EXIT_FAILURE);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Now we have lined up output sections for each of the original sections
Packit Service 97d2fb
     before prelinking.  Translate those to the prelinked sections.
Packit Service 97d2fb
     This matches what prelink's undo_sections does.  */
Packit Service 97d2fb
  struct section *split_bss = NULL;
Packit Service 97d2fb
  for (size_t i = 0; i < undo_nalloc; ++i)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      const struct section *undo_sec = &undo_sections[i];
Packit Service 97d2fb
Packit Service 97d2fb
      const char *name = undo_sec->name;
Packit Service 97d2fb
      scn = undo_sec->scn; /* This is just for elf_ndxscn.  */
Packit Service 97d2fb
Packit Service 97d2fb
      for (size_t j = 0; j < nalloc; ++j)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  struct section *sec = &sections[j];
Packit Service 97d2fb
#define RELA_SCALED(field) \
Packit Service 97d2fb
	  (2 * sec->shdr.field == 3 * undo_sec->shdr.field)
Packit Service 97d2fb
	  if (sec->outscn == NULL
Packit Service 97d2fb
	      && sec->shdr.sh_name == undo_sec->shdr.sh_name
Packit Service 97d2fb
	      && sec->shdr.sh_flags == undo_sec->shdr.sh_flags
Packit Service 97d2fb
	      && sec->shdr.sh_addralign == undo_sec->shdr.sh_addralign
Packit Service 97d2fb
	      && (((sec->shdr.sh_type == undo_sec->shdr.sh_type
Packit Service 97d2fb
		    && sec->shdr.sh_entsize == undo_sec->shdr.sh_entsize
Packit Service 97d2fb
		    && (sec->shdr.sh_size == undo_sec->shdr.sh_size
Packit Service 97d2fb
			|| (sec->shdr.sh_size > undo_sec->shdr.sh_size
Packit Service 97d2fb
			    && main_ehdr->e_type == ET_EXEC
Packit Service 97d2fb
			    && !strcmp (sec->name, ".dynstr"))))
Packit Service 97d2fb
		   || (sec->shdr.sh_size == undo_sec->shdr.sh_size
Packit Service 97d2fb
		       && ((sec->shdr.sh_entsize == undo_sec->shdr.sh_entsize
Packit Service 97d2fb
			    && undo_sec->shdr.sh_type == SHT_NOBITS)
Packit Service 97d2fb
			   || undo_sec->shdr.sh_type == SHT_PROGBITS)
Packit Service 97d2fb
		       && !strcmp (sec->name, ".plt")))
Packit Service 97d2fb
		  || (sec->shdr.sh_type == SHT_RELA
Packit Service 97d2fb
		      && undo_sec->shdr.sh_type == SHT_REL
Packit Service 97d2fb
		      && RELA_SCALED (sh_entsize) && RELA_SCALED (sh_size))
Packit Service 97d2fb
		  || (sec->shdr.sh_entsize == undo_sec->shdr.sh_entsize
Packit Service 97d2fb
		      && (sec->shdr.sh_type == undo_sec->shdr.sh_type
Packit Service 97d2fb
			  || (sec->shdr.sh_type == SHT_PROGBITS
Packit Service 97d2fb
			      && undo_sec->shdr.sh_type == SHT_NOBITS))
Packit Service 97d2fb
		      && sec->shdr.sh_size <= undo_sec->shdr.sh_size
Packit Service 97d2fb
		      && (!strcmp (sec->name, ".bss")
Packit Service 97d2fb
			  || !strcmp (sec->name, ".sbss"))
Packit Service 97d2fb
		      && (sec->shdr.sh_size == undo_sec->shdr.sh_size
Packit Service 97d2fb
			  || (split_bss = sec) > sections))))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      sec->outscn = undo_sec->outscn;
Packit Service 97d2fb
	      undo_sec = NULL;
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      check_match (undo_sec == NULL, scn, name);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  free (undo_sections);
Packit Service 97d2fb
Packit Service 97d2fb
  if (fail)
Packit Service 97d2fb
    exit (EXIT_FAILURE);
Packit Service 97d2fb
Packit Service 97d2fb
  return split_bss;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Create new .shstrtab contents, subroutine of copy_elided_sections.
Packit Service 97d2fb
   This can't be open coded there and still use variable-length auto arrays,
Packit Service 97d2fb
   since the end of our block would free other VLAs too.  */
Packit Service 97d2fb
static Elf_Data *
Packit Service 97d2fb
new_shstrtab (Elf *unstripped, size_t unstripped_shnum,
Packit Service 97d2fb
	      Elf_Data *shstrtab, size_t unstripped_shstrndx,
Packit Service 97d2fb
	      struct section *sections, size_t stripped_shnum,
Packit Service 97d2fb
	      Dwelf_Strtab *strtab)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (strtab == NULL)
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  Dwelf_Strent *unstripped_strent[unstripped_shnum];
Packit Service 97d2fb
  memset (unstripped_strent, 0, sizeof unstripped_strent);
Packit Service 97d2fb
  for (struct section *sec = sections;
Packit Service 97d2fb
       sec < &sections[stripped_shnum - 1];
Packit Service 97d2fb
       ++sec)
Packit Service 97d2fb
    if (sec->outscn != NULL)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	if (sec->strent == NULL)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    sec->strent = dwelf_strtab_add (strtab, sec->name);
Packit Service 97d2fb
	    ELF_CHECK (sec->strent != NULL,
Packit Service 97d2fb
		       _("cannot add section name to string table: %s"));
Packit Service 97d2fb
	  }
Packit Service 97d2fb
	unstripped_strent[elf_ndxscn (sec->outscn) - 1] = sec->strent;
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Add names of sections we aren't touching.  */
Packit Service 97d2fb
  for (size_t i = 0; i < unstripped_shnum - 1; ++i)
Packit Service 97d2fb
    if (unstripped_strent[i] == NULL)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	Elf_Scn *scn = elf_getscn (unstripped, i + 1);
Packit Service 97d2fb
	GElf_Shdr shdr_mem;
Packit Service 97d2fb
	GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Packit Service 97d2fb
	ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
Packit Service 97d2fb
	const char *name = get_section_name (i + 1, shdr, shstrtab);
Packit Service 97d2fb
	unstripped_strent[i] = dwelf_strtab_add (strtab, name);
Packit Service 97d2fb
	ELF_CHECK (unstripped_strent[i] != NULL,
Packit Service 97d2fb
		   _("cannot add section name to string table: %s"));
Packit Service 97d2fb
      }
Packit Service 97d2fb
    else
Packit Service 97d2fb
      unstripped_strent[i] = NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Now finalize the string table so we can get offsets.  */
Packit Service 97d2fb
  Elf_Data *strtab_data = elf_getdata (elf_getscn (unstripped,
Packit Service 97d2fb
						   unstripped_shstrndx), NULL);
Packit Service 97d2fb
  ELF_CHECK (elf_flagdata (strtab_data, ELF_C_SET, ELF_F_DIRTY),
Packit Service 97d2fb
	     _("cannot update section header string table data: %s"));
Packit Service 97d2fb
  if (dwelf_strtab_finalize (strtab, strtab_data) == NULL)
Packit Service 97d2fb
    error (EXIT_FAILURE, 0, "Not enough memory to create string table");
Packit Service 97d2fb
Packit Service 97d2fb
  /* Update the sh_name fields of sections we aren't modifying later.  */
Packit Service 97d2fb
  for (size_t i = 0; i < unstripped_shnum - 1; ++i)
Packit Service 97d2fb
    if (unstripped_strent[i] != NULL)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	Elf_Scn *scn = elf_getscn (unstripped, i + 1);
Packit Service 97d2fb
	GElf_Shdr shdr_mem;
Packit Service 97d2fb
	GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Packit Service 97d2fb
	ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
Packit Service 97d2fb
	shdr->sh_name = dwelf_strent_off (unstripped_strent[i]);
Packit Service 97d2fb
	if (i + 1 == unstripped_shstrndx)
Packit Service 97d2fb
	  shdr->sh_size = strtab_data->d_size;
Packit Service 97d2fb
	update_shdr (scn, shdr);
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
  return strtab_data;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Fill in any SHT_NOBITS sections in UNSTRIPPED by
Packit Service 97d2fb
   copying their contents and sh_type from STRIPPED.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
copy_elided_sections (Elf *unstripped, Elf *stripped,
Packit Service 97d2fb
		      const GElf_Ehdr *stripped_ehdr, GElf_Addr bias)
Packit Service 97d2fb
{
Packit Service 97d2fb
  size_t unstripped_shstrndx;
Packit Service 97d2fb
  ELF_CHECK (elf_getshdrstrndx (unstripped, &unstripped_shstrndx) == 0,
Packit Service 97d2fb
	     _("cannot get section header string table section index: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
  size_t stripped_shstrndx;
Packit Service 97d2fb
  ELF_CHECK (elf_getshdrstrndx (stripped, &stripped_shstrndx) == 0,
Packit Service 97d2fb
	     _("cannot get section header string table section index: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
  size_t unstripped_shnum;
Packit Service 97d2fb
  ELF_CHECK (elf_getshdrnum (unstripped, &unstripped_shnum) == 0,
Packit Service 97d2fb
	     _("cannot get section count: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
  size_t stripped_shnum;
Packit Service 97d2fb
  ELF_CHECK (elf_getshdrnum (stripped, &stripped_shnum) == 0,
Packit Service 97d2fb
	     _("cannot get section count: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely (stripped_shnum > unstripped_shnum))
Packit Service 97d2fb
    error (EXIT_FAILURE, 0, _("\
Packit Service 97d2fb
more sections in stripped file than debug file -- arguments reversed?"));
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely (stripped_shnum == 0))
Packit Service 97d2fb
    error (EXIT_FAILURE, 0, _("no sections in stripped file"));
Packit Service 97d2fb
Packit Service 97d2fb
  /* Used as sanity check for allocated section offset, if the section
Packit Service 97d2fb
     offset needs to be preserved.  We want to know the max size of the
Packit Service 97d2fb
     ELF file, to check if any existing section offsets are OK.  */
Packit Service 97d2fb
  int64_t max_off = -1;
Packit Service 97d2fb
  if (stripped_ehdr->e_type != ET_REL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      elf_flagelf (stripped, ELF_C_SET, ELF_F_LAYOUT);
Packit Service 97d2fb
      max_off = elf_update (stripped, ELF_C_NULL);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Cache the stripped file's section details.  */
Packit Service 97d2fb
  struct section sections[stripped_shnum - 1];
Packit Service 97d2fb
  Elf_Scn *scn = NULL;
Packit Service 97d2fb
  while ((scn = elf_nextscn (stripped, scn)) != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      size_t i = elf_ndxscn (scn) - 1;
Packit Service 97d2fb
      GElf_Shdr *shdr = gelf_getshdr (scn, &sections[i].shdr);
Packit Service 97d2fb
      ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
Packit Service 97d2fb
      sections[i].name = elf_strptr (stripped, stripped_shstrndx,
Packit Service 97d2fb
				     shdr->sh_name);
Packit Service 97d2fb
      if (sections[i].name == NULL)
Packit Service 97d2fb
	error (EXIT_FAILURE, 0, _("cannot read section [%zu] name: %s"),
Packit Service 97d2fb
	       elf_ndxscn (scn), elf_errmsg (-1));
Packit Service 97d2fb
      sections[i].scn = scn;
Packit Service 97d2fb
      sections[i].outscn = NULL;
Packit Service 97d2fb
      sections[i].strent = NULL;
Packit Service 97d2fb
      sections[i].sig = get_group_sig (stripped, shdr);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  const struct section *stripped_symtab = NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Sort the sections, allocated by address and others after.  */
Packit Service 97d2fb
  qsort (sections, stripped_shnum - 1, sizeof sections[0],
Packit Service 97d2fb
	 stripped_ehdr->e_type == ET_REL
Packit Service 97d2fb
	 ? compare_sections_rel : compare_sections_nonrel);
Packit Service 97d2fb
  size_t nalloc = stripped_shnum - 1;
Packit Service 97d2fb
  while (nalloc > 0 && !(sections[nalloc - 1].shdr.sh_flags & SHF_ALLOC))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      --nalloc;
Packit Service 97d2fb
      if (sections[nalloc].shdr.sh_type == SHT_SYMTAB)
Packit Service 97d2fb
	stripped_symtab = &sections[nalloc];
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Locate a matching unallocated section in SECTIONS.  */
Packit Service 97d2fb
  inline struct section *find_unalloc_section (const GElf_Shdr *shdr,
Packit Service 97d2fb
					       const char *name,
Packit Service 97d2fb
					       const char *sig)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      size_t l = nalloc, u = stripped_shnum - 1;
Packit Service 97d2fb
      while (l < u)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  size_t i = (l + u) / 2;
Packit Service 97d2fb
	  struct section *sec = &sections[i];
Packit Service 97d2fb
	  int cmp = compare_unalloc_sections (shdr, &sec->shdr,
Packit Service 97d2fb
					      name, sec->name,
Packit Service 97d2fb
					      sig, sec->sig);
Packit Service 97d2fb
	  if (cmp < 0)
Packit Service 97d2fb
	    u = i;
Packit Service 97d2fb
	  else if (cmp > 0)
Packit Service 97d2fb
	    l = i + 1;
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    return sec;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      return NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  Elf_Data *shstrtab = elf_getdata (elf_getscn (unstripped,
Packit Service 97d2fb
						unstripped_shstrndx), NULL);
Packit Service 97d2fb
  ELF_CHECK (shstrtab != NULL,
Packit Service 97d2fb
	     _("cannot read section header string table: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
  /* Match each debuginfo section with its corresponding stripped section.  */
Packit Service 97d2fb
  bool check_prelink = false;
Packit Service 97d2fb
  Elf_Scn *unstripped_symtab = NULL;
Packit Service 97d2fb
  size_t unstripped_strndx = 0;
Packit Service 97d2fb
  size_t alloc_avail = 0;
Packit Service 97d2fb
  scn = NULL;
Packit Service 97d2fb
  while ((scn = elf_nextscn (unstripped, scn)) != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Shdr shdr_mem;
Packit Service 97d2fb
      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Packit Service 97d2fb
      ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
      if (shdr->sh_type == SHT_SYMTAB)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  unstripped_symtab = scn;
Packit Service 97d2fb
	  unstripped_strndx = shdr->sh_link;
Packit Service 97d2fb
	  continue;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      const size_t ndx = elf_ndxscn (scn);
Packit Service 97d2fb
      if (ndx == unstripped_shstrndx || ndx == unstripped_strndx)
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
Packit Service 97d2fb
      const char *name = get_section_name (ndx, shdr, shstrtab);
Packit Service 97d2fb
Packit Service 97d2fb
      struct section *sec = NULL;
Packit Service 97d2fb
      if (shdr->sh_flags & SHF_ALLOC)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (stripped_ehdr->e_type != ET_REL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* Look for the section that matches.  */
Packit Service 97d2fb
	      sec = find_alloc_section (shdr, bias, name, sections, nalloc);
Packit Service 97d2fb
	      if (sec == NULL)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  /* We couldn't figure it out.  It may be a prelink issue.  */
Packit Service 97d2fb
		  check_prelink = true;
Packit Service 97d2fb
		  continue;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* The sh_addr of allocated sections does not help us,
Packit Service 97d2fb
		 but the order usually matches.  */
Packit Service 97d2fb
	      if (likely (sections_match (sections, alloc_avail, shdr, name)))
Packit Service 97d2fb
		sec = &sections[alloc_avail++];
Packit Service 97d2fb
	      else
Packit Service 97d2fb
		for (size_t i = alloc_avail + 1; i < nalloc; ++i)
Packit Service 97d2fb
		  if (sections_match (sections, i, shdr, name))
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      sec = &sections[i];
Packit Service 97d2fb
		      break;
Packit Service 97d2fb
		    }
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Look for the section that matches.  */
Packit Service 97d2fb
	  sec = find_unalloc_section (shdr, name,
Packit Service 97d2fb
				      get_group_sig (unstripped, shdr));
Packit Service 97d2fb
	  if (sec == NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* An additional unallocated section is fine if not SHT_NOBITS.
Packit Service 97d2fb
		 We looked it up anyway in case it's an unallocated section
Packit Service 97d2fb
		 copied in both files (e.g. SHT_NOTE), and don't keep both.  */
Packit Service 97d2fb
	      if (shdr->sh_type != SHT_NOBITS)
Packit Service 97d2fb
		continue;
Packit Service 97d2fb
Packit Service 97d2fb
	      /* Somehow some old .debug files wound up with SHT_NOBITS
Packit Service 97d2fb
		 .comment sections, so let those pass.  */
Packit Service 97d2fb
	      if (!strcmp (name, ".comment"))
Packit Service 97d2fb
		continue;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (sec == NULL)
Packit Service 97d2fb
	error (EXIT_FAILURE, 0,
Packit Service 97d2fb
	       _("cannot find matching section for [%zu] '%s'"),
Packit Service 97d2fb
	       elf_ndxscn (scn), name);
Packit Service 97d2fb
Packit Service 97d2fb
      sec->outscn = scn;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* If that failed due to changes made by prelink, we take another tack.
Packit Service 97d2fb
     We keep track of a .bss section that was partly split into .dynbss
Packit Service 97d2fb
     so that collect_symbols can update symbols' st_shndx fields.  */
Packit Service 97d2fb
  struct section *split_bss = NULL;
Packit Service 97d2fb
  if (check_prelink)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Elf_Data *data = elf_getdata (elf_getscn (stripped, stripped_shstrndx),
Packit Service 97d2fb
				    NULL);
Packit Service 97d2fb
      ELF_CHECK (data != NULL,
Packit Service 97d2fb
		 _("cannot read section header string table: %s"));
Packit Service 97d2fb
      split_bss = find_alloc_sections_prelink (unstripped, shstrtab,
Packit Service 97d2fb
					       stripped, stripped_ehdr,
Packit Service 97d2fb
					       data, bias, sections,
Packit Service 97d2fb
					       nalloc, stripped_shnum - 1);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Make sure each main file section has a place to go.  */
Packit Service 97d2fb
  const struct section *stripped_dynsym = NULL;
Packit Service 97d2fb
  size_t debuglink = SHN_UNDEF;
Packit Service 97d2fb
  size_t ndx_sec_num = stripped_shnum - 1;
Packit Service 97d2fb
  size_t ndx_section[ndx_sec_num];
Packit Service 97d2fb
  Dwelf_Strtab *strtab = NULL;
Packit Service 97d2fb
  for (struct section *sec = sections;
Packit Service 97d2fb
       sec < &sections[ndx_sec_num];
Packit Service 97d2fb
       ++sec)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      size_t secndx = elf_ndxscn (sec->scn);
Packit Service 97d2fb
Packit Service 97d2fb
      if (sec->outscn == NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* We didn't find any corresponding section for this.  */
Packit Service 97d2fb
Packit Service 97d2fb
	  if (secndx == stripped_shstrndx)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* We only need one .shstrtab.  */
Packit Service 97d2fb
	      ndx_section[secndx - 1] = unstripped_shstrndx;
Packit Service 97d2fb
	      continue;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  if (unstripped_symtab != NULL && sec == stripped_symtab)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* We don't need a second symbol table.  */
Packit Service 97d2fb
	      ndx_section[secndx - 1] = elf_ndxscn (unstripped_symtab);
Packit Service 97d2fb
	      continue;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  if (unstripped_symtab != NULL && stripped_symtab != NULL
Packit Service 97d2fb
	      && secndx == stripped_symtab->shdr.sh_link
Packit Service 97d2fb
	      && unstripped_strndx != 0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* ... nor its string table.  */
Packit Service 97d2fb
	      ndx_section[secndx - 1] = unstripped_strndx;
Packit Service 97d2fb
	      continue;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  if (!(sec->shdr.sh_flags & SHF_ALLOC)
Packit Service 97d2fb
	      && !strcmp (sec->name, ".gnu_debuglink"))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* This was created by stripping.  We don't want it.  */
Packit Service 97d2fb
	      debuglink = secndx;
Packit Service 97d2fb
	      ndx_section[secndx - 1] = SHN_UNDEF;
Packit Service 97d2fb
	      continue;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  sec->outscn = elf_newscn (unstripped);
Packit Service 97d2fb
	  Elf_Data *newdata = elf_newdata (sec->outscn);
Packit Service 97d2fb
	  ELF_CHECK (newdata != NULL && gelf_update_shdr (sec->outscn,
Packit Service 97d2fb
							  &sec->shdr),
Packit Service 97d2fb
		     _("cannot add new section: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
	  if (strtab == NULL)
Packit Service 97d2fb
	    strtab = dwelf_strtab_init (true);
Packit Service 97d2fb
	  sec->strent = dwelf_strtab_add (strtab, sec->name);
Packit Service 97d2fb
	  ELF_CHECK (sec->strent != NULL,
Packit Service 97d2fb
		     _("cannot add section name to string table: %s"));
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Cache the mapping of original section indices to output sections.  */
Packit Service 97d2fb
      ndx_section[secndx - 1] = elf_ndxscn (sec->outscn);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* We added some sections, so we need a new shstrtab.  */
Packit Service 97d2fb
  Elf_Data *strtab_data = new_shstrtab (unstripped, unstripped_shnum,
Packit Service 97d2fb
					shstrtab, unstripped_shstrndx,
Packit Service 97d2fb
					sections, stripped_shnum,
Packit Service 97d2fb
					strtab);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Get the updated section count.  */
Packit Service 97d2fb
  ELF_CHECK (elf_getshdrnum (unstripped, &unstripped_shnum) == 0,
Packit Service 97d2fb
	     _("cannot get section count: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
  bool placed[unstripped_shnum - 1];
Packit Service 97d2fb
  memset (placed, 0, sizeof placed);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Now update the output sections and copy in their data.  */
Packit Service 97d2fb
  GElf_Off offset = 0;
Packit Service 97d2fb
  for (const struct section *sec = sections;
Packit Service 97d2fb
       sec < &sections[stripped_shnum - 1];
Packit Service 97d2fb
       ++sec)
Packit Service 97d2fb
    if (sec->outscn != NULL)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	GElf_Shdr shdr_mem;
Packit Service 97d2fb
	GElf_Shdr *shdr = gelf_getshdr (sec->outscn, &shdr_mem);
Packit Service 97d2fb
	ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
	/* In an ET_REL file under --relocate, the sh_addr of SHF_ALLOC
Packit Service 97d2fb
	   sections will have been set nonzero by relocation.  This
Packit Service 97d2fb
	   touched the shdrs of whichever file had the symtab.  sh_addr
Packit Service 97d2fb
	   is still zero in the corresponding shdr.  The relocated
Packit Service 97d2fb
	   address is what we want to use.  */
Packit Service 97d2fb
	if (stripped_ehdr->e_type != ET_REL
Packit Service 97d2fb
	    || !(shdr_mem.sh_flags & SHF_ALLOC)
Packit Service 97d2fb
	    || shdr_mem.sh_addr == 0)
Packit Service 97d2fb
	  shdr_mem.sh_addr = sec->shdr.sh_addr;
Packit Service 97d2fb
Packit Service 97d2fb
	shdr_mem.sh_type = sec->shdr.sh_type;
Packit Service 97d2fb
	shdr_mem.sh_size = sec->shdr.sh_size;
Packit Service 97d2fb
	shdr_mem.sh_info = sec->shdr.sh_info;
Packit Service 97d2fb
	shdr_mem.sh_link = sec->shdr.sh_link;
Packit Service 97d2fb
Packit Service 97d2fb
	/* Buggy binutils objdump might have stripped the SHF_INFO_LINK
Packit Service 97d2fb
	   put it back if necessary.  */
Packit Service 97d2fb
	if ((sec->shdr.sh_type == SHT_REL || sec->shdr.sh_type == SHT_RELA)
Packit Service 97d2fb
	    && sec->shdr.sh_flags != shdr_mem.sh_flags
Packit Service 97d2fb
	    && (sec->shdr.sh_flags & SHF_INFO_LINK) != 0)
Packit Service 97d2fb
	  shdr_mem.sh_flags |= SHF_INFO_LINK;
Packit Service 97d2fb
Packit Service 97d2fb
	if (sec->shdr.sh_link != SHN_UNDEF)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    if (sec->shdr.sh_link > ndx_sec_num)
Packit Service 97d2fb
	      error (EXIT_FAILURE, 0,
Packit Service 97d2fb
		     "section [%zd] has invalid sh_link %" PRId32,
Packit Service 97d2fb
		     elf_ndxscn (sec->scn), sec->shdr.sh_link);
Packit Service 97d2fb
	    shdr_mem.sh_link = ndx_section[sec->shdr.sh_link - 1];
Packit Service 97d2fb
	  }
Packit Service 97d2fb
	if (SH_INFO_LINK_P (&sec->shdr) && sec->shdr.sh_info != 0)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    if (sec->shdr.sh_info > ndx_sec_num)
Packit Service 97d2fb
	      error (EXIT_FAILURE, 0,
Packit Service 97d2fb
		     "section [%zd] has invalid sh_info %" PRId32,
Packit Service 97d2fb
		     elf_ndxscn (sec->scn), sec->shdr.sh_info);
Packit Service 97d2fb
	    shdr_mem.sh_info = ndx_section[sec->shdr.sh_info - 1];
Packit Service 97d2fb
	  }
Packit Service 97d2fb
Packit Service 97d2fb
	if (strtab != NULL)
Packit Service 97d2fb
	  shdr_mem.sh_name = dwelf_strent_off (sec->strent);
Packit Service 97d2fb
Packit Service 97d2fb
	Elf_Data *indata = elf_getdata (sec->scn, NULL);
Packit Service 97d2fb
	ELF_CHECK (indata != NULL, _("cannot get section data: %s"));
Packit Service 97d2fb
	Elf_Data *outdata = elf_getdata (sec->outscn, NULL);
Packit Service 97d2fb
	ELF_CHECK (outdata != NULL, _("cannot copy section data: %s"));
Packit Service 97d2fb
	*outdata = *indata;
Packit Service 97d2fb
	elf_flagdata (outdata, ELF_C_SET, ELF_F_DIRTY);
Packit Service 97d2fb
Packit Service 97d2fb
	/* Preserve the file layout of the allocated sections.  */
Packit Service 97d2fb
	if (stripped_ehdr->e_type != ET_REL && (shdr_mem.sh_flags & SHF_ALLOC))
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    if (max_off > 0 && sec->shdr.sh_offset > (Elf64_Off) max_off)
Packit Service 97d2fb
		error (EXIT_FAILURE, 0,
Packit Service 97d2fb
		       "allocated section offset too large [%zd] %" PRIx64,
Packit Service 97d2fb
		       elf_ndxscn (sec->scn), sec->shdr.sh_offset);
Packit Service 97d2fb
Packit Service 97d2fb
	    shdr_mem.sh_offset = sec->shdr.sh_offset;
Packit Service 97d2fb
	    placed[elf_ndxscn (sec->outscn) - 1] = true;
Packit Service 97d2fb
Packit Service 97d2fb
	    const GElf_Off end_offset = (shdr_mem.sh_offset
Packit Service 97d2fb
					 + (shdr_mem.sh_type == SHT_NOBITS
Packit Service 97d2fb
					    ? 0 : shdr_mem.sh_size));
Packit Service 97d2fb
	    if (end_offset > offset)
Packit Service 97d2fb
	      offset = end_offset;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
Packit Service 97d2fb
	update_shdr (sec->outscn, &shdr_mem);
Packit Service 97d2fb
Packit Service 97d2fb
	if (shdr_mem.sh_type == SHT_SYMTAB || shdr_mem.sh_type == SHT_DYNSYM)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    /* We must adjust all the section indices in the symbol table.  */
Packit Service 97d2fb
Packit Service 97d2fb
	    Elf_Data *shndxdata = NULL;	/* XXX */
Packit Service 97d2fb
Packit Service 97d2fb
	    if (shdr_mem.sh_entsize == 0)
Packit Service 97d2fb
	      error (EXIT_FAILURE, 0,
Packit Service 97d2fb
		     "SYMTAB section cannot have zero sh_entsize");
Packit Service 97d2fb
	    for (size_t i = 1; i < shdr_mem.sh_size / shdr_mem.sh_entsize; ++i)
Packit Service 97d2fb
	      {
Packit Service 97d2fb
		GElf_Sym sym_mem;
Packit Service 97d2fb
		GElf_Word shndx = SHN_UNDEF;
Packit Service 97d2fb
		GElf_Sym *sym = gelf_getsymshndx (outdata, shndxdata,
Packit Service 97d2fb
						  i, &sym_mem, &shndx);
Packit Service 97d2fb
		ELF_CHECK (sym != NULL,
Packit Service 97d2fb
			   _("cannot get symbol table entry: %s"));
Packit Service 97d2fb
		if (sym->st_shndx != SHN_XINDEX)
Packit Service 97d2fb
		  shndx = sym->st_shndx;
Packit Service 97d2fb
Packit Service 97d2fb
		if (shndx != SHN_UNDEF && shndx < SHN_LORESERVE)
Packit Service 97d2fb
		  {
Packit Service 97d2fb
		    if (shndx >= stripped_shnum)
Packit Service 97d2fb
		      error (EXIT_FAILURE, 0,
Packit Service 97d2fb
			     _("symbol [%zu] has invalid section index"), i);
Packit Service 97d2fb
Packit Service 97d2fb
		    shndx = ndx_section[shndx - 1];
Packit Service 97d2fb
		    if (shndx < SHN_LORESERVE)
Packit Service 97d2fb
		      {
Packit Service 97d2fb
			sym->st_shndx = shndx;
Packit Service 97d2fb
			shndx = SHN_UNDEF;
Packit Service 97d2fb
		      }
Packit Service 97d2fb
		    else
Packit Service 97d2fb
		      sym->st_shndx = SHN_XINDEX;
Packit Service 97d2fb
Packit Service 97d2fb
		    ELF_CHECK (gelf_update_symshndx (outdata, shndxdata,
Packit Service 97d2fb
						     i, sym, shndx),
Packit Service 97d2fb
			       _("cannot update symbol table: %s"));
Packit Service 97d2fb
		  }
Packit Service 97d2fb
	      }
Packit Service 97d2fb
Packit Service 97d2fb
	    if (shdr_mem.sh_type == SHT_SYMTAB)
Packit Service 97d2fb
	      stripped_symtab = sec;
Packit Service 97d2fb
	    if (shdr_mem.sh_type == SHT_DYNSYM)
Packit Service 97d2fb
	      stripped_dynsym = sec;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
Packit Service 97d2fb
	if (shdr_mem.sh_type == SHT_GROUP)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    /* We must adjust all the section indices in the group.
Packit Service 97d2fb
	       Skip the first word, which is the section group flag.
Packit Service 97d2fb
	       Everything else is a section index.  */
Packit Service 97d2fb
	    Elf32_Word *shndx = (Elf32_Word *) outdata->d_buf;
Packit Service 97d2fb
	    for (size_t i = 1; i < shdr_mem.sh_size / sizeof (Elf32_Word); ++i)
Packit Service 97d2fb
	      if (shndx[i]  == SHN_UNDEF || shndx[i] >= stripped_shnum)
Packit Service 97d2fb
		error (EXIT_FAILURE, 0,
Packit Service 97d2fb
		       _("group has invalid section index [%zd]"), i);
Packit Service 97d2fb
	      else
Packit Service 97d2fb
		shndx[i] = ndx_section[shndx[i] - 1];
Packit Service 97d2fb
	  }
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
  /* We may need to update the symbol table.  */
Packit Service 97d2fb
  Elf_Data *symdata = NULL;
Packit Service 97d2fb
  Dwelf_Strtab *symstrtab = NULL;
Packit Service 97d2fb
  Elf_Data *symstrdata = NULL;
Packit Service 97d2fb
  if (unstripped_symtab != NULL && (stripped_symtab != NULL
Packit Service 97d2fb
				    || check_prelink /* Section adjustments. */
Packit Service 97d2fb
				    || (stripped_ehdr->e_type != ET_REL
Packit Service 97d2fb
					&& bias != 0)))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Merge the stripped file's symbol table into the unstripped one.  */
Packit Service 97d2fb
      const size_t stripped_nsym = (stripped_symtab == NULL ? 1
Packit Service 97d2fb
				    : (stripped_symtab->shdr.sh_size
Packit Service 97d2fb
				       / (stripped_symtab->shdr.sh_entsize == 0
Packit Service 97d2fb
					  ? 1
Packit Service 97d2fb
					  : stripped_symtab->shdr.sh_entsize)));
Packit Service 97d2fb
Packit Service 97d2fb
      GElf_Shdr shdr_mem;
Packit Service 97d2fb
      GElf_Shdr *shdr = gelf_getshdr (unstripped_symtab, &shdr_mem);
Packit Service 97d2fb
      ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
Packit Service 97d2fb
      if (shdr->sh_entsize == 0)
Packit Service 97d2fb
	error (EXIT_FAILURE, 0,
Packit Service 97d2fb
	       "unstripped SYMTAB section cannot have zero sh_entsize");
Packit Service 97d2fb
      const size_t unstripped_nsym = shdr->sh_size / shdr->sh_entsize;
Packit Service 97d2fb
Packit Service 97d2fb
      /* First collect all the symbols from both tables.  */
Packit Service 97d2fb
Packit Service 97d2fb
      const size_t total_syms = stripped_nsym - 1 + unstripped_nsym - 1;
Packit Service 97d2fb
      struct symbol *symbols = xmalloc (total_syms * sizeof (struct symbol));
Packit Service 97d2fb
      size_t *symndx_map = xmalloc (total_syms * sizeof (size_t));
Packit Service 97d2fb
Packit Service 97d2fb
      if (stripped_symtab != NULL)
Packit Service 97d2fb
	collect_symbols (unstripped, stripped_ehdr->e_type == ET_REL,
Packit Service 97d2fb
			 stripped_symtab->scn,
Packit Service 97d2fb
			 elf_getscn (stripped, stripped_symtab->shdr.sh_link),
Packit Service 97d2fb
			 stripped_nsym, 0, ndx_section,
Packit Service 97d2fb
			 symbols, symndx_map, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
      Elf_Scn *unstripped_strtab = elf_getscn (unstripped, shdr->sh_link);
Packit Service 97d2fb
      collect_symbols (unstripped, stripped_ehdr->e_type == ET_REL,
Packit Service 97d2fb
		       unstripped_symtab, unstripped_strtab, unstripped_nsym,
Packit Service 97d2fb
		       stripped_ehdr->e_type == ET_REL ? 0 : bias, NULL,
Packit Service 97d2fb
		       &symbols[stripped_nsym - 1],
Packit Service 97d2fb
		       &symndx_map[stripped_nsym - 1], split_bss);
Packit Service 97d2fb
Packit Service 97d2fb
      /* Next, sort our array of all symbols.  */
Packit Service 97d2fb
      qsort (symbols, total_syms, sizeof symbols[0], compare_symbols);
Packit Service 97d2fb
Packit Service 97d2fb
      /* Now we can weed out the duplicates.  Assign remaining symbols
Packit Service 97d2fb
	 new slots, collecting a map from old indices to new.  */
Packit Service 97d2fb
      size_t nsym = 0;
Packit Service 97d2fb
      for (struct symbol *s = symbols; s < &symbols[total_syms]; ++s)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Skip a section symbol for a removed section.  */
Packit Service 97d2fb
	  if (s->shndx == SHN_UNDEF
Packit Service 97d2fb
	      && GELF_ST_TYPE (s->info.info) == STT_SECTION)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      s->name = NULL;	/* Mark as discarded. */
Packit Service 97d2fb
	      *s->map = STN_UNDEF;
Packit Service 97d2fb
	      s->duplicate = NULL;
Packit Service 97d2fb
	      continue;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  struct symbol *n = s;
Packit Service 97d2fb
	  while (n + 1 < &symbols[total_syms] && !compare_symbols (s, n + 1))
Packit Service 97d2fb
	    ++n;
Packit Service 97d2fb
Packit Service 97d2fb
	  while (s < n)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* This is a duplicate.  Its twin will get the next slot.  */
Packit Service 97d2fb
	      s->name = NULL;	/* Mark as discarded. */
Packit Service 97d2fb
	      s->duplicate = n->map;
Packit Service 97d2fb
	      ++s;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Allocate the next slot.  */
Packit Service 97d2fb
	  *s->map = ++nsym;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Now we sort again, to determine the order in the output.  */
Packit Service 97d2fb
      qsort (symbols, total_syms, sizeof symbols[0], compare_symbols_output);
Packit Service 97d2fb
Packit Service 97d2fb
      if (nsym < total_syms)
Packit Service 97d2fb
	/* The discarded symbols are now at the end of the table.  */
Packit Service 97d2fb
	assert (symbols[nsym].name == NULL);
Packit Service 97d2fb
Packit Service 97d2fb
      /* Now a final pass updates the map with the final order,
Packit Service 97d2fb
	 and builds up the new string table.  */
Packit Service 97d2fb
      symstrtab = dwelf_strtab_init (true);
Packit Service 97d2fb
      for (size_t i = 0; i < nsym; ++i)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  assert (symbols[i].name != NULL);
Packit Service 97d2fb
	  assert (*symbols[i].map != 0);
Packit Service 97d2fb
	  *symbols[i].map = 1 + i;
Packit Service 97d2fb
	  symbols[i].strent = dwelf_strtab_add (symstrtab, symbols[i].name);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Scan the discarded symbols too, just to update their slots
Packit Service 97d2fb
	 in SYMNDX_MAP to refer to their live duplicates.  */
Packit Service 97d2fb
      for (size_t i = nsym; i < total_syms; ++i)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  assert (symbols[i].name == NULL);
Packit Service 97d2fb
	  if (symbols[i].duplicate == NULL)
Packit Service 97d2fb
	    assert (*symbols[i].map == STN_UNDEF);
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      assert (*symbols[i].duplicate != STN_UNDEF);
Packit Service 97d2fb
	      *symbols[i].map = *symbols[i].duplicate;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Now we are ready to write the new symbol table.  */
Packit Service 97d2fb
      symdata = elf_getdata (unstripped_symtab, NULL);
Packit Service 97d2fb
      symstrdata = elf_getdata (unstripped_strtab, NULL);
Packit Service 97d2fb
      Elf_Data *shndxdata = NULL;	/* XXX */
Packit Service 97d2fb
Packit Service 97d2fb
      /* If symtab and the section header table share the string table
Packit Service 97d2fb
	 add the section names to the strtab and then (after finalizing)
Packit Service 97d2fb
	 fixup the section header sh_names.  Also dispose of the old data.  */
Packit Service 97d2fb
      Dwelf_Strent *unstripped_strent[unstripped_shnum - 1];
Packit Service 97d2fb
      if (unstripped_shstrndx == elf_ndxscn (unstripped_strtab))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  for (size_t i = 0; i < unstripped_shnum - 1; ++i)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      Elf_Scn *sec = elf_getscn (unstripped, i + 1);
Packit Service 97d2fb
	      GElf_Shdr mem;
Packit Service 97d2fb
	      GElf_Shdr *hdr = gelf_getshdr (sec, &mem;;
Packit Service 97d2fb
	      const char *name = get_section_name (i + 1, hdr, shstrtab);
Packit Service 97d2fb
	      unstripped_strent[i] = dwelf_strtab_add (symstrtab, name);
Packit Service 97d2fb
	      ELF_CHECK (unstripped_strent[i] != NULL,
Packit Service 97d2fb
			 _("cannot add section name to string table: %s"));
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  if (strtab != NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      dwelf_strtab_free (strtab);
Packit Service 97d2fb
	      free (strtab_data->d_buf);
Packit Service 97d2fb
	      strtab = NULL;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (dwelf_strtab_finalize (symstrtab, symstrdata) == NULL)
Packit Service 97d2fb
	error (EXIT_FAILURE, 0, "Not enough memory to create symbol table");
Packit Service 97d2fb
Packit Service 97d2fb
      elf_flagdata (symstrdata, ELF_C_SET, ELF_F_DIRTY);
Packit Service 97d2fb
Packit Service 97d2fb
      /* And update the section header names if necessary.  */
Packit Service 97d2fb
      if (unstripped_shstrndx == elf_ndxscn (unstripped_strtab))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  for (size_t i = 0; i < unstripped_shnum - 1; ++i)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      Elf_Scn *sec = elf_getscn (unstripped, i + 1);
Packit Service 97d2fb
	      GElf_Shdr mem;
Packit Service 97d2fb
	      GElf_Shdr *hdr = gelf_getshdr (sec, &mem;;
Packit Service 97d2fb
	      shdr->sh_name = dwelf_strent_off (unstripped_strent[i]);
Packit Service 97d2fb
	      update_shdr (sec, hdr);
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Now update the symtab shdr.  Reload symtab shdr because sh_name
Packit Service 97d2fb
	 might have changed above. */
Packit Service 97d2fb
      shdr = gelf_getshdr (unstripped_symtab, &shdr_mem);
Packit Service 97d2fb
      ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
      shdr->sh_size = symdata->d_size = (1 + nsym) * shdr->sh_entsize;
Packit Service 97d2fb
      symdata->d_buf = xmalloc (symdata->d_size);
Packit Service 97d2fb
      record_new_data (symdata->d_buf);
Packit Service 97d2fb
Packit Service 97d2fb
      GElf_Sym sym;
Packit Service 97d2fb
      memset (&sym, 0, sizeof sym);
Packit Service 97d2fb
      ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, 0, &sym, SHN_UNDEF),
Packit Service 97d2fb
		 _("cannot update symbol table: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
      shdr->sh_info = 1;
Packit Service 97d2fb
      for (size_t i = 0; i < nsym; ++i)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  struct symbol *s = &symbols[i];
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Fill in the symbol details.  */
Packit Service 97d2fb
	  sym.st_name = dwelf_strent_off (s->strent);
Packit Service 97d2fb
	  sym.st_value = s->value; /* Already biased to output address.  */
Packit Service 97d2fb
	  sym.st_size = s->size;
Packit Service 97d2fb
	  sym.st_shndx = s->shndx; /* Already mapped to output index.  */
Packit Service 97d2fb
	  sym.st_info = s->info.info;
Packit Service 97d2fb
	  sym.st_other = s->info.other;
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Keep track of the number of leading local symbols.  */
Packit Service 97d2fb
	  if (GELF_ST_BIND (sym.st_info) == STB_LOCAL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      assert (shdr->sh_info == 1 + i);
Packit Service 97d2fb
	      shdr->sh_info = 1 + i + 1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, 1 + i,
Packit Service 97d2fb
					   &sym, SHN_UNDEF),
Packit Service 97d2fb
		     _("cannot update symbol table: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
	}
Packit Service 97d2fb
      elf_flagdata (symdata, ELF_C_SET, ELF_F_DIRTY);
Packit Service 97d2fb
      update_shdr (unstripped_symtab, shdr);
Packit Service 97d2fb
Packit Service 97d2fb
      if (stripped_symtab != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Adjust any relocations referring to the old symbol table.  */
Packit Service 97d2fb
	  const size_t old_sh_link = elf_ndxscn (stripped_symtab->scn);
Packit Service 97d2fb
	  for (const struct section *sec = sections;
Packit Service 97d2fb
	       sec < &sections[stripped_shnum - 1];
Packit Service 97d2fb
	       ++sec)
Packit Service 97d2fb
	    if (sec->outscn != NULL && sec->shdr.sh_link == old_sh_link)
Packit Service 97d2fb
	      adjust_relocs (sec->outscn, sec->scn, &sec->shdr,
Packit Service 97d2fb
			     symndx_map, total_syms, shdr);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Also adjust references to the other old symbol table.  */
Packit Service 97d2fb
      adjust_all_relocs (unstripped, unstripped_symtab, shdr,
Packit Service 97d2fb
			 &symndx_map[stripped_nsym - 1],
Packit Service 97d2fb
			 total_syms - (stripped_nsym - 1));
Packit Service 97d2fb
Packit Service 97d2fb
      free (symbols);
Packit Service 97d2fb
      free (symndx_map);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else if (stripped_symtab != NULL && stripped_shnum != unstripped_shnum)
Packit Service 97d2fb
    check_symtab_section_symbols (unstripped,
Packit Service 97d2fb
				  stripped_ehdr->e_type == ET_REL,
Packit Service 97d2fb
				  stripped_symtab->scn,
Packit Service 97d2fb
				  unstripped_shnum, unstripped_shstrndx,
Packit Service 97d2fb
				  stripped_symtab->outscn,
Packit Service 97d2fb
				  stripped_shnum, stripped_shstrndx,
Packit Service 97d2fb
				  debuglink);
Packit Service 97d2fb
Packit Service 97d2fb
  if (stripped_dynsym != NULL)
Packit Service 97d2fb
    (void) check_symtab_section_symbols (unstripped,
Packit Service 97d2fb
					 stripped_ehdr->e_type == ET_REL,
Packit Service 97d2fb
					 stripped_dynsym->outscn,
Packit Service 97d2fb
					 unstripped_shnum,
Packit Service 97d2fb
					 unstripped_shstrndx,
Packit Service 97d2fb
					 stripped_dynsym->scn, stripped_shnum,
Packit Service 97d2fb
					 stripped_shstrndx, debuglink);
Packit Service 97d2fb
Packit Service 97d2fb
  /* We need to preserve the layout of the stripped file so the
Packit Service 97d2fb
     phdrs will match up.  This requires us to do our own layout of
Packit Service 97d2fb
     the added sections.  We do manual layout even for ET_REL just
Packit Service 97d2fb
     so we can try to match what the original probably had.  */
Packit Service 97d2fb
Packit Service 97d2fb
  elf_flagelf (unstripped, ELF_C_SET, ELF_F_LAYOUT);
Packit Service 97d2fb
Packit Service 97d2fb
  if (offset == 0)
Packit Service 97d2fb
    /* For ET_REL we are starting the layout from scratch.  */
Packit Service 97d2fb
    offset = gelf_fsize (unstripped, ELF_T_EHDR, 1, EV_CURRENT);
Packit Service 97d2fb
Packit Service 97d2fb
  bool skip_reloc = false;
Packit Service 97d2fb
  do
Packit Service 97d2fb
    {
Packit Service 97d2fb
      skip_reloc = !skip_reloc;
Packit Service 97d2fb
      for (size_t i = 0; i < unstripped_shnum - 1; ++i)
Packit Service 97d2fb
	if (!placed[i])
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    scn = elf_getscn (unstripped, 1 + i);
Packit Service 97d2fb
Packit Service 97d2fb
	    GElf_Shdr shdr_mem;
Packit Service 97d2fb
	    GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Packit Service 97d2fb
	    ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
	    /* We must make sure we have read in the data of all sections
Packit Service 97d2fb
	       beforehand and marked them to be written out.  When we're
Packit Service 97d2fb
	       modifying the existing file in place, we might overwrite
Packit Service 97d2fb
	       this part of the file before we get to handling the section.  */
Packit Service 97d2fb
Packit Service 97d2fb
	    ELF_CHECK (elf_flagdata (elf_getdata (scn, NULL),
Packit Service 97d2fb
				     ELF_C_SET, ELF_F_DIRTY),
Packit Service 97d2fb
		       _("cannot read section data: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
	    if (skip_reloc
Packit Service 97d2fb
		&& (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
Packit Service 97d2fb
	      continue;
Packit Service 97d2fb
Packit Service 97d2fb
	    GElf_Off align = shdr->sh_addralign ?: 1;
Packit Service 97d2fb
	    offset = (offset + align - 1) & -align;
Packit Service 97d2fb
	    shdr->sh_offset = offset;
Packit Service 97d2fb
	    if (shdr->sh_type != SHT_NOBITS)
Packit Service 97d2fb
	      offset += shdr->sh_size;
Packit Service 97d2fb
Packit Service 97d2fb
	    update_shdr (scn, shdr);
Packit Service 97d2fb
Packit Service 97d2fb
	    if (unstripped_shstrndx == 1 + i)
Packit Service 97d2fb
	      {
Packit Service 97d2fb
		/* Place the section headers immediately after
Packit Service 97d2fb
		   .shstrtab, and update the ELF header.  */
Packit Service 97d2fb
Packit Service 97d2fb
		GElf_Ehdr ehdr_mem;
Packit Service 97d2fb
		GElf_Ehdr *ehdr = gelf_getehdr (unstripped, &ehdr_mem);
Packit Service 97d2fb
		ELF_CHECK (ehdr != NULL, _("cannot get ELF header: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
		GElf_Off sh_align = gelf_getclass (unstripped) * 4;
Packit Service 97d2fb
		offset = (offset + sh_align - 1) & -sh_align;
Packit Service 97d2fb
		ehdr->e_shnum = unstripped_shnum;
Packit Service 97d2fb
		ehdr->e_shoff = offset;
Packit Service 97d2fb
		offset += unstripped_shnum * ehdr->e_shentsize;
Packit Service 97d2fb
		ELF_CHECK (gelf_update_ehdr (unstripped, ehdr),
Packit Service 97d2fb
			   _("cannot update ELF header: %s"));
Packit Service 97d2fb
	      }
Packit Service 97d2fb
Packit Service 97d2fb
	    placed[i] = true;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
    }
Packit Service 97d2fb
  while (skip_reloc);
Packit Service 97d2fb
Packit Service 97d2fb
  size_t phnum;
Packit Service 97d2fb
  ELF_CHECK (elf_getphdrnum (stripped, &phnum) == 0,
Packit Service 97d2fb
	     _("cannot get number of program headers: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
  if (phnum > 0)
Packit Service 97d2fb
    ELF_CHECK (gelf_newphdr (unstripped, phnum),
Packit Service 97d2fb
	       _("cannot create program headers: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
  /* Copy each program header from the stripped file.  */
Packit Service 97d2fb
  for (size_t i = 0; i < phnum; ++i)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Phdr phdr_mem;
Packit Service 97d2fb
      GElf_Phdr *phdr = gelf_getphdr (stripped, i, &phdr_mem);
Packit Service 97d2fb
      ELF_CHECK (phdr != NULL, _("cannot get program header: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
      ELF_CHECK (gelf_update_phdr (unstripped, i, phdr),
Packit Service 97d2fb
		 _("cannot update program header: %s"));
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Finally, write out the file.  */
Packit Service 97d2fb
  ELF_CHECK (elf_update (unstripped, ELF_C_WRITE) > 0,
Packit Service 97d2fb
	     _("cannot write output file: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
  if (strtab != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      dwelf_strtab_free (strtab);
Packit Service 97d2fb
      free (strtab_data->d_buf);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (symstrtab != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      dwelf_strtab_free (symstrtab);
Packit Service 97d2fb
      free (symstrdata->d_buf);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  free_new_data ();
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Process one pair of files, already opened.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
handle_file (const char *output_file, bool create_dirs,
Packit Service 97d2fb
	     Elf *stripped, const GElf_Ehdr *stripped_ehdr,
Packit Service 97d2fb
	     Elf *unstripped)
Packit Service 97d2fb
{
Packit Service 97d2fb
  size_t phnum;
Packit Service 97d2fb
  ELF_CHECK (elf_getphdrnum (stripped, &phnum) == 0,
Packit Service 97d2fb
	     _("cannot get number of program headers: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
  /* Determine the address bias between the debuginfo file and the main
Packit Service 97d2fb
     file, which may have been modified by prelinking.  */
Packit Service 97d2fb
  GElf_Addr bias = 0;
Packit Service 97d2fb
  if (unstripped != NULL)
Packit Service 97d2fb
    for (size_t i = 0; i < phnum; ++i)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	GElf_Phdr phdr_mem;
Packit Service 97d2fb
	GElf_Phdr *phdr = gelf_getphdr (stripped, i, &phdr_mem);
Packit Service 97d2fb
	ELF_CHECK (phdr != NULL, _("cannot get program header: %s"));
Packit Service 97d2fb
	if (phdr->p_type == PT_LOAD)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    GElf_Phdr unstripped_phdr_mem;
Packit Service 97d2fb
	    GElf_Phdr *unstripped_phdr = gelf_getphdr (unstripped, i,
Packit Service 97d2fb
						       &unstripped_phdr_mem);
Packit Service 97d2fb
	    ELF_CHECK (unstripped_phdr != NULL,
Packit Service 97d2fb
		       _("cannot get program header: %s"));
Packit Service 97d2fb
	    bias = phdr->p_vaddr - unstripped_phdr->p_vaddr;
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
  /* One day we could adjust all the DWARF data (like prelink itself does).  */
Packit Service 97d2fb
  if (bias != 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (output_file == NULL)
Packit Service 97d2fb
	error (0, 0, _("\
Packit Service 97d2fb
DWARF data not adjusted for prelinking bias; consider prelink -u"));
Packit Service 97d2fb
      else
Packit Service 97d2fb
	error (0, 0, _("\
Packit Service 97d2fb
DWARF data in '%s' not adjusted for prelinking bias; consider prelink -u"),
Packit Service 97d2fb
	       output_file);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (output_file == NULL)
Packit Service 97d2fb
    /* Modify the unstripped file in place.  */
Packit Service 97d2fb
    copy_elided_sections (unstripped, stripped, stripped_ehdr, bias);
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (create_dirs)
Packit Service 97d2fb
	make_directories (output_file);
Packit Service 97d2fb
Packit Service 97d2fb
      /* Copy the unstripped file and then modify it.  */
Packit Service 97d2fb
      int outfd = open (output_file, O_RDWR | O_CREAT,
Packit Service 97d2fb
			  stripped_ehdr->e_type == ET_REL ? 0666 : 0777);
Packit Service 97d2fb
      if (outfd < 0)
Packit Service 97d2fb
	error (EXIT_FAILURE, errno, _("cannot open '%s'"), output_file);
Packit Service 97d2fb
      Elf *outelf = elf_begin (outfd, ELF_C_WRITE, NULL);
Packit Service 97d2fb
      ELF_CHECK (outelf != NULL, _("cannot create ELF descriptor: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
      if (unstripped == NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Actually, we are just copying out the main file as it is.  */
Packit Service 97d2fb
	  copy_elf (outelf, stripped);
Packit Service 97d2fb
	  if (stripped_ehdr->e_type != ET_REL)
Packit Service 97d2fb
	    elf_flagelf (outelf, ELF_C_SET, ELF_F_LAYOUT);
Packit Service 97d2fb
	  ELF_CHECK (elf_update (outelf, ELF_C_WRITE) > 0,
Packit Service 97d2fb
		     _("cannot write output file: %s"));
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  copy_elf (outelf, unstripped);
Packit Service 97d2fb
	  copy_elided_sections (outelf, stripped, stripped_ehdr, bias);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      elf_end (outelf);
Packit Service 97d2fb
      close (outfd);
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
open_file (const char *file, bool writable)
Packit Service 97d2fb
{
Packit Service 97d2fb
  int fd = open (file, writable ? O_RDWR : O_RDONLY);
Packit Service 97d2fb
  if (fd < 0)
Packit Service 97d2fb
    error (EXIT_FAILURE, errno, _("cannot open '%s'"), file);
Packit Service 97d2fb
  return fd;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Handle a pair of files we need to open by name.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
handle_explicit_files (const char *output_file, bool create_dirs, bool force,
Packit Service 97d2fb
		       const char *stripped_file, const char *unstripped_file)
Packit Service 97d2fb
{
Packit Service 97d2fb
Packit Service 97d2fb
  /* Warn, and exit if not forced to continue, if some ELF header
Packit Service 97d2fb
     sanity check for the stripped and unstripped files failed.  */
Packit Service 97d2fb
  void warn (const char *msg)
Packit Service 97d2fb
  {
Packit Service 97d2fb
    error (force ? 0 : EXIT_FAILURE, 0, "%s'%s' and '%s' %s%s.",
Packit Service 97d2fb
	   force ? _("WARNING: ") : "",
Packit Service 97d2fb
	   stripped_file, unstripped_file, msg,
Packit Service 97d2fb
	   force ? "" : _(", use --force"));
Packit Service 97d2fb
  }
Packit Service 97d2fb
Packit Service 97d2fb
  int stripped_fd = open_file (stripped_file, false);
Packit Service 97d2fb
  Elf *stripped = elf_begin (stripped_fd, ELF_C_READ, NULL);
Packit Service 97d2fb
  GElf_Ehdr stripped_ehdr;
Packit Service 97d2fb
  ELF_CHECK (gelf_getehdr (stripped, &stripped_ehdr),
Packit Service 97d2fb
	     _("cannot create ELF descriptor: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
  int unstripped_fd = -1;
Packit Service 97d2fb
  Elf *unstripped = NULL;
Packit Service 97d2fb
  if (unstripped_file != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      unstripped_fd = open_file (unstripped_file, output_file == NULL);
Packit Service 97d2fb
      unstripped = elf_begin (unstripped_fd,
Packit Service 97d2fb
			      (output_file == NULL ? ELF_C_RDWR : ELF_C_READ),
Packit Service 97d2fb
			      NULL);
Packit Service 97d2fb
      GElf_Ehdr unstripped_ehdr;
Packit Service 97d2fb
      ELF_CHECK (gelf_getehdr (unstripped, &unstripped_ehdr),
Packit Service 97d2fb
		 _("cannot create ELF descriptor: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
      if (memcmp (stripped_ehdr.e_ident,
Packit Service 97d2fb
		  unstripped_ehdr.e_ident, EI_NIDENT) != 0)
Packit Service 97d2fb
	warn (_("ELF header identification (e_ident) different"));
Packit Service 97d2fb
Packit Service 97d2fb
      if (stripped_ehdr.e_type != unstripped_ehdr.e_type)
Packit Service 97d2fb
	warn (_("ELF header type (e_type) different"));
Packit Service 97d2fb
Packit Service 97d2fb
      if (stripped_ehdr.e_machine != unstripped_ehdr.e_machine)
Packit Service 97d2fb
	warn (_("ELF header machine type (e_machine) different"));
Packit Service 97d2fb
Packit Service 97d2fb
      if (stripped_ehdr.e_phnum < unstripped_ehdr.e_phnum)
Packit Service 97d2fb
	warn (_("stripped program header (e_phnum) smaller than unstripped"));
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  handle_file (output_file, create_dirs, stripped, &stripped_ehdr, unstripped);
Packit Service 97d2fb
Packit Service 97d2fb
  elf_end (stripped);
Packit Service 97d2fb
  close (stripped_fd);
Packit Service 97d2fb
Packit Service 97d2fb
  elf_end (unstripped);
Packit Service 97d2fb
  close (unstripped_fd);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Handle a pair of files opened implicitly by libdwfl for one module.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
handle_dwfl_module (const char *output_file, bool create_dirs, bool force,
Packit Service 97d2fb
		    Dwfl_Module *mod, bool all, bool ignore, bool relocate)
Packit Service 97d2fb
{
Packit Service 97d2fb
  GElf_Addr bias;
Packit Service 97d2fb
  Elf *stripped = dwfl_module_getelf (mod, &bias);
Packit Service 97d2fb
  if (stripped == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (ignore)
Packit Service 97d2fb
	return;
Packit Service 97d2fb
Packit Service 97d2fb
      const char *file;
Packit Service 97d2fb
      const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
Packit Service 97d2fb
					      NULL, NULL, &file, NULL);
Packit Service 97d2fb
      if (file == NULL)
Packit Service 97d2fb
	error (EXIT_FAILURE, 0,
Packit Service 97d2fb
	       _("cannot find stripped file for module '%s': %s"),
Packit Service 97d2fb
	       modname, dwfl_errmsg (-1));
Packit Service 97d2fb
      else
Packit Service 97d2fb
	error (EXIT_FAILURE, 0,
Packit Service 97d2fb
	       _("cannot open stripped file '%s' for module '%s': %s"),
Packit Service 97d2fb
	       modname, file, dwfl_errmsg (-1));
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  Elf *debug = dwarf_getelf (dwfl_module_getdwarf (mod, &bias));
Packit Service 97d2fb
  if (debug == NULL && !all)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (ignore)
Packit Service 97d2fb
	return;
Packit Service 97d2fb
Packit Service 97d2fb
      const char *file;
Packit Service 97d2fb
      const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
Packit Service 97d2fb
					      NULL, NULL, NULL, &file;;
Packit Service 97d2fb
      if (file == NULL)
Packit Service 97d2fb
	error (EXIT_FAILURE, 0,
Packit Service 97d2fb
	       _("cannot find debug file for module '%s': %s"),
Packit Service 97d2fb
	       modname, dwfl_errmsg (-1));
Packit Service 97d2fb
      else
Packit Service 97d2fb
	error (EXIT_FAILURE, 0,
Packit Service 97d2fb
	       _("cannot open debug file '%s' for module '%s': %s"),
Packit Service 97d2fb
	       modname, file, dwfl_errmsg (-1));
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (debug == stripped)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (all)
Packit Service 97d2fb
	debug = NULL;
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  const char *file;
Packit Service 97d2fb
	  const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
Packit Service 97d2fb
						  NULL, NULL, &file, NULL);
Packit Service 97d2fb
	  error (EXIT_FAILURE, 0, _("module '%s' file '%s' is not stripped"),
Packit Service 97d2fb
		 modname, file);
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Ehdr stripped_ehdr;
Packit Service 97d2fb
  ELF_CHECK (gelf_getehdr (stripped, &stripped_ehdr),
Packit Service 97d2fb
	     _("cannot create ELF descriptor: %s"));
Packit Service 97d2fb
Packit Service 97d2fb
  if (stripped_ehdr.e_type == ET_REL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (!relocate)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* We can't use the Elf handles already open,
Packit Service 97d2fb
	     because the DWARF sections have been relocated.  */
Packit Service 97d2fb
Packit Service 97d2fb
	  const char *stripped_file = NULL;
Packit Service 97d2fb
	  const char *unstripped_file = NULL;
Packit Service 97d2fb
	  (void) dwfl_module_info (mod, NULL, NULL, NULL, NULL, NULL,
Packit Service 97d2fb
				   &stripped_file, &unstripped_file);
Packit Service 97d2fb
Packit Service 97d2fb
	  handle_explicit_files (output_file, create_dirs, force,
Packit Service 97d2fb
				 stripped_file, unstripped_file);
Packit Service 97d2fb
	  return;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Relocation is what we want!  This ensures that all sections that can
Packit Service 97d2fb
	 get sh_addr values assigned have them, even ones not used in DWARF.
Packit Service 97d2fb
	 They might still be used in the symbol table.  */
Packit Service 97d2fb
      if (dwfl_module_relocations (mod) < 0)
Packit Service 97d2fb
	error (EXIT_FAILURE, 0,
Packit Service 97d2fb
	       _("cannot cache section addresses for module '%s': %s"),
Packit Service 97d2fb
	       dwfl_module_info (mod, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
Packit Service 97d2fb
	       dwfl_errmsg (-1));
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  handle_file (output_file, create_dirs, stripped, &stripped_ehdr, debug);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Handle one module being written to the output directory.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
handle_output_dir_module (const char *output_dir, Dwfl_Module *mod, bool force,
Packit Service 97d2fb
			  bool all, bool ignore, bool modnames, bool relocate)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (! modnames)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Make sure we've searched for the ELF file.  */
Packit Service 97d2fb
      GElf_Addr bias;
Packit Service 97d2fb
      (void) dwfl_module_getelf (mod, &bias);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  const char *file;
Packit Service 97d2fb
  const char *name = dwfl_module_info (mod, NULL, NULL, NULL,
Packit Service 97d2fb
				       NULL, NULL, &file, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
  if (file == NULL && ignore)
Packit Service 97d2fb
    return;
Packit Service 97d2fb
Packit Service 97d2fb
  char *output_file;
Packit Service 97d2fb
  if (asprintf (&output_file, "%s/%s", output_dir, modnames ? name : file) < 0)
Packit Service 97d2fb
    error (EXIT_FAILURE, 0, _("memory exhausted"));
Packit Service 97d2fb
Packit Service 97d2fb
  handle_dwfl_module (output_file, true, force, mod, all, ignore, relocate);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
list_module (Dwfl_Module *mod)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Make sure we have searched for the files.  */
Packit Service 97d2fb
  GElf_Addr bias;
Packit Service 97d2fb
  bool have_elf = dwfl_module_getelf (mod, &bias) != NULL;
Packit Service 97d2fb
  bool have_dwarf = dwfl_module_getdwarf (mod, &bias) != NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  const char *file;
Packit Service 97d2fb
  const char *debug;
Packit Service 97d2fb
  Dwarf_Addr start;
Packit Service 97d2fb
  Dwarf_Addr end;
Packit Service 97d2fb
  const char *name = dwfl_module_info (mod, NULL, &start, &end,
Packit Service 97d2fb
				       NULL, NULL, &file, &debug);
Packit Service 97d2fb
  if (file != NULL && debug != NULL && (debug == file || !strcmp (debug, file)))
Packit Service 97d2fb
    debug = ".";
Packit Service 97d2fb
Packit Service 97d2fb
  const unsigned char *id;
Packit Service 97d2fb
  GElf_Addr id_vaddr;
Packit Service 97d2fb
  int id_len = dwfl_module_build_id (mod, &id, &id_vaddr);
Packit Service 97d2fb
Packit Service 97d2fb
  printf ("%#" PRIx64 "+%#" PRIx64 " ", start, end - start);
Packit Service 97d2fb
Packit Service 97d2fb
  if (id_len > 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      do
Packit Service 97d2fb
	printf ("%02" PRIx8, *id++);
Packit Service 97d2fb
      while (--id_len > 0);
Packit Service 97d2fb
      if (id_vaddr != 0)
Packit Service 97d2fb
	printf ("@%#" PRIx64, id_vaddr);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    putchar ('-');
Packit Service 97d2fb
Packit Service 97d2fb
  printf (" %s %s %s\n",
Packit Service 97d2fb
	  file ?: have_elf ? "." : "-",
Packit Service 97d2fb
	  debug ?: have_dwarf ? "." : "-",
Packit Service 97d2fb
	  name);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
struct match_module_info
Packit Service 97d2fb
{
Packit Service 97d2fb
  char **patterns;
Packit Service 97d2fb
  Dwfl_Module *found;
Packit Service 97d2fb
  bool match_files;
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
match_module (Dwfl_Module *mod,
Packit Service 97d2fb
	      void **userdata __attribute__ ((unused)),
Packit Service 97d2fb
	      const char *name,
Packit Service 97d2fb
	      Dwarf_Addr start __attribute__ ((unused)),
Packit Service 97d2fb
	      void *arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct match_module_info *info = arg;
Packit Service 97d2fb
Packit Service 97d2fb
  if (info->patterns[0] == NULL) /* Match all.  */
Packit Service 97d2fb
    {
Packit Service 97d2fb
    match:
Packit Service 97d2fb
      info->found = mod;
Packit Service 97d2fb
      return DWARF_CB_ABORT;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (info->match_files)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Make sure we've searched for the ELF file.  */
Packit Service 97d2fb
      GElf_Addr bias;
Packit Service 97d2fb
      (void) dwfl_module_getelf (mod, &bias);
Packit Service 97d2fb
Packit Service 97d2fb
      const char *file;
Packit Service 97d2fb
      const char *check = dwfl_module_info (mod, NULL, NULL, NULL,
Packit Service 97d2fb
					    NULL, NULL, &file, NULL);
Packit Service 97d2fb
      if (check == NULL || strcmp (check, name) != 0 || file == NULL)
Packit Service 97d2fb
	return DWARF_CB_OK;
Packit Service 97d2fb
Packit Service 97d2fb
      name = file;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  for (char **p = info->patterns; *p != NULL; ++p)
Packit Service 97d2fb
    if (fnmatch (*p, name, 0) == 0)
Packit Service 97d2fb
      goto match;
Packit Service 97d2fb
Packit Service 97d2fb
  return DWARF_CB_OK;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Handle files opened implicitly via libdwfl.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
handle_implicit_modules (const struct arg_info *info)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct match_module_info mmi = { info->args, NULL, info->match_files };
Packit Service 97d2fb
  inline ptrdiff_t next (ptrdiff_t offset)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      return dwfl_getmodules (info->dwfl, &match_module, &mmi, offset);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  ptrdiff_t offset = next (0);
Packit Service 97d2fb
  if (offset == 0)
Packit Service 97d2fb
    error (EXIT_FAILURE, 0, _("no matching modules found"));
Packit Service 97d2fb
Packit Service 97d2fb
  if (info->list)
Packit Service 97d2fb
    do
Packit Service 97d2fb
      list_module (mmi.found);
Packit Service 97d2fb
    while ((offset = next (offset)) > 0);
Packit Service 97d2fb
  else if (info->output_dir == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (next (offset) != 0)
Packit Service 97d2fb
	error (EXIT_FAILURE, 0, _("matched more than one module"));
Packit Service 97d2fb
      handle_dwfl_module (info->output_file, false, info->force, mmi.found,
Packit Service 97d2fb
			  info->all, info->ignore, info->relocate);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    do
Packit Service 97d2fb
      handle_output_dir_module (info->output_dir, mmi.found, info->force,
Packit Service 97d2fb
				info->all, info->ignore,
Packit Service 97d2fb
				info->modnames, info->relocate);
Packit Service 97d2fb
    while ((offset = next (offset)) > 0);
Packit Service 97d2fb
}
Packit Service 97d2fb

Packit Service 97d2fb
int
Packit Service 97d2fb
main (int argc, char **argv)
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
  const struct argp_child argp_children[] =
Packit Service 97d2fb
    {
Packit Service 97d2fb
      {
Packit Service 97d2fb
	.argp = dwfl_standard_argp (),
Packit Service 97d2fb
	.header = N_("Input selection options:"),
Packit Service 97d2fb
	.group = 1,
Packit Service 97d2fb
      },
Packit Service 97d2fb
      { .argp = NULL },
Packit Service 97d2fb
    };
Packit Service 97d2fb
  const struct argp argp =
Packit Service 97d2fb
    {
Packit Service 97d2fb
      .options = options,
Packit Service 97d2fb
      .parser = parse_opt,
Packit Service 97d2fb
      .children = argp_children,
Packit Service 97d2fb
      .args_doc = N_("STRIPPED-FILE DEBUG-FILE\n[MODULE...]"),
Packit Service 97d2fb
      .doc = N_("\
Packit Service 97d2fb
Combine stripped files with separate symbols and debug information.\n\
Packit Service 97d2fb
\n\
Packit Service 97d2fb
The first form puts the result in DEBUG-FILE if -o was not given.\n\
Packit Service 97d2fb
\n\
Packit Service 97d2fb
MODULE arguments give file name patterns matching modules to process.\n\
Packit Service 97d2fb
With -f these match the file name of the main (stripped) file \
Packit Service 97d2fb
(slashes are never special), otherwise they match the simple module names.  \
Packit Service 97d2fb
With no arguments, process all modules found.\n\
Packit Service 97d2fb
\n\
Packit Service 97d2fb
Multiple modules are written to files under OUTPUT-DIRECTORY, \
Packit Service 97d2fb
creating subdirectories as needed.  \
Packit Service 97d2fb
With -m these files have simple module names, otherwise they have the \
Packit Service 97d2fb
name of the main file complete with directory underneath OUTPUT-DIRECTORY.\n\
Packit Service 97d2fb
\n\
Packit Service 97d2fb
With -n no files are written, but one line to standard output for each module:\
Packit Service 97d2fb
\n\tSTART+SIZE BUILDID FILE DEBUGFILE MODULENAME\n\
Packit Service 97d2fb
START and SIZE are hexadecimal giving the address bounds of the module.  \
Packit Service 97d2fb
BUILDID is hexadecimal for the build ID bits, or - if no ID is known; \
Packit Service 97d2fb
the hexadecimal may be followed by @0xADDR giving the address where the \
Packit Service 97d2fb
ID resides if that is known.  \
Packit Service 97d2fb
FILE is the file name found for the module, or - if none was found, \
Packit Service 97d2fb
or . if an ELF image is available but not from any named file.  \
Packit Service 97d2fb
DEBUGFILE is the separate debuginfo file name, \
Packit Service 97d2fb
or - if no debuginfo was found, or . if FILE contains the debug information.\
Packit Service 97d2fb
")
Packit Service 97d2fb
    };
Packit Service 97d2fb
Packit Service 97d2fb
  int remaining;
Packit Service 97d2fb
  struct arg_info info = { .args = NULL };
Packit Service 97d2fb
  error_t result = argp_parse (&argp, argc, argv, 0, &remaining, &info;;
Packit Service 97d2fb
  if (result == ENOSYS)
Packit Service 97d2fb
    assert (info.dwfl == NULL);
Packit Service 97d2fb
  else if (result)
Packit Service 97d2fb
    return EXIT_FAILURE;
Packit Service 97d2fb
  assert (info.args != NULL);
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 (info.dwfl == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      assert (result == ENOSYS);
Packit Service 97d2fb
Packit Service 97d2fb
      if (info.output_dir != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  char *file;
Packit Service 97d2fb
	  if (asprintf (&file, "%s/%s", info.output_dir, info.args[0]) < 0)
Packit Service 97d2fb
	    error (EXIT_FAILURE, 0, _("memory exhausted"));
Packit Service 97d2fb
	  handle_explicit_files (file, true, info.force,
Packit Service 97d2fb
				 info.args[0], info.args[1]);
Packit Service 97d2fb
	  free (file);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	handle_explicit_files (info.output_file, false, info.force,
Packit Service 97d2fb
			       info.args[0], info.args[1]);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* parse_opt checked this.  */
Packit Service 97d2fb
      assert (info.output_file != NULL || info.output_dir != NULL || info.list);
Packit Service 97d2fb
Packit Service 97d2fb
      handle_implicit_modules (&info;;
Packit Service 97d2fb
Packit Service 97d2fb
      dwfl_end (info.dwfl);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
#include "debugpred.h"