15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Combine stripped files with separate symbols and debug information.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   Copyright (C) 2007-2012 Red Hat, Inc.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   This file is part of Red Hat elfutils.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   Written by Roland McGrath <roland@redhat.com>, 2007.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   Red Hat elfutils is free software; you can redistribute it and/or modify
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   it under the terms of the GNU General Public License as published by the
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   Free Software Foundation; version 2 of the License.
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   Red Hat elfutils is distributed in the hope that it will be useful, but
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   WITHOUT ANY WARRANTY; without even the implied warranty of
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch   General Public License for more details.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   You should have received a copy of the GNU General Public License along
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   with Red Hat elfutils; if not, write to the Free Software Foundation,
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   Red Hat elfutils is an included package of the Open Invention Network.
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)   An included package of the Open Invention Network is a package for which
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)   Open Invention Network licensees cross-license their patents.  No patent
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)   license is granted, either expressly or impliedly, by designation as an
23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch   included package.  Should you wish to participate in the Open Invention
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   Network licensing program, please visit www.openinventionnetwork.com
257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch   <http://www.openinventionnetwork.com>.  */
26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* TODO:
28ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
29ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  * SHX_XINDEX
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  * prelink vs .debug_* linked addresses
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch */
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_CONFIG_H
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# include <config.h>
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <argp.h>
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <assert.h>
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <error.h>
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h>
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <fnmatch.h>
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <libintl.h>
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <locale.h>
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <mcheck.h>
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdbool.h>
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio_ext.h>
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <inttypes.h>
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h>
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sys/stat.h>
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gelf.h>
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <libebl.h>
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <libdwfl.h>
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "system.h"
61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef _
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define _(str) gettext (str)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/* Name and version of program.  */
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic void print_version (FILE *stream, struct argp_state *state);
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Bug report address.  */
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Definitions of arguments for argp functions.  */
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const struct argp_option options[] =
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Group 2 will follow group 1 from dwfl_standard_argp.  */
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { "match-file-names", 'f', NULL, 0,
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    N_("Match MODULE against file names, not module names"), 2 },
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { "ignore-missing", 'i', NULL, 0, N_("Silently skip unfindable files"), 0 },
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { NULL, 0, NULL, 0, N_("Output options:"), 0 },
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { "output", 'o', "FILE", 0, N_("Place output into FILE"), 0 },
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { "output-directory", 'd', "DIRECTORY",
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    0, N_("Create multiple output files under DIRECTORY"), 0 },
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { "module-names", 'm', NULL, 0, N_("Use module rather than file names"), 0 },
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { "all", 'a', NULL, 0,
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    N_("Create output for modules that have no separate debug information"),
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    0 },
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { "relocate", 'R', NULL, 0,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    N_("Apply relocations to section contents in ET_REL files"), 0 },
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { "list-only", 'n', NULL, 0,
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    N_("Only list module and file names, build IDs"), 0 },
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { NULL, 0, NULL, 0, NULL, 0 }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct arg_info
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *output_file;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *output_dir;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Dwfl *dwfl;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char **args;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool list;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool all;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ignore;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool modnames;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool match_files;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool relocate;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Handle program arguments.  */
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static error_t
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)parse_opt (int key, char *arg, struct argp_state *state)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct arg_info *info = state->input;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (key)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ARGP_KEY_INIT:
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      state->child_inputs[0] = &info->dwfl;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'o':
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (info->output_file != NULL)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	{
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  argp_error (state, _("-o option specified twice"));
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  return EINVAL;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info->output_file = arg;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'd':
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (info->output_dir != NULL)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	{
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  argp_error (state, _("-d option specified twice"));
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  return EINVAL;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info->output_dir = arg;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'm':
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info->modnames = true;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'f':
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info->match_files = true;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'a':
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info->all = true;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'i':
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info->ignore = true;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'n':
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info->list = true;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 'R':
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info->relocate = true;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ARGP_KEY_ARGS:
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ARGP_KEY_NO_ARGS:
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* We "consume" all the arguments here.  */
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info->args = &state->argv[state->next];
163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (info->output_file != NULL && info->output_dir != NULL)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	{
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  argp_error (state, _("only one of -o or -d allowed"));
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  return EINVAL;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
169ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
170ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      if (info->list && (info->dwfl == NULL
171ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			 || info->output_dir != NULL
172ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			 || info->output_file != NULL))
173ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	{
174ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	  argp_error (state,
175ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		      _("-n cannot be used with explicit files or -o or -d"));
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  return EINVAL;
177ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
178ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
179ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      if (info->output_dir != NULL)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	{
181ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	  struct stat64 st;
182ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	  error_t fail = 0;
183ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	  if (stat64 (info->output_dir, &st) < 0)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    fail = errno;
185ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	  else if (!S_ISDIR (st.st_mode))
186ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	    fail = ENOTDIR;
187ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	  if (fail)
188ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	    {
189ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	      argp_failure (state, EXIT_FAILURE, fail,
190ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			    _("output directory '%s'"), info->output_dir);
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	      return fail;
192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	    }
193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	}
194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (info->dwfl == NULL)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	{
197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	  if (state->next + 2 != state->argc)
198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	    {
199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	      argp_error (state, _("exactly two file arguments are required"));
200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	      return EINVAL;
201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	    }
202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	  if (info->ignore || info->all || info->modnames || info->relocate)
204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	    {
205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	      argp_error (state, _("\
206ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch-m, -a, -R, and -i options not allowed with explicit files"));
207ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	      return EINVAL;
208ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	    }
209ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
210ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	  /* Bail out immediately to prevent dwfl_standard_argp's parser
211ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	     from defaulting to "-e a.out".  */
212ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	  return ENOSYS;
213ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
214ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      else if (info->output_file == NULL && info->output_dir == NULL
215ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	       && !info->list)
216ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	{
217ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	  argp_error (state,
218ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		      _("-o or -d is required when using implicit files"));
219ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	  return EINVAL;
220ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    default:
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return ARGP_ERR_UNKNOWN;
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return 0;
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Print the version information.  */
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fprintf (stream, "unstrip (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fprintf (stream, _("\
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Copyright (C) %s Red Hat, Inc.\n\
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This is free software; see the source for copying conditions.  There is NO\n\
237eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"), "2012");
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fprintf (stream, gettext ("Written by %s.\n"), "Roland McGrath");
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ELF_CHECK(call, msg)						      \
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do									      \
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {									      \
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!(call)) 							      \
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	error (EXIT_FAILURE, 0, msg, elf_errmsg (-1));			      \
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } while (0)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Copy INELF to newly-created OUTELF, exit via error for any problems.  */
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)copy_elf (Elf *outelf, Elf *inelf)
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ELF_CHECK (gelf_newehdr (outelf, gelf_getclass (inelf)),
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	     _("cannot create ELF header: %s"));
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GElf_Ehdr ehdr_mem;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GElf_Ehdr *ehdr = gelf_getehdr (inelf, &ehdr_mem);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ELF_CHECK (gelf_update_ehdr (outelf, ehdr),
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	     _("cannot copy ELF header: %s"));
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ehdr->e_phnum > 0)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ELF_CHECK (gelf_newphdr (outelf, ehdr->e_phnum),
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 _("cannot create program headers: %s"));
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GElf_Phdr phdr_mem;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ELF_CHECK (gelf_update_phdr (outelf, i,
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				     gelf_getphdr (inelf, i, &phdr_mem)),
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		   _("cannot copy program header: %s"));
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Elf_Scn *scn = NULL;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while ((scn = elf_nextscn (inelf, scn)) != NULL)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Elf_Scn *newscn = elf_newscn (outelf);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GElf_Shdr shdr_mem;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ELF_CHECK (gelf_update_shdr (newscn, gelf_getshdr (scn, &shdr_mem)),
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 _("cannot copy section header: %s"));
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Elf_Data *data = elf_getdata (scn, NULL);
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ELF_CHECK (data != NULL, _("cannot get section data: %s"));
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Elf_Data *newdata = elf_newdata (newscn);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ELF_CHECK (newdata != NULL, _("cannot copy section data: %s"));
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *newdata = *data;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elf_flagdata (newdata, ELF_C_SET, ELF_F_DIRTY);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Create directories containing PATH.  */
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)make_directories (const char *path)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *lastslash = strrchr (path, '/');
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (lastslash == NULL)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (lastslash > path && lastslash[-1] == '/')
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    --lastslash;
301eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (lastslash == path)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *dir = strndupa (path, lastslash - path);
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (mkdir (dir, 0777) < 0 && errno != EEXIST)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (errno == ENOENT)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      make_directories (dir);
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error (EXIT_FAILURE, errno, _("cannot create directory '%s'"), dir);
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
312ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
313ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch/* The binutils linker leaves gratuitous section symbols in .symtab
314ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   that strip has to remove.  Older linkers likewise include a
315ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   symbol for every section, even unallocated ones, in .dynsym.
316ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   Because of this, the related sections can shrink in the stripped
317ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   file from their original size.  Older versions of strip do not
318ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   adjust the sh_size field in the debuginfo file's SHT_NOBITS
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   version of the section header, so it can appear larger.  */
320ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic bool
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)section_can_shrink (const GElf_Shdr *shdr)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  switch (shdr->sh_type)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SHT_SYMTAB:
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SHT_DYNSYM:
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SHT_HASH:
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SHT_GNU_versym:
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* See if this symbol table has a leading section symbol for every single
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   section, in order.  The binutils linker produces this.  While we're here,
336eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch   update each section symbol's st_value.  */
337eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic size_t
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)symtab_count_leading_section_symbols (Elf *elf, Elf_Scn *scn, size_t shnum,
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				      Elf_Data *newsymdata)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Elf_Data *data = elf_getdata (scn, NULL);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Elf_Data *shndxdata = NULL;	/* XXX */
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
344eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 1; i < shnum; ++i)
345eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    {
346eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      GElf_Sym sym_mem;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GElf_Word shndx = SHN_UNDEF;
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GElf_Sym *sym = gelf_getsymshndx (data, shndxdata, i, &sym_mem, &shndx);
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ELF_CHECK (sym != NULL, _("cannot get symbol table entry: %s"));
350ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
351ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      GElf_Shdr shdr_mem;
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, i), &shdr_mem);
353eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (sym->st_shndx != SHN_XINDEX)
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	shndx = sym->st_shndx;
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (shndx != i || GELF_ST_TYPE (sym->st_info) != STT_SECTION)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return i;
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
361eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      sym->st_value = shdr->sh_addr;
362eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (sym->st_shndx != SHN_XINDEX)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	shndx = SHN_UNDEF;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ELF_CHECK (gelf_update_symshndx (newsymdata, shndxdata, i, sym, shndx),
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 _("cannot update symbol table: %s"));
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return shnum;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
371eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic void
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)update_shdr (Elf_Scn *outscn, GElf_Shdr *newshdr)
373eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
374ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  ELF_CHECK (gelf_update_shdr (outscn, newshdr),
375ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	     _("cannot update section header: %s"));
376ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
378eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/* We expanded the output section, so update its header.  */
379eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic void
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)update_sh_size (Elf_Scn *outscn, const Elf_Data *data)
381ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GElf_Shdr shdr_mem;
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GElf_Shdr *newshdr = gelf_getshdr (outscn, &shdr_mem);
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ELF_CHECK (newshdr != NULL, _("cannot get section header: %s"));
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  newshdr->sh_size = data->d_size;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  update_shdr (outscn, newshdr);
389ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Update relocation sections using the symbol table.  */
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	       size_t map[], const GElf_Shdr *symshdr)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Elf_Data *data = elf_getdata (outscn, NULL);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  inline void adjust_reloc (GElf_Xword *info)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size_t ndx = GELF_R_SYM (*info);
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (ndx != STN_UNDEF)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	*info = GELF_R_INFO (map[ndx - 1], GELF_R_TYPE (*info));
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (shdr->sh_type)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SHT_REL:
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i)
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	{
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  GElf_Rel rel_mem;
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  GElf_Rel *rel = gelf_getrel (data, i, &rel_mem);
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  adjust_reloc (&rel->r_info);
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  ELF_CHECK (gelf_update_rel (data, i, rel),
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		     _("cannot update relocation: %s"));
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case SHT_RELA:
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i)
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	{
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	  GElf_Rela rela_mem;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  GElf_Rela *rela = gelf_getrela (data, i, &rela_mem);
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  adjust_reloc (&rela->r_info);
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  ELF_CHECK (gelf_update_rela (data, i, rela),
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		     _("cannot update relocation: %s"));
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SHT_GROUP:
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	GElf_Shdr shdr_mem;
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	GElf_Shdr *newshdr = gelf_getshdr (outscn, &shdr_mem);
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	ELF_CHECK (newshdr != NULL, _("cannot get section header: %s"));
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	if (newshdr->sh_info != STN_UNDEF)
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	  {
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    newshdr->sh_info = map[newshdr->sh_info - 1];
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    update_shdr (outscn, newshdr);
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  }
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	break;
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SHT_HASH:
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* We must expand the table and rejigger its contents.  */
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	const size_t nsym = symshdr->sh_size / symshdr->sh_entsize;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	const size_t onent = shdr->sh_size / shdr->sh_entsize;
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	assert (data->d_size == shdr->sh_size);
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CONVERT_HASH(Hash_Word)						      \
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	{								      \
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  const Hash_Word *const old_hash = data->d_buf;		      \
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  const size_t nbucket = old_hash[0];				      \
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  const size_t nchain = old_hash[1];				      \
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  const Hash_Word *const old_bucket = &old_hash[2];		      \
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  const Hash_Word *const old_chain = &old_bucket[nbucket];	      \
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  assert (onent == 2 + nbucket + nchain);			      \
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)									      \
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  const size_t nent = 2 + nbucket + nsym;			      \
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  Hash_Word *const new_hash = xcalloc (nent, sizeof new_hash[0]);     \
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  Hash_Word *const new_bucket = &new_hash[2];			      \
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  Hash_Word *const new_chain = &new_bucket[nbucket];		      \
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)									      \
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  new_hash[0] = nbucket;					      \
464eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	  new_hash[1] = nsym;						      \
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  for (size_t i = 0; i < nbucket; ++i)				      \
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    if (old_bucket[i] != STN_UNDEF)				      \
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	      new_bucket[i] = map[old_bucket[i] - 1];			      \
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)									      \
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  for (size_t i = 1; i < nchain; ++i)				      \
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    if (old_chain[i] != STN_UNDEF)				      \
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	      new_chain[map[i - 1]] = map[old_chain[i] - 1];		      \
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)									      \
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  data->d_buf = new_hash;					      \
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  data->d_size = nent * sizeof new_hash[0];			      \
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	switch (shdr->sh_entsize)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  {
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  case 4:
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    CONVERT_HASH (Elf32_Word);
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    break;
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  case 8:
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    CONVERT_HASH (Elf64_Xword);
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    break;
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  default:
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    abort ();
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  }
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY);
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	update_sh_size (outscn, data);
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef	CONVERT_HASH
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SHT_GNU_versym:
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* We must expand the table and move its elements around.  */
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	const size_t nent = symshdr->sh_size / symshdr->sh_entsize;
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	const size_t onent = shdr->sh_size / shdr->sh_entsize;
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	assert (nent >= onent);
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* We don't bother using gelf_update_versym because there is
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	   really no conversion to be done.  */
505eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	assert (sizeof (Elf32_Versym) == sizeof (GElf_Versym));
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	assert (sizeof (Elf64_Versym) == sizeof (GElf_Versym));
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	GElf_Versym *versym = xcalloc (nent, sizeof versym[0]);
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (size_t i = 1; i < onent; ++i)
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  {
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    GElf_Versym *v = gelf_getversym (data, i, &versym[map[i - 1]]);
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    ELF_CHECK (v != NULL, _("cannot get symbol version: %s"));
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  }
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	data->d_buf = versym;
516eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	data->d_size = nent * shdr->sh_entsize;
517eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY);
518eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	update_sh_size (outscn, data);
519eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
520eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
521eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error (EXIT_FAILURE, 0,
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	     _("unexpected section type in [%Zu] with sh_link to symtab"),
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	     elf_ndxscn (inscn));
526eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
527eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
528eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
529eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/* Adjust all the relocation sections in the file.  */
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void
531eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochadjust_all_relocs (Elf *elf, Elf_Scn *symtab, const GElf_Shdr *symshdr,
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		   size_t map[])
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
534eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  size_t new_sh_link = elf_ndxscn (symtab);
535eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Elf_Scn *scn = NULL;
536eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  while ((scn = elf_nextscn (elf, scn)) != NULL)
537eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (scn != symtab)
538eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      {
539ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	GElf_Shdr shdr_mem;
540ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
541ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
542ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (shdr->sh_type != SHT_NOBITS && shdr->sh_link == new_sh_link)
543ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	  adjust_relocs (scn, scn, shdr, map, symshdr);
544ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      }
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* The original file probably had section symbols for all of its
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   sections, even the unallocated ones.  To match it as closely as
5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   possible, add in section symbols for the added sections.  */
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static Elf_Data *
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)add_new_section_symbols (Elf_Scn *old_symscn, size_t old_shnum,
5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			 Elf *elf, bool rel, Elf_Scn *symscn, size_t shnum)
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const size_t added = shnum - old_shnum;
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GElf_Shdr shdr_mem;
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GElf_Shdr *shdr = gelf_getshdr (symscn, &shdr_mem);
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const size_t nsym = shdr->sh_size / shdr->sh_entsize;
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t symndx_map[nsym - 1];
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  shdr->sh_info += added;
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  shdr->sh_size += added * shdr->sh_entsize;
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  update_shdr (symscn, shdr);
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Elf_Data *symdata = elf_getdata (symscn, NULL);
568eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Elf_Data *shndxdata = NULL;	/* XXX */
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  symdata->d_size = shdr->sh_size;
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  symdata->d_buf = xmalloc (symdata->d_size);
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  /* Copy the existing section symbols.  */
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Elf_Data *old_symdata = elf_getdata (old_symscn, NULL);
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < old_shnum; ++i)
576eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    {
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GElf_Sym sym_mem;
578eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      GElf_Word shndx = SHN_UNDEF;
5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GElf_Sym *sym = gelf_getsymshndx (old_symdata, shndxdata,
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)					i, &sym_mem, &shndx);
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, i,
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)				       sym, shndx),
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		 _("cannot update symbol table: %s"));
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (i > 0)
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	symndx_map[i - 1] = i;
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  /* Add in the new section symbols.  */
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = old_shnum; i < shnum; ++i)
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    {
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GElf_Shdr i_shdr_mem;
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GElf_Shdr *i_shdr = gelf_getshdr (elf_getscn (elf, i), &i_shdr_mem);
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ELF_CHECK (i_shdr != NULL, _("cannot get section header: %s"));
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GElf_Sym sym =
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	{
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	  .st_value = rel ? 0 : i_shdr->sh_addr,
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	  .st_info = GELF_ST_INFO (STB_LOCAL, STT_SECTION),
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	  .st_shndx = i < SHN_LORESERVE ? i : SHN_XINDEX
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	};
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GElf_Word shndx = i < SHN_LORESERVE ? SHN_UNDEF : i;
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, i,
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)				       &sym, shndx),
6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		 _("cannot update symbol table: %s"));
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Now copy the rest of the existing symbols.  */
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = old_shnum; i < nsym; ++i)
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GElf_Sym sym_mem;
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GElf_Word shndx = SHN_UNDEF;
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GElf_Sym *sym = gelf_getsymshndx (old_symdata, shndxdata,
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					i, &sym_mem, &shndx);
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ELF_CHECK (gelf_update_symshndx (symdata, shndxdata,
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				       i + added, sym, shndx),
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 _("cannot update symbol table: %s"));
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      symndx_map[i - 1] = i + added;
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
621eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  /* Adjust any relocations referring to the old symbol table.  */
622eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  adjust_all_relocs (elf, symscn, shdr, symndx_map);
623eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
624eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return symdata;
625eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
626eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
627eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/* This has the side effect of updating STT_SECTION symbols' values,
628eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch   in case of prelink adjustments.  */
629eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic Elf_Data *
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)check_symtab_section_symbols (Elf *elf, bool rel, Elf_Scn *scn,
631eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			      size_t shnum, size_t shstrndx,
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			      Elf_Scn *oscn, size_t oshnum, size_t oshstrndx,
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			      size_t debuglink)
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t n = symtab_count_leading_section_symbols (elf, oscn, oshnum,
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)						   elf_getdata (scn, NULL));
637eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
638eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (n == oshnum)
639eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return add_new_section_symbols (oscn, n, elf, rel, scn, shnum);
640eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
641eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (n == oshstrndx || (n == debuglink && n == oshstrndx - 1))
642eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return add_new_section_symbols (oscn, n, elf, rel, scn, shstrndx);
643eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
644eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return NULL;
645eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
646eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
647eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstruct section
648eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
649eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Elf_Scn *scn;
650eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const char *name;
651eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Elf_Scn *outscn;
652eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  struct Ebl_Strent *strent;
653eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  GElf_Shdr shdr;
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
655eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
656eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int
657eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochcompare_alloc_sections (const struct section *s1, const struct section *s2,
658eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			bool rel)
659eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!rel)
661eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    {
662eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      /* Sort by address.  */
663eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (s1->shdr.sh_addr < s2->shdr.sh_addr)
664eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return -1;
665eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (s1->shdr.sh_addr > s2->shdr.sh_addr)
666eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return 1;
667eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
668eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
669eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  /* At the same address, preserve original section order.  */
670eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return (ssize_t) elf_ndxscn (s1->scn) - (ssize_t) elf_ndxscn (s2->scn);
671eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
672eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
6732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static int
674eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochcompare_unalloc_sections (const GElf_Shdr *shdr1, const GElf_Shdr *shdr2,
675eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			  const char *name1, const char *name2)
676eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
677eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  /* Sort by sh_flags as an arbitrary ordering.  */
678eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (shdr1->sh_flags < shdr2->sh_flags)
679eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return -1;
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (shdr1->sh_flags > shdr2->sh_flags)
681eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return 1;
682eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
683eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  /* Sort by name as last resort.  */
684eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return strcmp (name1, name2);
685eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
686eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int
688eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochcompare_sections (const void *a, const void *b, bool rel)
6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const struct section *s1 = a;
691eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const struct section *s2 = b;
6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  /* Sort all non-allocated sections last.  */
6942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if ((s1->shdr.sh_flags ^ s2->shdr.sh_flags) & SHF_ALLOC)
6952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return (s1->shdr.sh_flags & SHF_ALLOC) ? -1 : 1;
6962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ((s1->shdr.sh_flags & SHF_ALLOC)
6982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	  ? compare_alloc_sections (s1, s2, rel)
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  : compare_unalloc_sections (&s1->shdr, &s2->shdr,
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				      s1->name, s2->name));
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static int
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)compare_sections_rel (const void *a, const void *b)
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
7062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return compare_sections (a, b, true);
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)compare_sections_nonrel (const void *a, const void *b)
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return compare_sections (a, b, false);
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct symbol
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t *map;
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  union
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char *name;
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct Ebl_Strent *strent;
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  union
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GElf_Addr value;
730eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      GElf_Xword size;
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GElf_Word shndx;
732eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      union
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct
7357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	{
7367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	  uint8_t info;
7377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	  uint8_t other;
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	} info;
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int16_t compare;
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      };
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    };
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* For a symbol discarded after first sort, this matches its better's
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       map pointer.  */
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t *duplicate;
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Collect input symbols into our internal form.  */
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)collect_symbols (Elf *outelf, bool rel, Elf_Scn *symscn, Elf_Scn *strscn,
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 const size_t nent, const GElf_Addr bias,
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 const size_t scnmap[], struct symbol *table, size_t *map,
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 struct section *split_bss)
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Elf_Data *symdata = elf_getdata (symscn, NULL);
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Elf_Data *strdata = elf_getdata (strscn, NULL);
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Elf_Data *shndxdata = NULL;	/* XXX */
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 1; i < nent; ++i)
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GElf_Sym sym_mem;
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GElf_Word shndx = SHN_UNDEF;
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GElf_Sym *sym = gelf_getsymshndx (symdata, shndxdata, i,
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					&sym_mem, &shndx);
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ELF_CHECK (sym != NULL, _("cannot get symbol table entry: %s"));
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (sym->st_shndx != SHN_XINDEX)
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	shndx = sym->st_shndx;
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (sym->st_name >= strdata->d_size)
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	error (EXIT_FAILURE, 0,
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	       _("invalid string offset in symbol [%Zu]"), i);
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      struct symbol *s = &table[i - 1];
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      s->map = &map[i - 1];
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      s->name = strdata->d_buf + sym->st_name;
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      s->value = sym->st_value + bias;
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      s->size = sym->st_size;
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      s->shndx = shndx;
780eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      s->info.info = sym->st_info;
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      s->info.other = sym->st_other;
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
783eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (scnmap != NULL && shndx != SHN_UNDEF && shndx < SHN_LORESERVE)
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	s->shndx = scnmap[shndx - 1];
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (GELF_ST_TYPE (s->info.info) == STT_SECTION && !rel)
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	{
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  /* Update the value to match the output section.  */
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  GElf_Shdr shdr_mem;
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  GElf_Shdr *shdr = gelf_getshdr (elf_getscn (outelf, s->shndx),
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					  &shdr_mem);
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  s->value = shdr->sh_addr;
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else if (split_bss != NULL
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	       && s->value < split_bss->shdr.sh_addr
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	       && s->value >= split_bss[-1].shdr.sh_addr
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	       && shndx == elf_ndxscn (split_bss->outscn))
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* This symbol was in .bss and was split into .dynbss.  */
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	s->shndx = elf_ndxscn (split_bss[-1].outscn);
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CMP(value)							      \
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (s1->value < s2->value)						      \
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;								      \
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (s1->value > s2->value)						      \
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Compare symbols with a consistent ordering,
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   but one only meaningful for equality.  */
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)compare_symbols (const void *a, const void *b)
8152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const struct symbol *s1 = a;
817eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const struct symbol *s2 = b;
818eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
819eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CMP (value);
820eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CMP (size);
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CMP (shndx);
822eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
823ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return (s1->compare - s2->compare) ?: strcmp (s1->name, s2->name);
824ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
825eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
826eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/* Compare symbols for output order after slots have been assigned.  */
827eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int
828eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochcompare_symbols_output (const void *a, const void *b)
829ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
830ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  const struct symbol *s1 = a;
831eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const struct symbol *s2 = b;
832eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int cmp;
833eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
834ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /* Sort discarded symbols last.  */
835ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  cmp = (s1->name == NULL) - (s2->name == NULL);
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cmp == 0)
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* Local symbols must come first.  */
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmp = ((GELF_ST_BIND (s2->info.info) == STB_LOCAL)
840eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	   - (GELF_ST_BIND (s1->info.info) == STB_LOCAL));
841ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
842ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (cmp == 0)
843ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* binutils always puts section symbols first.  */
844ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    cmp = ((GELF_ST_TYPE (s2->info.info) == STT_SECTION)
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	   - (GELF_ST_TYPE (s1->info.info) == STT_SECTION));
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (cmp == 0)
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
849eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (GELF_ST_TYPE (s1->info.info) == STT_SECTION)
850eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	{
851eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	  /* binutils always puts section symbols in section index order.  */
852eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	  CMP (shndx);
853eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	  else
854eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	    assert (s1 == s2);
855eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	}
856eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
857eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      /* Nothing really matters, so preserve the original order.  */
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CMP (map);
859eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      else
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	assert (s1 == s2);
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return cmp;
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef CMP
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Return true iff the flags, size, and name match.  */
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sections_match (const struct section *sections, size_t i,
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		const GElf_Shdr *shdr, const char *name)
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (sections[i].shdr.sh_flags == shdr->sh_flags
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  && (sections[i].shdr.sh_size == shdr->sh_size
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	      || (sections[i].shdr.sh_size < shdr->sh_size
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		  && section_can_shrink (&sections[i].shdr)))
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  && !strcmp (sections[i].name, name));
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Locate a matching allocated section in SECTIONS.  */
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct section *
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)find_alloc_section (const GElf_Shdr *shdr, GElf_Addr bias, const char *name,
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    struct section sections[], size_t nalloc)
8842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const GElf_Addr addr = shdr->sh_addr + bias;
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t l = 0, u = nalloc;
887eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  while (l < u)
888eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    {
889eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      size_t i = (l + u) / 2;
890eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (addr < sections[i].shdr.sh_addr)
891eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	u = i;
8927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      else if (addr > sections[i].shdr.sh_addr)
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	l = i + 1;
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	{
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  /* We've found allocated sections with this address.
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	     Find one with matching size, flags, and name.  */
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  while (i > 0 && sections[i - 1].shdr.sh_addr == addr)
899eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	    --i;
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  for (; i < nalloc && sections[i].shdr.sh_addr == addr;
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	       ++i)
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    if (sections_match (sections, i, shdr, name))
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	      return &sections[i];
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  break;
905ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
906ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
908eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
909eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static inline const char *
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)get_section_name (size_t ndx, const GElf_Shdr *shdr, const Elf_Data *shstrtab)
912ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
913ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (shdr->sh_name >= shstrtab->d_size)
914ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    error (EXIT_FAILURE, 0, _("cannot read section [%Zu] name: %s"),
915ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	   ndx, elf_errmsg (-1));
916ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return shstrtab->d_buf + shdr->sh_name;
917ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
918ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
919ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch/* Fix things up when prelink has moved some allocated sections around
920ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   and the debuginfo file's section headers no longer match up.
921ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   This fills in SECTIONS[0..NALLOC-1].outscn or exits.
922ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   If there was a .bss section that was split into two sections
923ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   with the new one preceding it in sh_addr, we return that pointer.  */
924ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic struct section *
925ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochfind_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			     Elf *main, const GElf_Ehdr *main_ehdr,
927ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			     Elf_Data *main_shstrtab, GElf_Addr bias,
928ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			     struct section *sections,
929ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			     size_t nalloc, size_t nsections)
930ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
931eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  /* Clear assignments that might have been bogus.  */
932eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 0; i < nalloc; ++i)
933eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    sections[i].outscn = NULL;
934eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
935eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Elf_Scn *undo = NULL;
936eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = nalloc; i < nsections; ++i)
937eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    {
938eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      const struct section *sec = &sections[i];
939ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      if (sec->shdr.sh_type == SHT_PROGBITS
940ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	  && !(sec->shdr.sh_flags & SHF_ALLOC)
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  && !strcmp (sec->name, ".gnu.prelink_undo"))
942eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	{
943ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	  undo = sec->scn;
944ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	  break;
945ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
946ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
947ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
948eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  /* Find the original allocated sections before prelinking.  */
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct section *undo_sections = NULL;
950ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  size_t undo_nalloc = 0;
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (undo != NULL)
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Elf_Data *undodata = elf_rawdata (undo, NULL);
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ELF_CHECK (undodata != NULL,
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 _("cannot read '.gnu.prelink_undo' section: %s"));
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      union
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	Elf32_Ehdr e32;
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	Elf64_Ehdr e64;
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } ehdr;
962      Elf_Data dst =
963	{
964	  .d_buf = &ehdr,
965	  .d_size = sizeof ehdr,
966	  .d_type = ELF_T_EHDR,
967	  .d_version = EV_CURRENT
968	};
969      Elf_Data src = *undodata;
970      src.d_size = gelf_fsize (main, ELF_T_EHDR, 1, EV_CURRENT);
971      src.d_type = ELF_T_EHDR;
972      ELF_CHECK (gelf_xlatetom (main, &dst, &src,
973				main_ehdr->e_ident[EI_DATA]) != NULL,
974		 _("cannot read '.gnu.prelink_undo' section: %s"));
975
976      uint_fast16_t phnum;
977      uint_fast16_t shnum;
978      if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
979	{
980	  phnum = ehdr.e32.e_phnum;
981	  shnum = ehdr.e32.e_shnum;
982	}
983      else
984	{
985	  phnum = ehdr.e64.e_phnum;
986	  shnum = ehdr.e64.e_shnum;
987	}
988
989      size_t phsize = gelf_fsize (main, ELF_T_PHDR, phnum, EV_CURRENT);
990      src.d_buf += src.d_size + phsize;
991      src.d_size = gelf_fsize (main, ELF_T_SHDR, shnum - 1, EV_CURRENT);
992      src.d_type = ELF_T_SHDR;
993      if ((size_t) (src.d_buf - undodata->d_buf) > undodata->d_size
994	  || undodata->d_size - (src.d_buf - undodata->d_buf) != src.d_size)
995	error (EXIT_FAILURE, 0, _("invalid contents in '%s' section"),
996	       ".gnu.prelink_undo");
997
998      union
999      {
1000	Elf32_Shdr s32[shnum - 1];
1001	Elf64_Shdr s64[shnum - 1];
1002      } shdr;
1003      dst.d_buf = &shdr;
1004      dst.d_size = sizeof shdr;
1005      ELF_CHECK (gelf_xlatetom (main, &dst, &src,
1006				main_ehdr->e_ident[EI_DATA]) != NULL,
1007		 _("cannot read '.gnu.prelink_undo' section: %s"));
1008
1009      undo_sections = xmalloc ((shnum - 1) * sizeof undo_sections[0]);
1010      for (size_t i = 0; i < shnum - 1; ++i)
1011	{
1012	  struct section *sec = &undo_sections[undo_nalloc];
1013	  if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
1014	    {
1015#define COPY(field) sec->shdr.field = shdr.s32[i].field
1016	      COPY (sh_name);
1017	      COPY (sh_type);
1018	      COPY (sh_flags);
1019	      COPY (sh_addr);
1020	      COPY (sh_offset);
1021	      COPY (sh_size);
1022	      COPY (sh_link);
1023	      COPY (sh_info);
1024	      COPY (sh_addralign);
1025	      COPY (sh_entsize);
1026#undef	COPY
1027	    }
1028	  else
1029	    sec->shdr = shdr.s64[i];
1030	  if (sec->shdr.sh_flags & SHF_ALLOC)
1031	    {
1032	      sec->shdr.sh_addr += bias;
1033	      sec->name = get_section_name (i + 1, &sec->shdr, main_shstrtab);
1034	      sec->scn = elf_getscn (main, i + 1); /* Really just for ndx.  */
1035	      sec->outscn = NULL;
1036	      sec->strent = NULL;
1037	      ++undo_nalloc;
1038	    }
1039	}
1040      qsort (undo_sections, undo_nalloc,
1041	     sizeof undo_sections[0], compare_sections_nonrel);
1042    }
1043
1044  bool fail = false;
1045  inline void check_match (bool match, Elf_Scn *scn, const char *name)
1046    {
1047      if (!match)
1048	{
1049	  fail = true;
1050	  error (0, 0, _("cannot find matching section for [%Zu] '%s'"),
1051		 elf_ndxscn (scn), name);
1052	}
1053    }
1054
1055  Elf_Scn *scn = NULL;
1056  while ((scn = elf_nextscn (debug, scn)) != NULL)
1057    {
1058      GElf_Shdr shdr_mem;
1059      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1060      ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1061
1062      if (!(shdr->sh_flags & SHF_ALLOC))
1063	continue;
1064
1065      const char *name = get_section_name (elf_ndxscn (scn), shdr,
1066					   debug_shstrtab);
1067
1068      if (undo_sections != NULL)
1069	{
1070	  struct section *sec = find_alloc_section (shdr, 0, name,
1071						    undo_sections,
1072						    undo_nalloc);
1073	  if (sec != NULL)
1074	    {
1075	      sec->outscn = scn;
1076	      continue;
1077	    }
1078	}
1079
1080      /* If there is no prelink info, we are just here to find
1081	 the sections to give error messages about.  */
1082      for (size_t i = 0; shdr != NULL && i < nalloc; ++i)
1083	if (sections[i].outscn == scn)
1084	  shdr = NULL;
1085      check_match (shdr == NULL, scn, name);
1086    }
1087
1088  if (fail)
1089    exit (EXIT_FAILURE);
1090
1091  /* Now we have lined up output sections for each of the original sections
1092     before prelinking.  Translate those to the prelinked sections.
1093     This matches what prelink's undo_sections does.  */
1094  struct section *split_bss = NULL;
1095  for (size_t i = 0; i < undo_nalloc; ++i)
1096    {
1097      const struct section *undo_sec = &undo_sections[i];
1098
1099      const char *name = undo_sec->name;
1100      scn = undo_sec->scn; /* This is just for elf_ndxscn.  */
1101
1102      for (size_t j = 0; j < nalloc; ++j)
1103	{
1104	  struct section *sec = &sections[j];
1105#define RELA_SCALED(field) \
1106	  (2 * sec->shdr.field == 3 * undo_sec->shdr.field)
1107	  if (sec->outscn == NULL
1108	      && sec->shdr.sh_name == undo_sec->shdr.sh_name
1109	      && sec->shdr.sh_flags == undo_sec->shdr.sh_flags
1110	      && sec->shdr.sh_addralign == undo_sec->shdr.sh_addralign
1111	      && (((sec->shdr.sh_type == undo_sec->shdr.sh_type
1112		    && sec->shdr.sh_entsize == undo_sec->shdr.sh_entsize
1113		    && (sec->shdr.sh_size == undo_sec->shdr.sh_size
1114			|| (sec->shdr.sh_size > undo_sec->shdr.sh_size
1115			    && main_ehdr->e_type == ET_EXEC
1116			    && !strcmp (sec->name, ".dynstr"))))
1117		   || (sec->shdr.sh_size == undo_sec->shdr.sh_size
1118		       && ((sec->shdr.sh_entsize == undo_sec->shdr.sh_entsize
1119			    && undo_sec->shdr.sh_type == SHT_NOBITS)
1120			   || undo_sec->shdr.sh_type == SHT_PROGBITS)
1121		       && !strcmp (sec->name, ".plt")))
1122		  || (sec->shdr.sh_type == SHT_RELA
1123		      && undo_sec->shdr.sh_type == SHT_REL
1124		      && RELA_SCALED (sh_entsize) && RELA_SCALED (sh_size))
1125		  || (sec->shdr.sh_entsize == undo_sec->shdr.sh_entsize
1126		      && (sec->shdr.sh_type == undo_sec->shdr.sh_type
1127			  || (sec->shdr.sh_type == SHT_PROGBITS
1128			      && undo_sec->shdr.sh_type == SHT_NOBITS))
1129		      && sec->shdr.sh_size < undo_sec->shdr.sh_size
1130		      && (!strcmp (sec->name, ".bss")
1131			  || !strcmp (sec->name, ".sbss"))
1132		      && (split_bss = sec) > sections)))
1133	    {
1134	      sec->outscn = undo_sec->outscn;
1135	      undo_sec = NULL;
1136	      break;
1137	    }
1138	}
1139
1140      check_match (undo_sec == NULL, scn, name);
1141    }
1142
1143  free (undo_sections);
1144
1145  if (fail)
1146    exit (EXIT_FAILURE);
1147
1148  return split_bss;
1149}
1150
1151/* Create new .shstrtab contents, subroutine of copy_elided_sections.
1152   This can't be open coded there and still use variable-length auto arrays,
1153   since the end of our block would free other VLAs too.  */
1154static Elf_Data *
1155new_shstrtab (Elf *unstripped, size_t unstripped_shnum,
1156	      Elf_Data *shstrtab, size_t unstripped_shstrndx,
1157	      struct section *sections, size_t stripped_shnum,
1158	      struct Ebl_Strtab *strtab)
1159{
1160  if (strtab == NULL)
1161    return NULL;
1162
1163  struct Ebl_Strent *unstripped_strent[unstripped_shnum - 1];
1164  memset (unstripped_strent, 0, sizeof unstripped_strent);
1165  for (struct section *sec = sections;
1166       sec < &sections[stripped_shnum - 1];
1167       ++sec)
1168    if (sec->outscn != NULL)
1169      {
1170	if (sec->strent == NULL)
1171	  {
1172	    sec->strent = ebl_strtabadd (strtab, sec->name, 0);
1173	    ELF_CHECK (sec->strent != NULL,
1174		       _("cannot add section name to string table: %s"));
1175	  }
1176	unstripped_strent[elf_ndxscn (sec->outscn) - 1] = sec->strent;
1177      }
1178
1179  /* Add names of sections we aren't touching.  */
1180  for (size_t i = 0; i < unstripped_shnum - 1; ++i)
1181    if (unstripped_strent[i] == NULL)
1182      {
1183	Elf_Scn *scn = elf_getscn (unstripped, i + 1);
1184	GElf_Shdr shdr_mem;
1185	GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1186	const char *name = get_section_name (i + 1, shdr, shstrtab);
1187	unstripped_strent[i] = ebl_strtabadd (strtab, name, 0);
1188	ELF_CHECK (unstripped_strent[i] != NULL,
1189		   _("cannot add section name to string table: %s"));
1190      }
1191    else
1192      unstripped_strent[i] = NULL;
1193
1194  /* Now finalize the string table so we can get offsets.  */
1195  Elf_Data *strtab_data = elf_getdata (elf_getscn (unstripped,
1196						   unstripped_shstrndx), NULL);
1197  ELF_CHECK (elf_flagdata (strtab_data, ELF_C_SET, ELF_F_DIRTY),
1198	     _("cannot update section header string table data: %s"));
1199  ebl_strtabfinalize (strtab, strtab_data);
1200
1201  /* Update the sh_name fields of sections we aren't modifying later.  */
1202  for (size_t i = 0; i < unstripped_shnum - 1; ++i)
1203    if (unstripped_strent[i] != NULL)
1204      {
1205	Elf_Scn *scn = elf_getscn (unstripped, i + 1);
1206	GElf_Shdr shdr_mem;
1207	GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1208	shdr->sh_name = ebl_strtaboffset (unstripped_strent[i]);
1209	if (i + 1 == unstripped_shstrndx)
1210	  shdr->sh_size = strtab_data->d_size;
1211	update_shdr (scn, shdr);
1212      }
1213
1214  return strtab_data;
1215}
1216
1217/* Fill in any SHT_NOBITS sections in UNSTRIPPED by
1218   copying their contents and sh_type from STRIPPED.  */
1219static void
1220copy_elided_sections (Elf *unstripped, Elf *stripped,
1221		      const GElf_Ehdr *stripped_ehdr, GElf_Addr bias)
1222{
1223  size_t unstripped_shstrndx;
1224  ELF_CHECK (elf_getshdrstrndx (unstripped, &unstripped_shstrndx) == 0,
1225	     _("cannot get section header string table section index: %s"));
1226
1227  size_t stripped_shstrndx;
1228  ELF_CHECK (elf_getshdrstrndx (stripped, &stripped_shstrndx) == 0,
1229	     _("cannot get section header string table section index: %s"));
1230
1231  size_t unstripped_shnum;
1232  ELF_CHECK (elf_getshdrnum (unstripped, &unstripped_shnum) == 0,
1233	     _("cannot get section count: %s"));
1234
1235  size_t stripped_shnum;
1236  ELF_CHECK (elf_getshdrnum (stripped, &stripped_shnum) == 0,
1237	     _("cannot get section count: %s"));
1238
1239  if (unlikely (stripped_shnum > unstripped_shnum))
1240    error (EXIT_FAILURE, 0, _("\
1241more sections in stripped file than debug file -- arguments reversed?"));
1242
1243  /* Cache the stripped file's section details.  */
1244  struct section sections[stripped_shnum - 1];
1245  Elf_Scn *scn = NULL;
1246  while ((scn = elf_nextscn (stripped, scn)) != NULL)
1247    {
1248      size_t i = elf_ndxscn (scn) - 1;
1249      GElf_Shdr *shdr = gelf_getshdr (scn, &sections[i].shdr);
1250      ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1251      sections[i].name = elf_strptr (stripped, stripped_shstrndx,
1252				     shdr->sh_name);
1253      if (sections[i].name == NULL)
1254	error (EXIT_FAILURE, 0, _("cannot read section [%Zu] name: %s"),
1255	       elf_ndxscn (scn), elf_errmsg (-1));
1256      sections[i].scn = scn;
1257      sections[i].outscn = NULL;
1258      sections[i].strent = NULL;
1259    }
1260
1261  const struct section *stripped_symtab = NULL;
1262
1263  /* Sort the sections, allocated by address and others after.  */
1264  qsort (sections, stripped_shnum - 1, sizeof sections[0],
1265	 stripped_ehdr->e_type == ET_REL
1266	 ? compare_sections_rel : compare_sections_nonrel);
1267  size_t nalloc = stripped_shnum - 1;
1268  while (nalloc > 0 && !(sections[nalloc - 1].shdr.sh_flags & SHF_ALLOC))
1269    {
1270      --nalloc;
1271      if (sections[nalloc].shdr.sh_type == SHT_SYMTAB)
1272	stripped_symtab = &sections[nalloc];
1273    }
1274
1275  /* Locate a matching unallocated section in SECTIONS.  */
1276  inline struct section *find_unalloc_section (const GElf_Shdr *shdr,
1277					       const char *name)
1278    {
1279      size_t l = nalloc, u = stripped_shnum - 1;
1280      while (l < u)
1281	{
1282	  size_t i = (l + u) / 2;
1283	  struct section *sec = &sections[i];
1284	  int cmp = compare_unalloc_sections (shdr, &sec->shdr,
1285					      name, sec->name);
1286	  if (cmp < 0)
1287	    u = i;
1288	  else if (cmp > 0)
1289	    l = i + 1;
1290	  else
1291	    return sec;
1292	}
1293      return NULL;
1294    }
1295
1296  Elf_Data *shstrtab = elf_getdata (elf_getscn (unstripped,
1297						unstripped_shstrndx), NULL);
1298  ELF_CHECK (shstrtab != NULL,
1299	     _("cannot read section header string table: %s"));
1300
1301  /* Match each debuginfo section with its corresponding stripped section.  */
1302  bool check_prelink = false;
1303  Elf_Scn *unstripped_symtab = NULL;
1304  size_t alloc_avail = 0;
1305  scn = NULL;
1306  while ((scn = elf_nextscn (unstripped, scn)) != NULL)
1307    {
1308      GElf_Shdr shdr_mem;
1309      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1310      ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1311
1312      if (shdr->sh_type == SHT_SYMTAB)
1313	{
1314	  unstripped_symtab = scn;
1315	  continue;
1316	}
1317
1318      const size_t ndx = elf_ndxscn (scn);
1319      if (ndx == unstripped_shstrndx)
1320	continue;
1321
1322      const char *name = get_section_name (ndx, shdr, shstrtab);
1323
1324      struct section *sec = NULL;
1325      if (shdr->sh_flags & SHF_ALLOC)
1326	{
1327	  if (stripped_ehdr->e_type != ET_REL)
1328	    {
1329	      /* Look for the section that matches.  */
1330	      sec = find_alloc_section (shdr, bias, name, sections, nalloc);
1331	      if (sec == NULL)
1332		{
1333		  /* We couldn't figure it out.  It may be a prelink issue.  */
1334		  check_prelink = true;
1335		  continue;
1336		}
1337	    }
1338	  else
1339	    {
1340	      /* The sh_addr of allocated sections does not help us,
1341		 but the order usually matches.  */
1342	      if (likely (sections_match (sections, alloc_avail, shdr, name)))
1343		sec = &sections[alloc_avail++];
1344	      else
1345		for (size_t i = alloc_avail + 1; i < nalloc; ++i)
1346		  if (sections_match (sections, i, shdr, name))
1347		    {
1348		      sec = &sections[i];
1349		      break;
1350		    }
1351	    }
1352	}
1353      else
1354	{
1355	  /* Look for the section that matches.  */
1356	  sec = find_unalloc_section (shdr, name);
1357	  if (sec == NULL)
1358	    {
1359	      /* An additional unallocated section is fine if not SHT_NOBITS.
1360		 We looked it up anyway in case it's an unallocated section
1361		 copied in both files (e.g. SHT_NOTE), and don't keep both.  */
1362	      if (shdr->sh_type != SHT_NOBITS)
1363		continue;
1364
1365	      /* Somehow some old .debug files wound up with SHT_NOBITS
1366		 .comment sections, so let those pass.  */
1367	      if (!strcmp (name, ".comment"))
1368		continue;
1369	    }
1370	}
1371
1372      if (sec == NULL)
1373	error (EXIT_FAILURE, 0,
1374	       _("cannot find matching section for [%Zu] '%s'"),
1375	       elf_ndxscn (scn), name);
1376
1377      sec->outscn = scn;
1378    }
1379
1380  /* If that failed due to changes made by prelink, we take another tack.
1381     We keep track of a .bss section that was partly split into .dynbss
1382     so that collect_symbols can update symbols' st_shndx fields.  */
1383  struct section *split_bss = NULL;
1384  if (check_prelink)
1385    {
1386      Elf_Data *data = elf_getdata (elf_getscn (stripped, stripped_shstrndx),
1387				    NULL);
1388      ELF_CHECK (data != NULL,
1389		 _("cannot read section header string table: %s"));
1390      split_bss = find_alloc_sections_prelink (unstripped, shstrtab,
1391					       stripped, stripped_ehdr,
1392					       data, bias, sections,
1393					       nalloc, stripped_shnum - 1);
1394    }
1395
1396  /* Make sure each main file section has a place to go.  */
1397  const struct section *stripped_dynsym = NULL;
1398  size_t debuglink = SHN_UNDEF;
1399  size_t ndx_section[stripped_shnum - 1];
1400  struct Ebl_Strtab *strtab = NULL;
1401  for (struct section *sec = sections;
1402       sec < &sections[stripped_shnum - 1];
1403       ++sec)
1404    {
1405      size_t secndx = elf_ndxscn (sec->scn);
1406
1407      if (sec->outscn == NULL)
1408	{
1409	  /* We didn't find any corresponding section for this.  */
1410
1411	  if (secndx == stripped_shstrndx)
1412	    {
1413	      /* We only need one .shstrtab.  */
1414	      ndx_section[secndx - 1] = unstripped_shstrndx;
1415	      continue;
1416	    }
1417
1418	  if (unstripped_symtab != NULL && sec == stripped_symtab)
1419	    {
1420	      /* We don't need a second symbol table.  */
1421	      ndx_section[secndx - 1] = elf_ndxscn (unstripped_symtab);
1422	      continue;
1423	    }
1424
1425	  if (unstripped_symtab != NULL && stripped_symtab != NULL
1426	      && secndx == stripped_symtab->shdr.sh_link)
1427	    {
1428	      /* ... nor its string table.  */
1429	      GElf_Shdr shdr_mem;
1430	      GElf_Shdr *shdr = gelf_getshdr (unstripped_symtab, &shdr_mem);
1431	      ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1432	      ndx_section[secndx - 1] = shdr->sh_link;
1433	      continue;
1434	    }
1435
1436	  if (!(sec->shdr.sh_flags & SHF_ALLOC)
1437	      && !strcmp (sec->name, ".gnu_debuglink"))
1438	    {
1439	      /* This was created by stripping.  We don't want it.  */
1440	      debuglink = secndx;
1441	      ndx_section[secndx - 1] = SHN_UNDEF;
1442	      continue;
1443	    }
1444
1445	  sec->outscn = elf_newscn (unstripped);
1446	  Elf_Data *newdata = elf_newdata (sec->outscn);
1447	  ELF_CHECK (newdata != NULL && gelf_update_shdr (sec->outscn,
1448							  &sec->shdr),
1449		     _("cannot add new section: %s"));
1450
1451	  if (strtab == NULL)
1452	    strtab = ebl_strtabinit (true);
1453	  sec->strent = ebl_strtabadd (strtab, sec->name, 0);
1454	  ELF_CHECK (sec->strent != NULL,
1455		     _("cannot add section name to string table: %s"));
1456	}
1457
1458      /* Cache the mapping of original section indices to output sections.  */
1459      ndx_section[secndx - 1] = elf_ndxscn (sec->outscn);
1460    }
1461
1462  /* We added some sections, so we need a new shstrtab.  */
1463  Elf_Data *strtab_data = new_shstrtab (unstripped, unstripped_shnum,
1464					shstrtab, unstripped_shstrndx,
1465					sections, stripped_shnum,
1466					strtab);
1467
1468  /* Get the updated section count.  */
1469  ELF_CHECK (elf_getshdrnum (unstripped, &unstripped_shnum) == 0,
1470	     _("cannot get section count: %s"));
1471
1472  bool placed[unstripped_shnum - 1];
1473  memset (placed, 0, sizeof placed);
1474
1475  /* Now update the output sections and copy in their data.  */
1476  GElf_Off offset = 0;
1477  for (const struct section *sec = sections;
1478       sec < &sections[stripped_shnum - 1];
1479       ++sec)
1480    if (sec->outscn != NULL)
1481      {
1482	GElf_Shdr shdr_mem;
1483	GElf_Shdr *shdr = gelf_getshdr (sec->outscn, &shdr_mem);
1484	ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1485
1486	/* In an ET_REL file under --relocate, the sh_addr of SHF_ALLOC
1487	   sections will have been set nonzero by relocation.  This
1488	   touched the shdrs of whichever file had the symtab.  sh_addr
1489	   is still zero in the corresponding shdr.  The relocated
1490	   address is what we want to use.  */
1491	if (stripped_ehdr->e_type != ET_REL
1492	    || !(shdr_mem.sh_flags & SHF_ALLOC)
1493	    || shdr_mem.sh_addr == 0)
1494	  shdr_mem.sh_addr = sec->shdr.sh_addr;
1495
1496	shdr_mem.sh_type = sec->shdr.sh_type;
1497	shdr_mem.sh_size = sec->shdr.sh_size;
1498	shdr_mem.sh_info = sec->shdr.sh_info;
1499	shdr_mem.sh_link = sec->shdr.sh_link;
1500	if (sec->shdr.sh_link != SHN_UNDEF)
1501	  shdr_mem.sh_link = ndx_section[sec->shdr.sh_link - 1];
1502	if (shdr_mem.sh_flags & SHF_INFO_LINK)
1503	  shdr_mem.sh_info = ndx_section[sec->shdr.sh_info - 1];
1504
1505	if (strtab != NULL)
1506	  shdr_mem.sh_name = ebl_strtaboffset (sec->strent);
1507
1508	Elf_Data *indata = elf_getdata (sec->scn, NULL);
1509	ELF_CHECK (indata != NULL, _("cannot get section data: %s"));
1510	Elf_Data *outdata = elf_getdata (sec->outscn, NULL);
1511	ELF_CHECK (outdata != NULL, _("cannot copy section data: %s"));
1512	*outdata = *indata;
1513	elf_flagdata (outdata, ELF_C_SET, ELF_F_DIRTY);
1514
1515	/* Preserve the file layout of the allocated sections.  */
1516	if (stripped_ehdr->e_type != ET_REL && (shdr_mem.sh_flags & SHF_ALLOC))
1517	  {
1518	    shdr_mem.sh_offset = sec->shdr.sh_offset;
1519	    placed[elf_ndxscn (sec->outscn) - 1] = true;
1520
1521	    const GElf_Off end_offset = (shdr_mem.sh_offset
1522					 + (shdr_mem.sh_type == SHT_NOBITS
1523					    ? 0 : shdr_mem.sh_size));
1524	    if (end_offset > offset)
1525	      offset = end_offset;
1526	  }
1527
1528	update_shdr (sec->outscn, &shdr_mem);
1529
1530	if (shdr_mem.sh_type == SHT_SYMTAB || shdr_mem.sh_type == SHT_DYNSYM)
1531	  {
1532	    /* We must adjust all the section indices in the symbol table.  */
1533
1534	    Elf_Data *shndxdata = NULL;	/* XXX */
1535
1536	    for (size_t i = 1; i < shdr_mem.sh_size / shdr_mem.sh_entsize; ++i)
1537	      {
1538		GElf_Sym sym_mem;
1539		GElf_Word shndx = SHN_UNDEF;
1540		GElf_Sym *sym = gelf_getsymshndx (outdata, shndxdata,
1541						  i, &sym_mem, &shndx);
1542		ELF_CHECK (sym != NULL,
1543			   _("cannot get symbol table entry: %s"));
1544		if (sym->st_shndx != SHN_XINDEX)
1545		  shndx = sym->st_shndx;
1546
1547		if (shndx != SHN_UNDEF && shndx < SHN_LORESERVE)
1548		  {
1549		    if (shndx >= stripped_shnum)
1550		      error (EXIT_FAILURE, 0,
1551			     _("symbol [%Zu] has invalid section index"), i);
1552
1553		    shndx = ndx_section[shndx - 1];
1554		    if (shndx < SHN_LORESERVE)
1555		      {
1556			sym->st_shndx = shndx;
1557			shndx = SHN_UNDEF;
1558		      }
1559		    else
1560		      sym->st_shndx = SHN_XINDEX;
1561
1562		    ELF_CHECK (gelf_update_symshndx (outdata, shndxdata,
1563						     i, sym, shndx),
1564			       _("cannot update symbol table: %s"));
1565		  }
1566	      }
1567
1568	    if (shdr_mem.sh_type == SHT_SYMTAB)
1569	      stripped_symtab = sec;
1570	    if (shdr_mem.sh_type == SHT_DYNSYM)
1571	      stripped_dynsym = sec;
1572	  }
1573      }
1574
1575  /* We may need to update the symbol table.  */
1576  Elf_Data *symdata = NULL;
1577  struct Ebl_Strtab *symstrtab = NULL;
1578  Elf_Data *symstrdata = NULL;
1579  if (unstripped_symtab != NULL && (stripped_symtab != NULL
1580				    || check_prelink /* Section adjustments. */
1581				    || (stripped_ehdr->e_type != ET_REL
1582					&& bias != 0)))
1583    {
1584      /* Merge the stripped file's symbol table into the unstripped one.  */
1585      const size_t stripped_nsym = (stripped_symtab == NULL ? 1
1586				    : (stripped_symtab->shdr.sh_size
1587				       / stripped_symtab->shdr.sh_entsize));
1588
1589      GElf_Shdr shdr_mem;
1590      GElf_Shdr *shdr = gelf_getshdr (unstripped_symtab, &shdr_mem);
1591      ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1592      const size_t unstripped_nsym = shdr->sh_size / shdr->sh_entsize;
1593
1594      /* First collect all the symbols from both tables.  */
1595
1596      const size_t total_syms = stripped_nsym - 1 + unstripped_nsym - 1;
1597      struct symbol symbols[total_syms];
1598      size_t symndx_map[total_syms];
1599
1600      if (stripped_symtab != NULL)
1601	collect_symbols (unstripped, stripped_ehdr->e_type == ET_REL,
1602			 stripped_symtab->scn,
1603			 elf_getscn (stripped, stripped_symtab->shdr.sh_link),
1604			 stripped_nsym, 0, ndx_section,
1605			 symbols, symndx_map, NULL);
1606
1607      Elf_Scn *unstripped_strtab = elf_getscn (unstripped, shdr->sh_link);
1608      collect_symbols (unstripped, stripped_ehdr->e_type == ET_REL,
1609		       unstripped_symtab, unstripped_strtab, unstripped_nsym,
1610		       stripped_ehdr->e_type == ET_REL ? 0 : bias, NULL,
1611		       &symbols[stripped_nsym - 1],
1612		       &symndx_map[stripped_nsym - 1], split_bss);
1613
1614      /* Next, sort our array of all symbols.  */
1615      qsort (symbols, total_syms, sizeof symbols[0], compare_symbols);
1616
1617      /* Now we can weed out the duplicates.  Assign remaining symbols
1618	 new slots, collecting a map from old indices to new.  */
1619      size_t nsym = 0;
1620      for (struct symbol *s = symbols; s < &symbols[total_syms]; ++s)
1621	{
1622	  /* Skip a section symbol for a removed section.  */
1623	  if (s->shndx == SHN_UNDEF
1624	      && GELF_ST_TYPE (s->info.info) == STT_SECTION)
1625	    {
1626	      s->name = NULL;	/* Mark as discarded. */
1627	      *s->map = STN_UNDEF;
1628	      s->duplicate = NULL;
1629	      continue;
1630	    }
1631
1632	  struct symbol *n = s;
1633	  while (n + 1 < &symbols[total_syms] && !compare_symbols (s, n + 1))
1634	    ++n;
1635
1636	  while (s < n)
1637	    {
1638	      /* This is a duplicate.  Its twin will get the next slot.  */
1639	      s->name = NULL;	/* Mark as discarded. */
1640	      s->duplicate = n->map;
1641	      ++s;
1642	    }
1643
1644	  /* Allocate the next slot.  */
1645	  *s->map = ++nsym;
1646	}
1647
1648      /* Now we sort again, to determine the order in the output.  */
1649      qsort (symbols, total_syms, sizeof symbols[0], compare_symbols_output);
1650
1651      if (nsym < total_syms)
1652	/* The discarded symbols are now at the end of the table.  */
1653	assert (symbols[nsym].name == NULL);
1654
1655      /* Now a final pass updates the map with the final order,
1656	 and builds up the new string table.  */
1657      symstrtab = ebl_strtabinit (true);
1658      for (size_t i = 0; i < nsym; ++i)
1659	{
1660	  assert (symbols[i].name != NULL);
1661	  assert (*symbols[i].map != 0);
1662	  *symbols[i].map = 1 + i;
1663	  symbols[i].strent = ebl_strtabadd (symstrtab, symbols[i].name, 0);
1664	}
1665
1666      /* Scan the discarded symbols too, just to update their slots
1667	 in SYMNDX_MAP to refer to their live duplicates.  */
1668      for (size_t i = nsym; i < total_syms; ++i)
1669	{
1670	  assert (symbols[i].name == NULL);
1671	  if (symbols[i].duplicate == NULL)
1672	    assert (*symbols[i].map == STN_UNDEF);
1673	  else
1674	    {
1675	      assert (*symbols[i].duplicate != STN_UNDEF);
1676	      *symbols[i].map = *symbols[i].duplicate;
1677	    }
1678	}
1679
1680      /* Now we are ready to write the new symbol table.  */
1681      symdata = elf_getdata (unstripped_symtab, NULL);
1682      symstrdata = elf_getdata (unstripped_strtab, NULL);
1683      Elf_Data *shndxdata = NULL;	/* XXX */
1684
1685      ebl_strtabfinalize (symstrtab, symstrdata);
1686      elf_flagdata (symstrdata, ELF_C_SET, ELF_F_DIRTY);
1687
1688      shdr->sh_size = symdata->d_size = (1 + nsym) * shdr->sh_entsize;
1689      symdata->d_buf = xmalloc (symdata->d_size);
1690
1691      GElf_Sym sym;
1692      memset (&sym, 0, sizeof sym);
1693      ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, 0, &sym, SHN_UNDEF),
1694		 _("cannot update symbol table: %s"));
1695
1696      shdr->sh_info = 1;
1697      for (size_t i = 0; i < nsym; ++i)
1698	{
1699	  struct symbol *s = &symbols[i];
1700
1701	  /* Fill in the symbol details.  */
1702	  sym.st_name = ebl_strtaboffset (s->strent);
1703	  sym.st_value = s->value; /* Already biased to output address.  */
1704	  sym.st_size = s->size;
1705	  sym.st_shndx = s->shndx; /* Already mapped to output index.  */
1706	  sym.st_info = s->info.info;
1707	  sym.st_other = s->info.other;
1708
1709	  /* Keep track of the number of leading local symbols.  */
1710	  if (GELF_ST_BIND (sym.st_info) == STB_LOCAL)
1711	    {
1712	      assert (shdr->sh_info == 1 + i);
1713	      shdr->sh_info = 1 + i + 1;
1714	    }
1715
1716	  ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, 1 + i,
1717					   &sym, SHN_UNDEF),
1718		     _("cannot update symbol table: %s"));
1719
1720	}
1721      elf_flagdata (symdata, ELF_C_SET, ELF_F_DIRTY);
1722      update_shdr (unstripped_symtab, shdr);
1723
1724      if (stripped_symtab != NULL)
1725	{
1726	  /* Adjust any relocations referring to the old symbol table.  */
1727	  const size_t old_sh_link = elf_ndxscn (stripped_symtab->scn);
1728	  for (const struct section *sec = sections;
1729	       sec < &sections[stripped_shnum - 1];
1730	       ++sec)
1731	    if (sec->outscn != NULL && sec->shdr.sh_link == old_sh_link)
1732	      adjust_relocs (sec->outscn, sec->scn, &sec->shdr,
1733			     symndx_map, shdr);
1734	}
1735
1736      /* Also adjust references to the other old symbol table.  */
1737      adjust_all_relocs (unstripped, unstripped_symtab, shdr,
1738			 &symndx_map[stripped_nsym - 1]);
1739    }
1740  else if (stripped_symtab != NULL && stripped_shnum != unstripped_shnum)
1741    check_symtab_section_symbols (unstripped,
1742				  stripped_ehdr->e_type == ET_REL,
1743				  stripped_symtab->scn,
1744				  unstripped_shnum, unstripped_shstrndx,
1745				  stripped_symtab->outscn,
1746				  stripped_shnum, stripped_shstrndx,
1747				  debuglink);
1748
1749  if (stripped_dynsym != NULL)
1750    (void) check_symtab_section_symbols (unstripped,
1751					 stripped_ehdr->e_type == ET_REL,
1752					 stripped_dynsym->outscn,
1753					 unstripped_shnum,
1754					 unstripped_shstrndx,
1755					 stripped_dynsym->scn, stripped_shnum,
1756					 stripped_shstrndx, debuglink);
1757
1758  /* We need to preserve the layout of the stripped file so the
1759     phdrs will match up.  This requires us to do our own layout of
1760     the added sections.  We do manual layout even for ET_REL just
1761     so we can try to match what the original probably had.  */
1762
1763  elf_flagelf (unstripped, ELF_C_SET, ELF_F_LAYOUT);
1764
1765  if (offset == 0)
1766    /* For ET_REL we are starting the layout from scratch.  */
1767    offset = gelf_fsize (unstripped, ELF_T_EHDR, 1, EV_CURRENT);
1768
1769  bool skip_reloc = false;
1770  do
1771    {
1772      skip_reloc = !skip_reloc;
1773      for (size_t i = 0; i < unstripped_shnum - 1; ++i)
1774	if (!placed[i])
1775	  {
1776	    scn = elf_getscn (unstripped, 1 + i);
1777
1778	    GElf_Shdr shdr_mem;
1779	    GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1780	    ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1781
1782	    /* We must make sure we have read in the data of all sections
1783	       beforehand and marked them to be written out.  When we're
1784	       modifying the existing file in place, we might overwrite
1785	       this part of the file before we get to handling the section.  */
1786
1787	    ELF_CHECK (elf_flagdata (elf_getdata (scn, NULL),
1788				     ELF_C_SET, ELF_F_DIRTY),
1789		       _("cannot read section data: %s"));
1790
1791	    if (skip_reloc
1792		&& (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
1793	      continue;
1794
1795	    GElf_Off align = shdr->sh_addralign ?: 1;
1796	    offset = (offset + align - 1) & -align;
1797	    shdr->sh_offset = offset;
1798	    if (shdr->sh_type != SHT_NOBITS)
1799	      offset += shdr->sh_size;
1800
1801	    update_shdr (scn, shdr);
1802
1803	    if (unstripped_shstrndx == 1 + i)
1804	      {
1805		/* Place the section headers immediately after
1806		   .shstrtab, and update the ELF header.  */
1807
1808		GElf_Ehdr ehdr_mem;
1809		GElf_Ehdr *ehdr = gelf_getehdr (unstripped, &ehdr_mem);
1810		ELF_CHECK (ehdr != NULL, _("cannot get ELF header: %s"));
1811
1812		GElf_Off sh_align = gelf_getclass (unstripped) * 4;
1813		offset = (offset + sh_align - 1) & -sh_align;
1814		ehdr->e_shnum = unstripped_shnum;
1815		ehdr->e_shoff = offset;
1816		offset += unstripped_shnum * ehdr->e_shentsize;
1817		ELF_CHECK (gelf_update_ehdr (unstripped, ehdr),
1818			   _("cannot update ELF header: %s"));
1819	      }
1820
1821	    placed[i] = true;
1822	  }
1823    }
1824  while (skip_reloc);
1825
1826  if (stripped_ehdr->e_phnum > 0)
1827    ELF_CHECK (gelf_newphdr (unstripped, stripped_ehdr->e_phnum),
1828	       _("cannot create program headers: %s"));
1829
1830  /* Copy each program header from the stripped file.  */
1831  for (uint_fast16_t i = 0; i < stripped_ehdr->e_phnum; ++i)
1832    {
1833      GElf_Phdr phdr_mem;
1834      GElf_Phdr *phdr = gelf_getphdr (stripped, i, &phdr_mem);
1835      ELF_CHECK (phdr != NULL, _("cannot get program header: %s"));
1836
1837      ELF_CHECK (gelf_update_phdr (unstripped, i, phdr),
1838		 _("cannot update program header: %s"));
1839    }
1840
1841  /* Finally, write out the file.  */
1842  ELF_CHECK (elf_update (unstripped, ELF_C_WRITE) > 0,
1843	     _("cannot write output file: %s"));
1844
1845  if (strtab != NULL)
1846    {
1847      ebl_strtabfree (strtab);
1848      free (strtab_data->d_buf);
1849    }
1850
1851  if (symdata != NULL)
1852    free (symdata->d_buf);
1853  if (symstrtab != NULL)
1854    {
1855      ebl_strtabfree (symstrtab);
1856      free (symstrdata->d_buf);
1857    }
1858}
1859
1860/* Process one pair of files, already opened.  */
1861static void
1862handle_file (const char *output_file, bool create_dirs,
1863	     Elf *stripped, const GElf_Ehdr *stripped_ehdr,
1864	     Elf *unstripped)
1865{
1866  /* Determine the address bias between the debuginfo file and the main
1867     file, which may have been modified by prelinking.  */
1868  GElf_Addr bias = 0;
1869  if (unstripped != NULL)
1870    for (uint_fast16_t i = 0; i < stripped_ehdr->e_phnum; ++i)
1871      {
1872	GElf_Phdr phdr_mem;
1873	GElf_Phdr *phdr = gelf_getphdr (stripped, i, &phdr_mem);
1874	ELF_CHECK (phdr != NULL, _("cannot get program header: %s"));
1875	if (phdr->p_type == PT_LOAD)
1876	  {
1877	    GElf_Phdr unstripped_phdr_mem;
1878	    GElf_Phdr *unstripped_phdr = gelf_getphdr (unstripped, i,
1879						       &unstripped_phdr_mem);
1880	    ELF_CHECK (unstripped_phdr != NULL,
1881		       _("cannot get program header: %s"));
1882	    bias = phdr->p_vaddr - unstripped_phdr->p_vaddr;
1883	    break;
1884	  }
1885      }
1886
1887  /* One day we could adjust all the DWARF data (like prelink itself does).  */
1888  if (bias != 0)
1889    {
1890      if (output_file == NULL)
1891	error (0, 0, _("\
1892DWARF data not adjusted for prelinking bias; consider prelink -u"));
1893      else
1894	error (0, 0, _("\
1895DWARF data in '%s' not adjusted for prelinking bias; consider prelink -u"),
1896	       output_file);
1897    }
1898
1899  if (output_file == NULL)
1900    /* Modify the unstripped file in place.  */
1901    copy_elided_sections (unstripped, stripped, stripped_ehdr, bias);
1902  else
1903    {
1904      if (create_dirs)
1905	make_directories (output_file);
1906
1907      /* Copy the unstripped file and then modify it.  */
1908      int outfd = open64 (output_file, O_RDWR | O_CREAT,
1909			  stripped_ehdr->e_type == ET_REL ? 0666 : 0777);
1910      if (outfd < 0)
1911	error (EXIT_FAILURE, errno, _("cannot open '%s'"), output_file);
1912      Elf *outelf = elf_begin (outfd, ELF_C_WRITE, NULL);
1913      ELF_CHECK (outelf != NULL, _("cannot create ELF descriptor: %s"));
1914
1915      if (unstripped == NULL)
1916	{
1917	  /* Actually, we are just copying out the main file as it is.  */
1918	  copy_elf (outelf, stripped);
1919	  if (stripped_ehdr->e_type != ET_REL)
1920	    elf_flagelf (outelf, ELF_C_SET, ELF_F_LAYOUT);
1921	  ELF_CHECK (elf_update (outelf, ELF_C_WRITE) > 0,
1922		     _("cannot write output file: %s"));
1923	}
1924      else
1925	{
1926	  copy_elf (outelf, unstripped);
1927	  copy_elided_sections (outelf, stripped, stripped_ehdr, bias);
1928	}
1929
1930      elf_end (outelf);
1931      close (outfd);
1932    }
1933}
1934
1935static int
1936open_file (const char *file, bool writable)
1937{
1938  int fd = open64 (file, writable ? O_RDWR : O_RDONLY);
1939  if (fd < 0)
1940    error (EXIT_FAILURE, errno, _("cannot open '%s'"), file);
1941  return fd;
1942}
1943
1944/* Handle a pair of files we need to open by name.  */
1945static void
1946handle_explicit_files (const char *output_file, bool create_dirs,
1947		       const char *stripped_file, const char *unstripped_file)
1948{
1949  int stripped_fd = open_file (stripped_file, false);
1950  Elf *stripped = elf_begin (stripped_fd, ELF_C_READ, NULL);
1951  GElf_Ehdr stripped_ehdr;
1952  ELF_CHECK (gelf_getehdr (stripped, &stripped_ehdr),
1953	     _("cannot create ELF descriptor: %s"));
1954
1955  int unstripped_fd = -1;
1956  Elf *unstripped = NULL;
1957  if (unstripped_file != NULL)
1958    {
1959      unstripped_fd = open_file (unstripped_file, output_file == NULL);
1960      unstripped = elf_begin (unstripped_fd,
1961			      (output_file == NULL ? ELF_C_RDWR : ELF_C_READ),
1962			      NULL);
1963      GElf_Ehdr unstripped_ehdr;
1964      ELF_CHECK (gelf_getehdr (unstripped, &unstripped_ehdr),
1965		 _("cannot create ELF descriptor: %s"));
1966
1967      if (memcmp (stripped_ehdr.e_ident, unstripped_ehdr.e_ident, EI_NIDENT)
1968	  || stripped_ehdr.e_type != unstripped_ehdr.e_type
1969	  || stripped_ehdr.e_machine != unstripped_ehdr.e_machine
1970	  || stripped_ehdr.e_phnum != unstripped_ehdr.e_phnum)
1971	error (EXIT_FAILURE, 0, _("'%s' and '%s' do not seem to match"),
1972	       stripped_file, unstripped_file);
1973    }
1974
1975  handle_file (output_file, create_dirs, stripped, &stripped_ehdr, unstripped);
1976
1977  elf_end (stripped);
1978  close (stripped_fd);
1979
1980  elf_end (unstripped);
1981  close (unstripped_fd);
1982}
1983
1984
1985/* Handle a pair of files opened implicitly by libdwfl for one module.  */
1986static void
1987handle_dwfl_module (const char *output_file, bool create_dirs,
1988		    Dwfl_Module *mod, bool all, bool ignore, bool relocate)
1989{
1990  GElf_Addr bias;
1991  Elf *stripped = dwfl_module_getelf (mod, &bias);
1992  if (stripped == NULL)
1993    {
1994      if (ignore)
1995	return;
1996
1997      const char *file;
1998      const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
1999					      NULL, NULL, &file, NULL);
2000      if (file == NULL)
2001	error (EXIT_FAILURE, 0,
2002	       _("cannot find stripped file for module '%s': %s"),
2003	       modname, dwfl_errmsg (-1));
2004      else
2005	error (EXIT_FAILURE, 0,
2006	       _("cannot open stripped file '%s' for module '%s': %s"),
2007	       modname, file, dwfl_errmsg (-1));
2008    }
2009
2010  Elf *debug = dwarf_getelf (dwfl_module_getdwarf (mod, &bias));
2011  if (debug == NULL && !all)
2012    {
2013      if (ignore)
2014	return;
2015
2016      const char *file;
2017      const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
2018					      NULL, NULL, NULL, &file);
2019      if (file == NULL)
2020	error (EXIT_FAILURE, 0,
2021	       _("cannot find debug file for module '%s': %s"),
2022	       modname, dwfl_errmsg (-1));
2023      else
2024	error (EXIT_FAILURE, 0,
2025	       _("cannot open debug file '%s' for module '%s': %s"),
2026	       modname, file, dwfl_errmsg (-1));
2027    }
2028
2029  if (debug == stripped)
2030    {
2031      if (all)
2032	debug = NULL;
2033      else
2034	{
2035	  const char *file;
2036	  const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
2037						  NULL, NULL, &file, NULL);
2038	  error (EXIT_FAILURE, 0, _("module '%s' file '%s' is not stripped"),
2039		 modname, file);
2040	}
2041    }
2042
2043  GElf_Ehdr stripped_ehdr;
2044  ELF_CHECK (gelf_getehdr (stripped, &stripped_ehdr),
2045	     _("cannot create ELF descriptor: %s"));
2046
2047  if (stripped_ehdr.e_type == ET_REL)
2048    {
2049      if (!relocate)
2050	{
2051	  /* We can't use the Elf handles already open,
2052	     because the DWARF sections have been relocated.  */
2053
2054	  const char *stripped_file = NULL;
2055	  const char *unstripped_file = NULL;
2056	  (void) dwfl_module_info (mod, NULL, NULL, NULL, NULL, NULL,
2057				   &stripped_file, &unstripped_file);
2058
2059	  handle_explicit_files (output_file, create_dirs,
2060				 stripped_file, unstripped_file);
2061	  return;
2062	}
2063
2064      /* Relocation is what we want!  This ensures that all sections that can
2065	 get sh_addr values assigned have them, even ones not used in DWARF.
2066	 They might still be used in the symbol table.  */
2067      if (dwfl_module_relocations (mod) < 0)
2068	error (EXIT_FAILURE, 0,
2069	       _("cannot cache section addresses for module '%s': %s"),
2070	       dwfl_module_info (mod, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
2071	       dwfl_errmsg (-1));
2072    }
2073
2074  handle_file (output_file, create_dirs, stripped, &stripped_ehdr, debug);
2075}
2076
2077/* Handle one module being written to the output directory.  */
2078static void
2079handle_output_dir_module (const char *output_dir, Dwfl_Module *mod,
2080			  bool all, bool ignore, bool modnames, bool relocate)
2081{
2082  if (! modnames)
2083    {
2084      /* Make sure we've searched for the ELF file.  */
2085      GElf_Addr bias;
2086      (void) dwfl_module_getelf (mod, &bias);
2087    }
2088
2089  const char *file;
2090  const char *name = dwfl_module_info (mod, NULL, NULL, NULL,
2091				       NULL, NULL, &file, NULL);
2092
2093  if (file == NULL && ignore)
2094    return;
2095
2096  char *output_file;
2097  if (asprintf (&output_file, "%s/%s", output_dir, modnames ? name : file) < 0)
2098    error (EXIT_FAILURE, 0, _("memory exhausted"));
2099
2100  handle_dwfl_module (output_file, true, mod, all, ignore, relocate);
2101}
2102
2103
2104static void
2105list_module (Dwfl_Module *mod)
2106{
2107  /* Make sure we have searched for the files.  */
2108  GElf_Addr bias;
2109  bool have_elf = dwfl_module_getelf (mod, &bias) != NULL;
2110  bool have_dwarf = dwfl_module_getdwarf (mod, &bias) != NULL;
2111
2112  const char *file;
2113  const char *debug;
2114  Dwarf_Addr start;
2115  Dwarf_Addr end;
2116  const char *name = dwfl_module_info (mod, NULL, &start, &end,
2117				       NULL, NULL, &file, &debug);
2118  if (file != NULL && debug != NULL && (debug == file || !strcmp (debug, file)))
2119    debug = ".";
2120
2121  const unsigned char *id;
2122  GElf_Addr id_vaddr;
2123  int id_len = dwfl_module_build_id (mod, &id, &id_vaddr);
2124
2125  printf ("%#" PRIx64 "+%#" PRIx64 " ", start, end - start);
2126
2127  if (id_len > 0)
2128    {
2129      do
2130	printf ("%02" PRIx8, *id++);
2131      while (--id_len > 0);
2132      if (id_vaddr != 0)
2133	printf ("@%#" PRIx64, id_vaddr);
2134    }
2135  else
2136    putchar ('-');
2137
2138  printf (" %s %s %s\n",
2139	  file ?: have_elf ? "." : "-",
2140	  debug ?: have_dwarf ? "." : "-",
2141	  name);
2142}
2143
2144
2145struct match_module_info
2146{
2147  char **patterns;
2148  Dwfl_Module *found;
2149  bool match_files;
2150};
2151
2152static int
2153match_module (Dwfl_Module *mod,
2154	      void **userdata __attribute__ ((unused)),
2155	      const char *name,
2156	      Dwarf_Addr start __attribute__ ((unused)),
2157	      void *arg)
2158{
2159  struct match_module_info *info = arg;
2160
2161  if (info->patterns[0] == NULL) /* Match all.  */
2162    {
2163    match:
2164      info->found = mod;
2165      return DWARF_CB_ABORT;
2166    }
2167
2168  if (info->match_files)
2169    {
2170      /* Make sure we've searched for the ELF file.  */
2171      GElf_Addr bias;
2172      (void) dwfl_module_getelf (mod, &bias);
2173
2174      const char *file;
2175      const char *check = dwfl_module_info (mod, NULL, NULL, NULL,
2176					    NULL, NULL, &file, NULL);
2177      assert (check == name);
2178      if (file == NULL)
2179	return DWARF_CB_OK;
2180
2181      name = file;
2182    }
2183
2184  for (char **p = info->patterns; *p != NULL; ++p)
2185    if (fnmatch (*p, name, 0) == 0)
2186      goto match;
2187
2188  return DWARF_CB_OK;
2189}
2190
2191/* Handle files opened implicitly via libdwfl.  */
2192static void
2193handle_implicit_modules (const struct arg_info *info)
2194{
2195  struct match_module_info mmi = { info->args, NULL, info->match_files };
2196  inline ptrdiff_t next (ptrdiff_t offset)
2197    {
2198      return dwfl_getmodules (info->dwfl, &match_module, &mmi, offset);
2199    }
2200  ptrdiff_t offset = next (0);
2201  if (offset == 0)
2202    error (EXIT_FAILURE, 0, _("no matching modules found"));
2203
2204  if (info->list)
2205    do
2206      list_module (mmi.found);
2207    while ((offset = next (offset)) > 0);
2208  else if (info->output_dir == NULL)
2209    {
2210      if (next (offset) != 0)
2211	error (EXIT_FAILURE, 0, _("matched more than one module"));
2212      handle_dwfl_module (info->output_file, false, mmi.found,
2213			  info->all, info->ignore, info->relocate);
2214    }
2215  else
2216    do
2217      handle_output_dir_module (info->output_dir, mmi.found,
2218				info->all, info->ignore,
2219				info->modnames, info->relocate);
2220    while ((offset = next (offset)) > 0);
2221}
2222
2223int
2224main (int argc, char **argv)
2225{
2226  /* Make memory leak detection possible.  */
2227  mtrace ();
2228
2229  /* We use no threads here which can interfere with handling a stream.  */
2230  __fsetlocking (stdin, FSETLOCKING_BYCALLER);
2231  __fsetlocking (stdout, FSETLOCKING_BYCALLER);
2232  __fsetlocking (stderr, FSETLOCKING_BYCALLER);
2233
2234  /* Set locale.  */
2235  setlocale (LC_ALL, "");
2236
2237  /* Make sure the message catalog can be found.  */
2238  bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
2239
2240  /* Initialize the message catalog.  */
2241  textdomain (PACKAGE_TARNAME);
2242
2243  /* Parse and process arguments.  */
2244  const struct argp_child argp_children[] =
2245    {
2246      {
2247	.argp = dwfl_standard_argp (),
2248	.header = N_("Input selection options:"),
2249	.group = 1,
2250      },
2251      { .argp = NULL },
2252    };
2253  const struct argp argp =
2254    {
2255      .options = options,
2256      .parser = parse_opt,
2257      .children = argp_children,
2258      .args_doc = N_("STRIPPED-FILE DEBUG-FILE\n[MODULE...]"),
2259      .doc = N_("\
2260Combine stripped files with separate symbols and debug information.\v\
2261The first form puts the result in DEBUG-FILE if -o was not given.\n\
2262\n\
2263MODULE arguments give file name patterns matching modules to process.\n\
2264With -f these match the file name of the main (stripped) file \
2265(slashes are never special), otherwise they match the simple module names.  \
2266With no arguments, process all modules found.\n\
2267\n\
2268Multiple modules are written to files under OUTPUT-DIRECTORY, \
2269creating subdirectories as needed.  \
2270With -m these files have simple module names, otherwise they have the \
2271name of the main file complete with directory underneath OUTPUT-DIRECTORY.\n\
2272\n\
2273With -n no files are written, but one line to standard output for each module:\
2274\n\tSTART+SIZE BUILDID FILE DEBUGFILE MODULENAME\n\
2275START and SIZE are hexadecimal giving the address bounds of the module.  \
2276BUILDID is hexadecimal for the build ID bits, or - if no ID is known; \
2277the hexadecimal may be followed by @0xADDR giving the address where the \
2278ID resides if that is known.  \
2279FILE is the file name found for the module, or - if none was found, \
2280or . if an ELF image is available but not from any named file.  \
2281DEBUGFILE is the separate debuginfo file name, \
2282or - if no debuginfo was found, or . if FILE contains the debug information.\
2283")
2284    };
2285
2286  int remaining;
2287  struct arg_info info = { .args = NULL };
2288  error_t result = argp_parse (&argp, argc, argv, 0, &remaining, &info);
2289  if (result == ENOSYS)
2290    assert (info.dwfl == NULL);
2291  else if (result)
2292    return EXIT_FAILURE;
2293  assert (info.args != NULL);
2294
2295  /* Tell the library which version we are expecting.  */
2296  elf_version (EV_CURRENT);
2297
2298  if (info.dwfl == NULL)
2299    {
2300      assert (result == ENOSYS);
2301
2302      if (info.output_dir != NULL)
2303	{
2304	  char *file;
2305	  if (asprintf (&file, "%s/%s", info.output_dir, info.args[0]) < 0)
2306	    error (EXIT_FAILURE, 0, _("memory exhausted"));
2307	  handle_explicit_files (file, true, info.args[0], info.args[1]);
2308	  free (file);
2309	}
2310      else
2311	handle_explicit_files (info.output_file, false,
2312			       info.args[0], info.args[1]);
2313    }
2314  else
2315    {
2316      /* parse_opt checked this.  */
2317      assert (info.output_file != NULL || info.output_dir != NULL || info.list);
2318
2319      handle_implicit_modules (&info);
2320
2321      dwfl_end (info.dwfl);
2322    }
2323
2324  return 0;
2325}
2326
2327
2328#include "debugpred.h"
2329