1cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Combine stripped files with separate symbols and debug information.
2cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Copyright (C) 2007 Red Hat, Inc.
3cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   This file is part of Red Hat elfutils.
4cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Written by Roland McGrath <roland@redhat.com>, 2007.
5cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
6cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Red Hat elfutils is free software; you can redistribute it and/or modify
7cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   it under the terms of the GNU General Public License as published by the
8cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Free Software Foundation; version 2 of the License.
9cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
10cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Red Hat elfutils is distributed in the hope that it will be useful, but
11cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   WITHOUT ANY WARRANTY; without even the implied warranty of
12cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   General Public License for more details.
14cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
15cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   You should have received a copy of the GNU General Public License along
16cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   with Red Hat elfutils; if not, write to the Free Software Foundation,
17cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
18cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
19cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Red Hat elfutils is an included package of the Open Invention Network.
20cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   An included package of the Open Invention Network is a package for which
21cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Open Invention Network licensees cross-license their patents.  No patent
22cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   license is granted, either expressly or impliedly, by designation as an
23cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   included package.  Should you wish to participate in the Open Invention
24cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Network licensing program, please visit www.openinventionnetwork.com
25cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   <http://www.openinventionnetwork.com>.  */
26cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
27cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* TODO:
28cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
29cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  * SHX_XINDEX
30cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
31cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  * prelink vs .debug_* linked addresses
32cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
33cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng */
34cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
35cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#ifdef HAVE_CONFIG_H
36cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng# include <config.h>
37cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#endif
38cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
39cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <argp.h>
40cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <assert.h>
41cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <errno.h>
42cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <error.h>
43cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <fcntl.h>
44cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <fnmatch.h>
45cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <libintl.h>
46cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <locale.h>
47cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <mcheck.h>
48cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <stdbool.h>
49cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <stdio.h>
50cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <stdio_ext.h>
51cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <inttypes.h>
52cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <stdlib.h>
53cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <string.h>
54cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <unistd.h>
55cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
56cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <gelf.h>
57cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <libebl.h>
58cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <libdwfl.h>
59cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include "system.h"
60cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
61cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#ifndef _
62cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng# define _(str) gettext (str)
63cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#endif
64cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
65cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Name and version of program.  */
66cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void print_version (FILE *stream, struct argp_state *state);
67cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengvoid (*argp_program_version_hook) (FILE *, struct argp_state *)
68cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  = print_version;
69cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
70cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Bug report address.  */
71cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengconst char *argp_program_bug_address = PACKAGE_BUGREPORT;
72cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
73cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Definitions of arguments for argp functions.  */
74cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic const struct argp_option options[] =
75cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
76cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Group 2 will follow group 1 from dwfl_standard_argp.  */
77cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  { "match-file-names", 'f', NULL, 0,
78cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    N_("Match MODULE against file names, not module names"), 2 },
79cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  { "ignore-missing", 'i', NULL, 0, N_("Silently skip unfindable files"), 0 },
80cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
81cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  { NULL, 0, NULL, 0, N_("Output options:"), 0 },
82cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  { "output", 'o', "FILE", 0, N_("Place output into FILE"), 0 },
83cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  { "output-directory", 'd', "DIRECTORY",
84cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    0, N_("Create multiple output files under DIRECTORY"), 0 },
85cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  { "module-names", 'm', NULL, 0, N_("Use module rather than file names"), 0 },
86cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  { "all", 'a', NULL, 0,
87cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    N_("Create output for modules that have no separate debug information"),
88cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    0 },
89cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  { "relocate", 'R', NULL, 0,
90cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    N_("Apply relocations to section contents in ET_REL files"), 0 },
91cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  { "list-only", 'n', NULL, 0,
92cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    N_("Only list module and file names, build IDs"), 0 },
93cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  { NULL, 0, NULL, 0, NULL, 0 }
94cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng};
95cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
96cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstruct arg_info
97cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
98cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const char *output_file;
99cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const char *output_dir;
100cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Dwfl *dwfl;
101cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  char **args;
102cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool list;
103cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool all;
104cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool ignore;
105cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool modnames;
106cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool match_files;
107cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool relocate;
108cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng};
109cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
110cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Handle program arguments.  */
111cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic error_t
112cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengparse_opt (int key, char *arg, struct argp_state *state)
113cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
114cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct arg_info *info = state->input;
115cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
116cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  switch (key)
117cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
118cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case ARGP_KEY_INIT:
119cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      state->child_inputs[0] = &info->dwfl;
120cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
121cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
122cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case 'o':
123cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (info->output_file != NULL)
124cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
125cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  argp_error (state, _("-o option specified twice"));
126cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  return EINVAL;
127cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
128cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      info->output_file = arg;
129cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
130cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
131cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case 'd':
132cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (info->output_dir != NULL)
133cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
134cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  argp_error (state, _("-d option specified twice"));
135cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  return EINVAL;
136cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
137cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      info->output_dir = arg;
138cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
139cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
140cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case 'm':
141cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      info->modnames = true;
142cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
143cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case 'f':
144cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      info->match_files = true;
145cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
146cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case 'a':
147cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      info->all = true;
148cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
149cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case 'i':
150cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      info->ignore = true;
151cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
152cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case 'n':
153cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      info->list = true;
154cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
155cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case 'R':
156cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      info->relocate = true;
157cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
158cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
159cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case ARGP_KEY_ARGS:
160cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case ARGP_KEY_NO_ARGS:
161cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* We "consume" all the arguments here.  */
162cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      info->args = &state->argv[state->next];
163cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
164cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (info->output_file != NULL && info->output_dir != NULL)
165cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
166cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  argp_error (state, _("only one of -o or -d allowed"));
167cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  return EINVAL;
168cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
169cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
170cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (info->list && (info->dwfl == NULL
171cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 || info->output_dir != NULL
172cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 || info->output_file != NULL))
173cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
174cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  argp_error (state,
175cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      _("-n cannot be used with explicit files or -o or -d"));
176cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  return EINVAL;
177cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
178cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
179cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (info->output_dir != NULL)
180cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
181cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  struct stat64 st;
182cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  error_t fail = 0;
183cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (stat64 (info->output_dir, &st) < 0)
184cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    fail = errno;
185cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else if (!S_ISDIR (st.st_mode))
186cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    fail = ENOTDIR;
187cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (fail)
188cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
189cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      argp_failure (state, EXIT_FAILURE, fail,
190cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    _("output directory '%s'"), info->output_dir);
191cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      return fail;
192cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
193cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
194cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
195cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (info->dwfl == NULL)
196cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
197cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (state->next + 2 != state->argc)
198cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
199cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      argp_error (state, _("exactly two file arguments are required"));
200cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      return EINVAL;
201cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
202cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
203cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (info->ignore || info->all || info->modnames || info->relocate)
204cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
205cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      argp_error (state, _("\
206cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng-m, -a, -R, and -i options not allowed with explicit files"));
207cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      return EINVAL;
208cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
209cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
210cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Bail out immediately to prevent dwfl_standard_argp's parser
211cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     from defaulting to "-e a.out".  */
212cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  return ENOSYS;
213cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
214cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else if (info->output_file == NULL && info->output_dir == NULL
215cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       && !info->list)
216cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
217cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  argp_error (state,
218cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      _("-o or -d is required when using implicit files"));
219cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  return EINVAL;
220cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
221cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
222cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
223cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    default:
224cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return ARGP_ERR_UNKNOWN;
225cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
226cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return 0;
227cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
228cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
229cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Print the version information.  */
230cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
231cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengprint_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
232cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
233cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  fprintf (stream, "unstrip (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
234cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  fprintf (stream, _("\
235cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengCopyright (C) %s Red Hat, Inc.\n\
236cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengThis is free software; see the source for copying conditions.  There is NO\n\
237cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
238cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng"), "2008");
239cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  fprintf (stream, gettext ("Written by %s.\n"), "Roland McGrath");
240cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
241cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
242cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#define ELF_CHECK(call, msg)						      \
243cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  do									      \
244cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {									      \
245cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (!(call)) 							      \
246cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	error (EXIT_FAILURE, 0, msg, elf_errmsg (-1));			      \
247cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    } while (0)
248cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
249cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Copy INELF to newly-created OUTELF, exit via error for any problems.  */
250cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
251cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcopy_elf (Elf *outelf, Elf *inelf)
252cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
253cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ELF_CHECK (gelf_newehdr (outelf, gelf_getclass (inelf)),
254cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     _("cannot create ELF header: %s"));
255cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
256cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Ehdr ehdr_mem;
257cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Ehdr *ehdr = gelf_getehdr (inelf, &ehdr_mem);
258cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ELF_CHECK (gelf_update_ehdr (outelf, ehdr),
259cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     _("cannot copy ELF header: %s"));
260cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
261cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (ehdr->e_phnum > 0)
262cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
263cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (gelf_newphdr (outelf, ehdr->e_phnum),
264cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 _("cannot create program headers: %s"));
265cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
266cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Phdr phdr_mem;
267cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
268cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ELF_CHECK (gelf_update_phdr (outelf, i,
269cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				     gelf_getphdr (inelf, i, &phdr_mem)),
270cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   _("cannot copy program header: %s"));
271cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
272cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
273cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *scn = NULL;
274cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  while ((scn = elf_nextscn (inelf, scn)) != NULL)
275cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
276cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Elf_Scn *newscn = elf_newscn (outelf);
277cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
278cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Shdr shdr_mem;
279cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (gelf_update_shdr (newscn, gelf_getshdr (scn, &shdr_mem)),
280cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 _("cannot copy section header: %s"));
281cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
282cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Elf_Data *data = elf_getdata (scn, NULL);
283cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (data != NULL, _("cannot get section data: %s"));
284cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Elf_Data *newdata = elf_newdata (newscn);
285cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (newdata != NULL, _("cannot copy section data: %s"));
286cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      *newdata = *data;
287cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      elf_flagdata (newdata, ELF_C_SET, ELF_F_DIRTY);
288cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
289cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
290cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
291cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Create directories containing PATH.  */
292cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
293cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengmake_directories (const char *path)
294cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
295cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const char *lastslash = strrchr (path, '/');
296cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (lastslash == NULL)
297cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return;
298cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
299cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  while (lastslash > path && lastslash[-1] == '/')
300cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    --lastslash;
301cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (lastslash == path)
302cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return;
303cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
304cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  char *dir = strndupa (path, lastslash - path);
305cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  while (mkdir (dir, 0777) < 0 && errno != EEXIST)
306cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (errno == ENOENT)
307cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      make_directories (dir);
308cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    else
309cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      error (EXIT_FAILURE, errno, _("cannot create directory '%s'"), dir);
310cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
311cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
312cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
313cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* The binutils linker leaves gratuitous section symbols in .symtab
314cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   that strip has to remove.  Older linkers likewise include a
315cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   symbol for every section, even unallocated ones, in .dynsym.
316cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Because of this, the related sections can shrink in the stripped
317cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   file from their original size.  Older versions of strip do not
318cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   adjust the sh_size field in the debuginfo file's SHT_NOBITS
319cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   version of the section header, so it can appear larger.  */
320cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic bool
321cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection_can_shrink (const GElf_Shdr *shdr)
322cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
323cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  switch (shdr->sh_type)
324cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
325cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case SHT_SYMTAB:
326cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case SHT_DYNSYM:
327cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case SHT_HASH:
328cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case SHT_GNU_versym:
329cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return true;
330cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
331cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return false;
332cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
333cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
334cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* See if this symbol table has a leading section symbol for every single
335cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   section, in order.  The binutils linker produces this.  While we're here,
336cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   update each section symbol's st_value.  */
337cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic size_t
338cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsymtab_count_leading_section_symbols (Elf *elf, Elf_Scn *scn, size_t shnum,
339cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				      Elf_Data *newsymdata)
340cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
341cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *data = elf_getdata (scn, NULL);
342cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *shndxdata = NULL;	/* XXX */
343cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
344cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (size_t i = 1; i < shnum; ++i)
345cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
346cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Sym sym_mem;
347cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Word shndx = SHN_UNDEF;
348cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Sym *sym = gelf_getsymshndx (data, shndxdata, i, &sym_mem, &shndx);
349cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (sym != NULL, _("cannot get symbol table entry: %s"));
350cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
351cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Shdr shdr_mem;
352cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, i), &shdr_mem);
353cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
354cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
355cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (sym->st_shndx != SHN_XINDEX)
356cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	shndx = sym->st_shndx;
357cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
358cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (shndx != i || GELF_ST_TYPE (sym->st_info) != STT_SECTION)
359cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	return i;
360cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
361cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      sym->st_value = shdr->sh_addr;
362cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (sym->st_shndx != SHN_XINDEX)
363cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	shndx = SHN_UNDEF;
364cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (gelf_update_symshndx (newsymdata, shndxdata, i, sym, shndx),
365cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 _("cannot update symbol table: %s"));
366cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
367cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
368cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return shnum;
369cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
370cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
371cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* We expanded the output section, so update its header.  */
372cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
373cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengupdate_sh_size (Elf_Scn *outscn, const Elf_Data *data)
374cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
375cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr shdr_mem;
376cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *newshdr = gelf_getshdr (outscn, &shdr_mem);
377cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ELF_CHECK (newshdr != NULL, _("cannot get section header: %s"));
378cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
379cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  newshdr->sh_size = data->d_size;
380cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
381cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ELF_CHECK (gelf_update_shdr (outscn, newshdr),
382cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     _("cannot update section header: %s"));
383cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
384cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
385cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Update relocation sections using the symbol table.  */
386cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
387cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengadjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
388cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       size_t map[], const GElf_Shdr *symshdr)
389cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
390cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *data = elf_getdata (outscn, NULL);
391cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
392cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  inline void adjust_reloc (GElf_Xword *info)
393cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
394cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      size_t ndx = GELF_R_SYM (*info);
395cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (ndx != STN_UNDEF)
396cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	*info = GELF_R_INFO (map[ndx - 1], GELF_R_TYPE (*info));
397cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
398cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
399cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  switch (shdr->sh_type)
400cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
401cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case SHT_REL:
402cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i)
403cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
404cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  GElf_Rel rel_mem;
405cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  GElf_Rel *rel = gelf_getrel (data, i, &rel_mem);
406cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  adjust_reloc (&rel->r_info);
407cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ELF_CHECK (gelf_update_rel (data, i, rel),
408cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     _("cannot update relocation: %s"));
409cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
410cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
411cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
412cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case SHT_RELA:
413cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i)
414cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
415cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  GElf_Rela rela_mem;
416cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  GElf_Rela *rela = gelf_getrela (data, i, &rela_mem);
417cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  adjust_reloc (&rela->r_info);
418cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ELF_CHECK (gelf_update_rela (data, i, rela),
419cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     _("cannot update relocation: %s"));
420cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
421cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
422cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
423cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case SHT_GROUP:
424cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
425cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Shdr shdr_mem;
426cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Shdr *newshdr = gelf_getshdr (outscn, &shdr_mem);
427cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ELF_CHECK (newshdr != NULL, _("cannot get section header: %s"));
428cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (newshdr->sh_info != STN_UNDEF)
429cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  {
430cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    newshdr->sh_info = map[newshdr->sh_info - 1];
431cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ELF_CHECK (gelf_update_shdr (outscn, newshdr),
432cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       _("cannot update section header: %s"));
433cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  }
434cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	break;
435cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
436cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
437cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case SHT_HASH:
438cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* We must expand the table and rejigger its contents.  */
439cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
440cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	const size_t nsym = symshdr->sh_size / symshdr->sh_entsize;
441cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	const size_t onent = shdr->sh_size / shdr->sh_entsize;
442cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	assert (data->d_size == shdr->sh_size);
443cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
444cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#define CONVERT_HASH(Hash_Word)						      \
445cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{								      \
446cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  const Hash_Word *const old_hash = data->d_buf;		      \
447cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  const size_t nbucket = old_hash[0];				      \
448cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  const size_t nchain = old_hash[1];				      \
449cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  const Hash_Word *const old_bucket = &old_hash[2];		      \
450cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  const Hash_Word *const old_chain = &old_bucket[nbucket];	      \
451cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  assert (onent == 2 + nbucket + nchain);			      \
452cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng									      \
453cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  const size_t nent = 2 + nbucket + nsym;			      \
454cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  Hash_Word *const new_hash = xcalloc (nent, sizeof new_hash[0]);     \
455cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  Hash_Word *const new_bucket = &new_hash[2];			      \
456cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  Hash_Word *const new_chain = &new_bucket[nbucket];		      \
457cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng									      \
458cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  new_hash[0] = nbucket;					      \
459cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  new_hash[1] = nsym;						      \
460cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  for (size_t i = 0; i < nbucket; ++i)				      \
461cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (old_bucket[i] != STN_UNDEF)				      \
462cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      new_bucket[i] = map[old_bucket[i] - 1];			      \
463cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng									      \
464cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  for (size_t i = 1; i < nchain; ++i)				      \
465cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (old_chain[i] != STN_UNDEF)				      \
466cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      new_chain[map[i - 1]] = map[old_chain[i] - 1];		      \
467cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng									      \
468cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  data->d_buf = new_hash;					      \
469cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  data->d_size = nent * sizeof new_hash[0];			      \
470cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
471cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
472cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	switch (shdr->sh_entsize)
473cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  {
474cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case 4:
475cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    CONVERT_HASH (Elf32_Word);
476cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    break;
477cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case 8:
478cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    CONVERT_HASH (Elf64_Xword);
479cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    break;
480cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  default:
481cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    abort ();
482cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  }
483cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
484cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY);
485cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	update_sh_size (outscn, data);
486cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
487cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#undef	CONVERT_HASH
488cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
489cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
490cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
491cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case SHT_GNU_versym:
492cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* We must expand the table and move its elements around.  */
493cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
494cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	const size_t nent = symshdr->sh_size / symshdr->sh_entsize;
495cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	const size_t onent = shdr->sh_size / shdr->sh_entsize;
496cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	assert (nent >= onent);
497cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
498cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	/* We don't bother using gelf_update_versym because there is
499cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   really no conversion to be done.  */
500cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	assert (sizeof (Elf32_Versym) == sizeof (GElf_Versym));
501cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	assert (sizeof (Elf64_Versym) == sizeof (GElf_Versym));
502cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Versym *versym = xcalloc (nent, sizeof versym[0]);
503cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
504cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	for (size_t i = 1; i < onent; ++i)
505cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  {
506cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    GElf_Versym *v = gelf_getversym (data, i, &versym[map[i - 1]]);
507cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ELF_CHECK (v != NULL, _("cannot get symbol version: %s"));
508cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  }
509cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
510cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	data->d_buf = versym;
511cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	data->d_size = nent * shdr->sh_entsize;
512cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY);
513cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	update_sh_size (outscn, data);
514cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
515cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
516cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
517cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    default:
518cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      error (EXIT_FAILURE, 0,
519cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     _("unexpected section type in [%Zu] with sh_link to symtab"),
520cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     elf_ndxscn (inscn));
521cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
522cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
523cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
524cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Adjust all the relocation sections in the file.  */
525cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
526cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengadjust_all_relocs (Elf *elf, Elf_Scn *symtab, const GElf_Shdr *symshdr,
527cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   size_t map[])
528cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
529cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t new_sh_link = elf_ndxscn (symtab);
530cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *scn = NULL;
531cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  while ((scn = elf_nextscn (elf, scn)) != NULL)
532cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (scn != symtab)
533cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
534cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Shdr shdr_mem;
535cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
536cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
537cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (shdr->sh_type != SHT_NOBITS && shdr->sh_link == new_sh_link)
538cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  adjust_relocs (scn, scn, shdr, map, symshdr);
539cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
540cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
541cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
542cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* The original file probably had section symbols for all of its
543cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   sections, even the unallocated ones.  To match it as closely as
544cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   possible, add in section symbols for the added sections.  */
545cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic Elf_Data *
546cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengadd_new_section_symbols (Elf_Scn *old_symscn, size_t old_shnum,
547cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 Elf *elf, bool rel, Elf_Scn *symscn, size_t shnum)
548cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
549cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const size_t added = shnum - old_shnum;
550cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
551cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr shdr_mem;
552cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *shdr = gelf_getshdr (symscn, &shdr_mem);
553cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
554cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
555cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const size_t nsym = shdr->sh_size / shdr->sh_entsize;
556cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t symndx_map[nsym - 1];
557cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
558cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  shdr->sh_info += added;
559cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  shdr->sh_size += added * shdr->sh_entsize;
560cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
561cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ELF_CHECK (gelf_update_shdr (symscn, shdr),
562cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     _("cannot update section header: %s"));
563cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
564cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *symdata = elf_getdata (symscn, NULL);
565cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *shndxdata = NULL;	/* XXX */
566cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
567cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  symdata->d_size = shdr->sh_size;
568cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  symdata->d_buf = xmalloc (symdata->d_size);
569cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
570cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Copy the existing section symbols.  */
571cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *old_symdata = elf_getdata (old_symscn, NULL);
572cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (size_t i = 0; i < old_shnum; ++i)
573cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
574cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Sym sym_mem;
575cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Word shndx = SHN_UNDEF;
576cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Sym *sym = gelf_getsymshndx (old_symdata, shndxdata,
577cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					i, &sym_mem, &shndx);
578cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, i,
579cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				       sym, shndx),
580cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 _("cannot update symbol table: %s"));
581cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
582cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (i > 0)
583cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	symndx_map[i - 1] = i;
584cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
585cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
586cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Add in the new section symbols.  */
587cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (size_t i = old_shnum; i < shnum; ++i)
588cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
589cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Shdr i_shdr_mem;
590cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Shdr *i_shdr = gelf_getshdr (elf_getscn (elf, i), &i_shdr_mem);
591cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (i_shdr != NULL, _("cannot get section header: %s"));
592cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Sym sym =
593cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
594cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  .st_value = rel ? 0 : i_shdr->sh_addr,
595cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  .st_info = GELF_ST_INFO (STB_LOCAL, STT_SECTION),
596cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  .st_shndx = i < SHN_LORESERVE ? i : SHN_XINDEX
597cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	};
598cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Word shndx = i < SHN_LORESERVE ? SHN_UNDEF : i;
599cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, i,
600cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				       &sym, shndx),
601cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 _("cannot update symbol table: %s"));
602cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
603cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
604cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Now copy the rest of the existing symbols.  */
605cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (size_t i = old_shnum; i < nsym; ++i)
606cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
607cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Sym sym_mem;
608cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Word shndx = SHN_UNDEF;
609cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Sym *sym = gelf_getsymshndx (old_symdata, shndxdata,
610cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					i, &sym_mem, &shndx);
611cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (gelf_update_symshndx (symdata, shndxdata,
612cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				       i + added, sym, shndx),
613cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 _("cannot update symbol table: %s"));
614cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
615cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      symndx_map[i - 1] = i + added;
616cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
617cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
618cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Adjust any relocations referring to the old symbol table.  */
619cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  adjust_all_relocs (elf, symscn, shdr, symndx_map);
620cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
621cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return symdata;
622cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
623cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
624cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* This has the side effect of updating STT_SECTION symbols' values,
625cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   in case of prelink adjustments.  */
626cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic Elf_Data *
627cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_symtab_section_symbols (Elf *elf, bool rel, Elf_Scn *scn,
628cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      size_t shnum, size_t shstrndx,
629cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      Elf_Scn *oscn, size_t oshnum, size_t oshstrndx,
630cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      size_t debuglink)
631cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
632cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t n = symtab_count_leading_section_symbols (elf, oscn, oshnum,
633cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						   elf_getdata (scn, NULL));
634cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
635cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (n == oshnum)
636cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return add_new_section_symbols (oscn, n, elf, rel, scn, shnum);
637cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
638cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (n == oshstrndx || (n == debuglink && n == oshstrndx - 1))
639cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return add_new_section_symbols (oscn, n, elf, rel, scn, shstrndx);
640cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
641cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return NULL;
642cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
643cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
644cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstruct section
645cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
646cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *scn;
647cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const char *name;
648cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *outscn;
649cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct Ebl_Strent *strent;
650cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr shdr;
651cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng};
652cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
653cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic int
654cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcompare_alloc_sections (const struct section *s1, const struct section *s2,
655cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			bool rel)
656cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
657cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (!rel)
658cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
659cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Sort by address.  */
660cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (s1->shdr.sh_addr < s2->shdr.sh_addr)
661cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	return -1;
662cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (s1->shdr.sh_addr > s2->shdr.sh_addr)
663cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	return 1;
664cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
665cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
666cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* At the same address, preserve original section order.  */
667cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return (ssize_t) elf_ndxscn (s1->scn) - (ssize_t) elf_ndxscn (s2->scn);
668cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
669cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
670cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic int
671cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcompare_unalloc_sections (const GElf_Shdr *shdr1, const GElf_Shdr *shdr2,
672cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  const char *name1, const char *name2)
673cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
674cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Sort by sh_flags as an arbitrary ordering.  */
675cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (shdr1->sh_flags < shdr2->sh_flags)
676cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return -1;
677cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (shdr1->sh_flags > shdr2->sh_flags)
678cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return 1;
679cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
680cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Sort by name as last resort.  */
681cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return strcmp (name1, name2);
682cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
683cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
684cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic int
685cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcompare_sections (const void *a, const void *b, bool rel)
686cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
687cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const struct section *s1 = a;
688cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const struct section *s2 = b;
689cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
690cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Sort all non-allocated sections last.  */
691cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if ((s1->shdr.sh_flags ^ s2->shdr.sh_flags) & SHF_ALLOC)
692cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return (s1->shdr.sh_flags & SHF_ALLOC) ? -1 : 1;
693cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
694cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return ((s1->shdr.sh_flags & SHF_ALLOC)
695cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ? compare_alloc_sections (s1, s2, rel)
696cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  : compare_unalloc_sections (&s1->shdr, &s2->shdr,
697cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				      s1->name, s2->name));
698cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
699cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
700cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic int
701cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcompare_sections_rel (const void *a, const void *b)
702cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
703cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return compare_sections (a, b, true);
704cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
705cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
706cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengint
707cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcompare_sections_nonrel (const void *a, const void *b)
708cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
709cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return compare_sections (a, b, false);
710cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
711cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
712cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
713cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstruct symbol
714cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
715cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t *map;
716cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
717cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  union
718cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  {
719cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    const char *name;
720cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    struct Ebl_Strent *strent;
721cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  };
722cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  union
723cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  {
724cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    struct
725cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
726cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Addr value;
727cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Xword size;
728cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Word shndx;
729cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      union
730cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
731cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	struct
732cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
733cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  uint8_t info;
734cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  uint8_t other;
735cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	} info;
736cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	int16_t compare;
737cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      };
738cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    };
739cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
740cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    /* For a symbol discarded after first sort, this matches its better's
741cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng       map pointer.  */
742cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    size_t *duplicate;
743cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  };
744cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng};
745cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
746cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Collect input symbols into our internal form.  */
747cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
748cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcollect_symbols (Elf *outelf, bool rel, Elf_Scn *symscn, Elf_Scn *strscn,
749cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 const size_t nent, const GElf_Addr bias,
750cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 const size_t scnmap[], struct symbol *table, size_t *map,
751cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 struct section *split_bss)
752cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
753cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *symdata = elf_getdata (symscn, NULL);
754cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *strdata = elf_getdata (strscn, NULL);
755cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *shndxdata = NULL;	/* XXX */
756cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
757cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (size_t i = 1; i < nent; ++i)
758cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
759cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Sym sym_mem;
760cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Word shndx = SHN_UNDEF;
761cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Sym *sym = gelf_getsymshndx (symdata, shndxdata, i,
762cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					&sym_mem, &shndx);
763cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (sym != NULL, _("cannot get symbol table entry: %s"));
764cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (sym->st_shndx != SHN_XINDEX)
765cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	shndx = sym->st_shndx;
766cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
767cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (sym->st_name >= strdata->d_size)
768cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	error (EXIT_FAILURE, 0,
769cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       _("invalid string offset in symbol [%Zu]"), i);
770cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
771cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      struct symbol *s = &table[i - 1];
772cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      s->map = &map[i - 1];
773cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      s->name = strdata->d_buf + sym->st_name;
774cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      s->value = sym->st_value + bias;
775cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      s->size = sym->st_size;
776cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      s->shndx = shndx;
777cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      s->info.info = sym->st_info;
778cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      s->info.other = sym->st_other;
779cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
780cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (scnmap != NULL && shndx != SHN_UNDEF && shndx < SHN_LORESERVE)
781cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	s->shndx = scnmap[shndx - 1];
782cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
783cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (GELF_ST_TYPE (s->info.info) == STT_SECTION && !rel)
784cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
785cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Update the value to match the output section.  */
786cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  GElf_Shdr shdr_mem;
787cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  GElf_Shdr *shdr = gelf_getshdr (elf_getscn (outelf, s->shndx),
788cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					  &shdr_mem);
789cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
790cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  s->value = shdr->sh_addr;
791cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
792cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else if (split_bss != NULL
793cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       && s->value < split_bss->shdr.sh_addr
794cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       && s->value >= split_bss[-1].shdr.sh_addr
795cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       && shndx == elf_ndxscn (split_bss->outscn))
796cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	/* This symbol was in .bss and was split into .dynbss.  */
797cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	s->shndx = elf_ndxscn (split_bss[-1].outscn);
798cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
799cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
800cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
801cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
802cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#define CMP(value)							      \
803cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (s1->value < s2->value)						      \
804cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return -1;								      \
805cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (s1->value > s2->value)						      \
806cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return 1
807cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
808cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Compare symbols with a consistent ordering,
809cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   but one only meaningful for equality.  */
810cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic int
811cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcompare_symbols (const void *a, const void *b)
812cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
813cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const struct symbol *s1 = a;
814cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const struct symbol *s2 = b;
815cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
816cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  CMP (value);
817cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  CMP (size);
818cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  CMP (shndx);
819cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
820cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return (s1->compare - s2->compare) ?: strcmp (s1->name, s2->name);
821cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
822cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
823cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Compare symbols for output order after slots have been assigned.  */
824cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic int
825cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcompare_symbols_output (const void *a, const void *b)
826cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
827cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const struct symbol *s1 = a;
828cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const struct symbol *s2 = b;
829cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  int cmp;
830cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
831cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Sort discarded symbols last.  */
832cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  cmp = (s1->name == NULL) - (s2->name == NULL);
833cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
834cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (cmp == 0)
835cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    /* Local symbols must come first.  */
836cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    cmp = ((GELF_ST_BIND (s2->info.info) == STB_LOCAL)
837cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   - (GELF_ST_BIND (s1->info.info) == STB_LOCAL));
838cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
839cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (cmp == 0)
840cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    /* binutils always puts section symbols first.  */
841cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    cmp = ((GELF_ST_TYPE (s2->info.info) == STT_SECTION)
842cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   - (GELF_ST_TYPE (s1->info.info) == STT_SECTION));
843cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
844cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (cmp == 0)
845cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
846cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (GELF_ST_TYPE (s1->info.info) == STT_SECTION)
847cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
848cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* binutils always puts section symbols in section index order.  */
849cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  CMP (shndx);
850cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else
851cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    assert (s1 == s2);
852cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
853cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
854cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Nothing really matters, so preserve the original order.  */
855cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      CMP (map);
856cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else
857cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	assert (s1 == s2);
858cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
859cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
860cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return cmp;
861cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
862cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
863cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#undef CMP
864cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
865cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Return true iff the flags, size, and name match.  */
866cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic bool
867cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsections_match (const struct section *sections, size_t i,
868cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		const GElf_Shdr *shdr, const char *name)
869cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
870cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return (sections[i].shdr.sh_flags == shdr->sh_flags
871cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && (sections[i].shdr.sh_size == shdr->sh_size
872cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      || (sections[i].shdr.sh_size < shdr->sh_size
873cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  && section_can_shrink (&sections[i].shdr)))
874cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && !strcmp (sections[i].name, name));
875cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
876cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
877cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Locate a matching allocated section in SECTIONS.  */
878cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic struct section *
879cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengfind_alloc_section (const GElf_Shdr *shdr, GElf_Addr bias, const char *name,
880cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    struct section sections[], size_t nalloc)
881cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
882cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const GElf_Addr addr = shdr->sh_addr + bias;
883cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t l = 0, u = nalloc;
884cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  while (l < u)
885cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
886cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      size_t i = (l + u) / 2;
887cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (addr < sections[i].shdr.sh_addr)
888cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	u = i;
889cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else if (addr > sections[i].shdr.sh_addr)
890cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	l = i + 1;
891cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else
892cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
893cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* We've found allocated sections with this address.
894cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     Find one with matching size, flags, and name.  */
895cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  while (i > 0 && sections[i - 1].shdr.sh_addr == addr)
896cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    --i;
897cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  for (; i < nalloc && sections[i].shdr.sh_addr == addr;
898cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       ++i)
899cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (sections_match (sections, i, shdr, name))
900cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      return &sections[i];
901cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  break;
902cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
903cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
904cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return NULL;
905cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
906cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
907cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic inline const char *
908cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengget_section_name (size_t ndx, const GElf_Shdr *shdr, const Elf_Data *shstrtab)
909cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
910cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (shdr->sh_name >= shstrtab->d_size)
911cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    error (EXIT_FAILURE, 0, _("cannot read section [%Zu] name: %s"),
912cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   ndx, elf_errmsg (-1));
913cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return shstrtab->d_buf + shdr->sh_name;
914cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
915cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
916cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Fix things up when prelink has moved some allocated sections around
917cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   and the debuginfo file's section headers no longer match up.
918cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   This fills in SECTIONS[0..NALLOC-1].outscn or exits.
919cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   If there was a .bss section that was split into two sections
920cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   with the new one preceding it in sh_addr, we return that pointer.  */
921cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic struct section *
922cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengfind_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
923cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     Elf *main, const GElf_Ehdr *main_ehdr,
924cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     Elf_Data *main_shstrtab, GElf_Addr bias,
925cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     struct section *sections,
926cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     size_t nalloc, size_t nsections)
927cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
928cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Clear assignments that might have been bogus.  */
929cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (size_t i = 0; i < nalloc; ++i)
930cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    sections[i].outscn = NULL;
931cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
932cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *undo = NULL;
933cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (size_t i = nalloc; i < nsections; ++i)
934cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
935cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const struct section *sec = &sections[i];
936cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (sec->shdr.sh_type == SHT_PROGBITS
937cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && !(sec->shdr.sh_flags & SHF_ALLOC)
938cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && !strcmp (sec->name, ".gnu.prelink_undo"))
939cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
940cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  undo = sec->scn;
941cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  break;
942cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
943cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
944cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
945cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Find the original allocated sections before prelinking.  */
946cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct section *undo_sections = NULL;
947cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t undo_nalloc = 0;
948cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (undo != NULL)
949cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
950cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Elf_Data *undodata = elf_rawdata (undo, NULL);
951cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (undodata != NULL,
952cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 _("cannot read '.gnu.prelink_undo' section: %s"));
953cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
954cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      union
955cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
956cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	Elf32_Ehdr e32;
957cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	Elf64_Ehdr e64;
958cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      } ehdr;
959cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Elf_Data dst =
960cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
961cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  .d_buf = &ehdr,
962cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  .d_size = sizeof ehdr,
963cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  .d_type = ELF_T_EHDR,
964cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  .d_version = EV_CURRENT
965cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	};
966cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Elf_Data src = *undodata;
967cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      src.d_size = gelf_fsize (main, ELF_T_EHDR, 1, EV_CURRENT);
968cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      src.d_type = ELF_T_EHDR;
969cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (gelf_xlatetom (main, &dst, &src,
970cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				main_ehdr->e_ident[EI_DATA]) != NULL,
971cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 _("cannot read '.gnu.prelink_undo' section: %s"));
972cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
973cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      uint_fast16_t phnum;
974cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      uint_fast16_t shnum;
975cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
976cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
977cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  phnum = ehdr.e32.e_phnum;
978cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  shnum = ehdr.e32.e_shnum;
979cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
980cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else
981cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
982cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  phnum = ehdr.e64.e_phnum;
983cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  shnum = ehdr.e64.e_shnum;
984cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
985cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
986cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      size_t phsize = gelf_fsize (main, ELF_T_PHDR, phnum, EV_CURRENT);
987cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      src.d_buf += src.d_size + phsize;
988cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      src.d_size = gelf_fsize (main, ELF_T_SHDR, shnum - 1, EV_CURRENT);
989cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      src.d_type = ELF_T_SHDR;
990cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if ((size_t) (src.d_buf - undodata->d_buf) > undodata->d_size
991cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  || undodata->d_size - (src.d_buf - undodata->d_buf) != src.d_size)
992cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	error (EXIT_FAILURE, 0, _("invalid contents in '%s' section"),
993cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       ".gnu.prelink_undo");
994cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
995cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      union
996cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
997cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	Elf32_Shdr s32[shnum - 1];
998cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	Elf64_Shdr s64[shnum - 1];
999cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      } shdr;
1000cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      dst.d_buf = &shdr;
1001cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      dst.d_size = sizeof shdr;
1002cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (gelf_xlatetom (main, &dst, &src,
1003cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				main_ehdr->e_ident[EI_DATA]) != NULL,
1004cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 _("cannot read '.gnu.prelink_undo' section: %s"));
1005cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1006cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      undo_sections = xmalloc ((shnum - 1) * sizeof undo_sections[0]);
1007cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (size_t i = 0; i < shnum - 1; ++i)
1008cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
1009cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  struct section *sec = &undo_sections[undo_nalloc];
1010cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
1011cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1012cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#define COPY(field) sec->shdr.field = shdr.s32[i].field
1013cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      COPY (sh_name);
1014cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      COPY (sh_type);
1015cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      COPY (sh_flags);
1016cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      COPY (sh_addr);
1017cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      COPY (sh_offset);
1018cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      COPY (sh_size);
1019cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      COPY (sh_link);
1020cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      COPY (sh_info);
1021cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      COPY (sh_addralign);
1022cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      COPY (sh_entsize);
1023cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#undef	COPY
1024cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1025cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else
1026cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    sec->shdr = shdr.s64[i];
1027cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (sec->shdr.sh_flags & SHF_ALLOC)
1028cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1029cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      sec->shdr.sh_addr += bias;
1030cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      sec->name = get_section_name (i + 1, &sec->shdr, main_shstrtab);
1031cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      sec->scn = elf_getscn (main, i + 1); /* Really just for ndx.  */
1032cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      sec->outscn = NULL;
1033cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      sec->strent = NULL;
1034cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ++undo_nalloc;
1035cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1036cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
1037cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      qsort (undo_sections, undo_nalloc,
1038cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     sizeof undo_sections[0], compare_sections_nonrel);
1039cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1040cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1041cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool fail = false;
1042cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  inline void check_match (bool match, Elf_Scn *scn, const char *name)
1043cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1044cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (!match)
1045cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
1046cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  fail = true;
1047cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  error (0, 0, _("cannot find matching section for [%Zu] '%s'"),
1048cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 elf_ndxscn (scn), name);
1049cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
1050cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1051cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1052cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *scn = NULL;
1053cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  while ((scn = elf_nextscn (debug, scn)) != NULL)
1054cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1055cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Shdr shdr_mem;
1056cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1057cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1058cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1059cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (!(shdr->sh_flags & SHF_ALLOC))
1060cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	continue;
1061cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1062cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const char *name = get_section_name (elf_ndxscn (scn), shdr,
1063cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					   debug_shstrtab);
1064cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1065cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (undo_sections != NULL)
1066cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
1067cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  struct section *sec = find_alloc_section (shdr, 0, name,
1068cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						    undo_sections,
1069cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						    undo_nalloc);
1070cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (sec != NULL)
1071cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1072cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      sec->outscn = scn;
1073cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      continue;
1074cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1075cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
1076cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1077cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* If there is no prelink info, we are just here to find
1078cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 the sections to give error messages about.  */
1079cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (size_t i = 0; shdr != NULL && i < nalloc; ++i)
1080cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (sections[i].outscn == scn)
1081cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  shdr = NULL;
1082cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      check_match (shdr == NULL, scn, name);
1083cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1084cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1085cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (fail)
1086cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    exit (EXIT_FAILURE);
1087cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1088cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Now we have lined up output sections for each of the original sections
1089cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     before prelinking.  Translate those to the prelinked sections.
1090cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     This matches what prelink's undo_sections does.  */
1091cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct section *split_bss = NULL;
1092cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (size_t i = 0; i < undo_nalloc; ++i)
1093cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1094cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const struct section *undo_sec = &undo_sections[i];
1095cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1096cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const char *name = undo_sec->name;
1097cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      scn = undo_sec->scn; /* This is just for elf_ndxscn.  */
1098cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1099cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (size_t j = 0; j < nalloc; ++j)
1100cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
1101cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  struct section *sec = &sections[j];
1102cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#define RELA_SCALED(field) \
1103cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  (2 * sec->shdr.field == 3 * undo_sec->shdr.field)
1104cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (sec->outscn == NULL
1105cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      && sec->shdr.sh_name == undo_sec->shdr.sh_name
1106cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      && sec->shdr.sh_flags == undo_sec->shdr.sh_flags
1107cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      && sec->shdr.sh_addralign == undo_sec->shdr.sh_addralign
1108cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      && (((sec->shdr.sh_type == undo_sec->shdr.sh_type
1109cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    && sec->shdr.sh_entsize == undo_sec->shdr.sh_entsize
1110cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    && (sec->shdr.sh_size == undo_sec->shdr.sh_size
1111cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			|| (sec->shdr.sh_size > undo_sec->shdr.sh_size
1112cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    && main_ehdr->e_type == ET_EXEC
1113cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    && !strcmp (sec->name, ".dynstr"))))
1114cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   || (sec->shdr.sh_size == undo_sec->shdr.sh_size
1115cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       && ((sec->shdr.sh_entsize == undo_sec->shdr.sh_entsize
1116cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    && undo_sec->shdr.sh_type == SHT_NOBITS)
1117cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   || undo_sec->shdr.sh_type == SHT_PROGBITS)
1118cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       && !strcmp (sec->name, ".plt")))
1119cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  || (sec->shdr.sh_type == SHT_RELA
1120cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      && undo_sec->shdr.sh_type == SHT_REL
1121cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      && RELA_SCALED (sh_entsize) && RELA_SCALED (sh_size))
1122cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  || (sec->shdr.sh_entsize == undo_sec->shdr.sh_entsize
1123cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      && (sec->shdr.sh_type == undo_sec->shdr.sh_type
1124cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  || (sec->shdr.sh_type == SHT_PROGBITS
1125cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      && undo_sec->shdr.sh_type == SHT_NOBITS))
1126cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      && sec->shdr.sh_size < undo_sec->shdr.sh_size
1127cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      && (!strcmp (sec->name, ".bss")
1128cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  || !strcmp (sec->name, ".sbss"))
1129cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      && (split_bss = sec) > sections)))
1130cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1131cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      sec->outscn = undo_sec->outscn;
1132cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      undo_sec = NULL;
1133cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      break;
1134cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1135cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
1136cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1137cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      check_match (undo_sec == NULL, scn, name);
1138cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1139cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1140cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  free (undo_sections);
1141cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1142cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (fail)
1143cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    exit (EXIT_FAILURE);
1144cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1145cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return split_bss;
1146cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
1147cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1148cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Create new .shstrtab contents, subroutine of copy_elided_sections.
1149cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   This can't be open coded there and still use variable-length auto arrays,
1150cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   since the end of our block would free other VLAs too.  */
1151cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic Elf_Data *
1152cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengnew_shstrtab (Elf *unstripped, size_t unstripped_shnum,
1153cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      Elf_Data *shstrtab, size_t unstripped_shstrndx,
1154cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      struct section *sections, size_t stripped_shnum,
1155cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      struct Ebl_Strtab *strtab)
1156cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
1157cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (strtab == NULL)
1158cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return NULL;
1159cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1160cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct Ebl_Strent *unstripped_strent[unstripped_shnum - 1];
1161cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  memset (unstripped_strent, 0, sizeof unstripped_strent);
1162cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (struct section *sec = sections;
1163cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng       sec < &sections[stripped_shnum - 1];
1164cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng       ++sec)
1165cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (sec->outscn != NULL)
1166cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
1167cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (sec->strent == NULL)
1168cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  {
1169cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    sec->strent = ebl_strtabadd (strtab, sec->name, 0);
1170cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ELF_CHECK (sec->strent != NULL,
1171cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       _("cannot add section name to string table: %s"));
1172cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  }
1173cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	unstripped_strent[elf_ndxscn (sec->outscn) - 1] = sec->strent;
1174cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
1175cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1176cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Add names of sections we aren't touching.  */
1177cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (size_t i = 0; i < unstripped_shnum - 1; ++i)
1178cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (unstripped_strent[i] == NULL)
1179cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
1180cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	Elf_Scn *scn = elf_getscn (unstripped, i + 1);
1181cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Shdr shdr_mem;
1182cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1183cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	const char *name = get_section_name (i + 1, shdr, shstrtab);
1184cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	unstripped_strent[i] = ebl_strtabadd (strtab, name, 0);
1185cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ELF_CHECK (unstripped_strent[i] != NULL,
1186cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   _("cannot add section name to string table: %s"));
1187cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
1188cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    else
1189cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      unstripped_strent[i] = NULL;
1190cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1191cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Now finalize the string table so we can get offsets.  */
1192cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *strtab_data = elf_getdata (elf_getscn (unstripped,
1193cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						   unstripped_shstrndx), NULL);
1194cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ELF_CHECK (elf_flagdata (strtab_data, ELF_C_SET, ELF_F_DIRTY),
1195cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     _("cannot update section header string table data: %s"));
1196cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ebl_strtabfinalize (strtab, strtab_data);
1197cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1198cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Update the sh_name fields of sections we aren't modifying later.  */
1199cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (size_t i = 0; i < unstripped_shnum - 1; ++i)
1200cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (unstripped_strent[i] != NULL)
1201cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
1202cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	Elf_Scn *scn = elf_getscn (unstripped, i + 1);
1203cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Shdr shdr_mem;
1204cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1205cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	shdr->sh_name = ebl_strtaboffset (unstripped_strent[i]);
1206cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (i + 1 == unstripped_shstrndx)
1207cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  shdr->sh_size = strtab_data->d_size;
1208cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ELF_CHECK (gelf_update_shdr (scn, shdr),
1209cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   _("cannot update section header: %s"));
1210cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
1211cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1212cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return strtab_data;
1213cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
1214cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1215cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Fill in any SHT_NOBITS sections in UNSTRIPPED by
1216cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   copying their contents and sh_type from STRIPPED.  */
1217cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
1218cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcopy_elided_sections (Elf *unstripped, Elf *stripped,
1219cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      const GElf_Ehdr *stripped_ehdr, GElf_Addr bias)
1220cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
1221cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t unstripped_shstrndx;
1222cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ELF_CHECK (elf_getshstrndx (unstripped, &unstripped_shstrndx) == 0,
1223cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     _("cannot get section header string table section index: %s"));
1224cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1225cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t stripped_shstrndx;
1226cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ELF_CHECK (elf_getshstrndx (stripped, &stripped_shstrndx) == 0,
1227cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     _("cannot get section header string table section index: %s"));
1228cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1229cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t unstripped_shnum;
1230cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ELF_CHECK (elf_getshnum (unstripped, &unstripped_shnum) == 0,
1231cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     _("cannot get section count: %s"));
1232cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1233cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t stripped_shnum;
1234cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ELF_CHECK (elf_getshnum (stripped, &stripped_shnum) == 0,
1235cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     _("cannot get section count: %s"));
1236cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1237cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Cache the stripped file's section details.  */
1238cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct section sections[stripped_shnum - 1];
1239cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *scn = NULL;
1240cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  while ((scn = elf_nextscn (stripped, scn)) != NULL)
1241cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1242cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      size_t i = elf_ndxscn (scn) - 1;
1243cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Shdr *shdr = gelf_getshdr (scn, &sections[i].shdr);
1244cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1245cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      sections[i].name = elf_strptr (stripped, stripped_shstrndx,
1246cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				     shdr->sh_name);
1247cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (sections[i].name == NULL)
1248cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	error (EXIT_FAILURE, 0, _("cannot read section [%Zu] name: %s"),
1249cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       elf_ndxscn (scn), elf_errmsg (-1));
1250cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      sections[i].scn = scn;
1251cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      sections[i].outscn = NULL;
1252cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      sections[i].strent = NULL;
1253cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1254cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1255cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const struct section *stripped_symtab = NULL;
1256cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1257cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Sort the sections, allocated by address and others after.  */
1258cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  qsort (sections, stripped_shnum - 1, sizeof sections[0],
1259cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 stripped_ehdr->e_type == ET_REL
1260cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 ? compare_sections_rel : compare_sections_nonrel);
1261cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t nalloc = stripped_shnum - 1;
1262cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  while (nalloc > 0 && !(sections[nalloc - 1].shdr.sh_flags & SHF_ALLOC))
1263cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1264cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      --nalloc;
1265cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (sections[nalloc].shdr.sh_type == SHT_SYMTAB)
1266cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	stripped_symtab = &sections[nalloc];
1267cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1268cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1269cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Locate a matching unallocated section in SECTIONS.  */
1270cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  inline struct section *find_unalloc_section (const GElf_Shdr *shdr,
1271cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					       const char *name)
1272cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1273cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      size_t l = nalloc, u = stripped_shnum - 1;
1274cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      while (l < u)
1275cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
1276cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  size_t i = (l + u) / 2;
1277cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  struct section *sec = &sections[i];
1278cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  int cmp = compare_unalloc_sections (shdr, &sec->shdr,
1279cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					      name, sec->name);
1280cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (cmp < 0)
1281cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    u = i;
1282cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else if (cmp > 0)
1283cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    l = i + 1;
1284cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else
1285cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    return sec;
1286cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
1287cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return NULL;
1288cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1289cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1290cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *shstrtab = elf_getdata (elf_getscn (unstripped,
1291cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						unstripped_shstrndx), NULL);
1292cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ELF_CHECK (shstrtab != NULL,
1293cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     _("cannot read section header string table: %s"));
1294cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1295cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Match each debuginfo section with its corresponding stripped section.  */
1296cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool check_prelink = false;
1297cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *unstripped_symtab = NULL;
1298cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t unstripped_strtab_ndx = SHN_UNDEF;
1299cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t alloc_avail = 0;
1300cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  scn = NULL;
1301cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  while ((scn = elf_nextscn (unstripped, scn)) != NULL)
1302cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1303cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Shdr shdr_mem;
1304cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1305cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1306cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1307cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (shdr->sh_type == SHT_SYMTAB)
1308cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
1309cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  unstripped_symtab = scn;
1310cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  unstripped_strtab_ndx = shdr->sh_link;
1311cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  continue;
1312cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
1313cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1314cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const size_t ndx = elf_ndxscn (scn);
1315cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (ndx == unstripped_shstrndx)
1316cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	continue;
1317cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1318cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const char *name = get_section_name (ndx, shdr, shstrtab);
1319cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1320cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      struct section *sec = NULL;
1321cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (shdr->sh_flags & SHF_ALLOC)
1322cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
1323cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (stripped_ehdr->e_type != ET_REL)
1324cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1325cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* Look for the section that matches.  */
1326cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      sec = find_alloc_section (shdr, bias, name, sections, nalloc);
1327cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (sec == NULL)
1328cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		{
1329cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  /* We couldn't figure it out.  It may be a prelink issue.  */
1330cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  check_prelink = true;
1331cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  continue;
1332cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		}
1333cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1334cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else
1335cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1336cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* The sh_addr of allocated sections does not help us,
1337cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 but the order usually matches.  */
1338cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (likely (sections_match (sections, alloc_avail, shdr, name)))
1339cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		sec = &sections[alloc_avail++];
1340cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      else
1341cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		for (size_t i = alloc_avail + 1; i < nalloc; ++i)
1342cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  if (sections_match (sections, i, shdr, name))
1343cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    {
1344cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      sec = &sections[i];
1345cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      break;
1346cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    }
1347cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1348cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
1349cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else
1350cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
1351cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Look for the section that matches.  */
1352cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  sec = find_unalloc_section (shdr, name);
1353cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (sec == NULL)
1354cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1355cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* An additional unallocated section is fine if not SHT_NOBITS.
1356cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 We looked it up anyway in case it's an unallocated section
1357cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 copied in both files (e.g. SHT_NOTE), and don't keep both.  */
1358cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (shdr->sh_type != SHT_NOBITS)
1359cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		continue;
1360cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1361cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* Somehow some old .debug files wound up with SHT_NOBITS
1362cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 .comment sections, so let those pass.  */
1363cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (!strcmp (name, ".comment"))
1364cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		continue;
1365cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1366cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
1367cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1368cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (sec == NULL)
1369cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	error (EXIT_FAILURE, 0,
1370cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       _("cannot find matching section for [%Zu] '%s'"),
1371cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       elf_ndxscn (scn), name);
1372cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1373cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      sec->outscn = scn;
1374cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1375cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1376cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* If that failed due to changes made by prelink, we take another tack.
1377cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     We keep track of a .bss section that was partly split into .dynbss
1378cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     so that collect_symbols can update symbols' st_shndx fields.  */
1379cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct section *split_bss = NULL;
1380cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (check_prelink)
1381cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1382cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Elf_Data *data = elf_getdata (elf_getscn (stripped, stripped_shstrndx),
1383cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				    NULL);
1384cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (data != NULL,
1385cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 _("cannot read section header string table: %s"));
1386cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      split_bss = find_alloc_sections_prelink (unstripped, shstrtab,
1387cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					       stripped, stripped_ehdr,
1388cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					       data, bias, sections,
1389cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					       nalloc, stripped_shnum - 1);
1390cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1391cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1392cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Make sure each main file section has a place to go.  */
1393cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const struct section *stripped_dynsym = NULL;
1394cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t debuglink = SHN_UNDEF;
1395cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t ndx_section[stripped_shnum - 1];
1396cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct Ebl_Strtab *strtab = NULL;
1397cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (struct section *sec = sections;
1398cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng       sec < &sections[stripped_shnum - 1];
1399cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng       ++sec)
1400cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1401cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      size_t secndx = elf_ndxscn (sec->scn);
1402cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1403cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (sec->outscn == NULL)
1404cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
1405cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* We didn't find any corresponding section for this.  */
1406cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1407cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (secndx == stripped_shstrndx)
1408cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1409cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* We only need one .shstrtab.  */
1410cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ndx_section[secndx - 1] = unstripped_shstrndx;
1411cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      continue;
1412cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1413cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1414cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (unstripped_symtab != NULL && sec == stripped_symtab)
1415cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1416cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* We don't need a second symbol table.  */
1417cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ndx_section[secndx - 1] = elf_ndxscn (unstripped_symtab);
1418cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      continue;
1419cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1420cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1421cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (unstripped_symtab != NULL && stripped_symtab != NULL
1422cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      && secndx == stripped_symtab->shdr.sh_link)
1423cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1424cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* ... nor its string table.  */
1425cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      GElf_Shdr shdr_mem;
1426cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      GElf_Shdr *shdr = gelf_getshdr (unstripped_symtab, &shdr_mem);
1427cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1428cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ndx_section[secndx - 1] = shdr->sh_link;
1429cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      continue;
1430cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1431cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1432cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (!(sec->shdr.sh_flags & SHF_ALLOC)
1433cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      && !strcmp (sec->name, ".gnu_debuglink"))
1434cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1435cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* This was created by stripping.  We don't want it.  */
1436cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      debuglink = secndx;
1437cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ndx_section[secndx - 1] = SHN_UNDEF;
1438cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      continue;
1439cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1440cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1441cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  sec->outscn = elf_newscn (unstripped);
1442cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  Elf_Data *newdata = elf_newdata (sec->outscn);
1443cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ELF_CHECK (newdata != NULL && gelf_update_shdr (sec->outscn,
1444cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng							  &sec->shdr),
1445cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     _("cannot add new section: %s"));
1446cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1447cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (strtab == NULL)
1448cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    strtab = ebl_strtabinit (true);
1449cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  sec->strent = ebl_strtabadd (strtab, sec->name, 0);
1450cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ELF_CHECK (sec->strent != NULL,
1451cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     _("cannot add section name to string table: %s"));
1452cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
1453cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1454cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Cache the mapping of original section indices to output sections.  */
1455cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ndx_section[secndx - 1] = elf_ndxscn (sec->outscn);
1456cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1457cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1458cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* We added some sections, so we need a new shstrtab.  */
1459cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *strtab_data = new_shstrtab (unstripped, unstripped_shnum,
1460cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					shstrtab, unstripped_shstrndx,
1461cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					sections, stripped_shnum,
1462cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					strtab);
1463cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1464cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Get the updated section count.  */
1465cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ELF_CHECK (elf_getshnum (unstripped, &unstripped_shnum) == 0,
1466cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     _("cannot get section count: %s"));
1467cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1468cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool placed[unstripped_shnum - 1];
1469cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  memset (placed, 0, sizeof placed);
1470cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1471cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Now update the output sections and copy in their data.  */
1472cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Off offset = 0;
1473cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (const struct section *sec = sections;
1474cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng       sec < &sections[stripped_shnum - 1];
1475cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng       ++sec)
1476cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (sec->outscn != NULL)
1477cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
1478cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Shdr shdr_mem;
1479cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Shdr *shdr = gelf_getshdr (sec->outscn, &shdr_mem);
1480cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1481cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1482cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	/* In an ET_REL file under --relocate, the sh_addr of SHF_ALLOC
1483cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   sections will have been set nonzero by relocation.  This
1484cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   touched the shdrs of whichever file had the symtab.  sh_addr
1485cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   is still zero in the corresponding shdr.  The relocated
1486cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   address is what we want to use.  */
1487cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (stripped_ehdr->e_type != ET_REL
1488cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    || !(shdr_mem.sh_flags & SHF_ALLOC)
1489cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    || shdr_mem.sh_addr == 0)
1490cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  shdr_mem.sh_addr = sec->shdr.sh_addr;
1491cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1492cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	shdr_mem.sh_type = sec->shdr.sh_type;
1493cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	shdr_mem.sh_size = sec->shdr.sh_size;
1494cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	shdr_mem.sh_info = sec->shdr.sh_info;
1495cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	shdr_mem.sh_link = sec->shdr.sh_link;
1496cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (sec->shdr.sh_link != SHN_UNDEF)
1497cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  shdr_mem.sh_link = ndx_section[sec->shdr.sh_link - 1];
1498cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (shdr_mem.sh_flags & SHF_INFO_LINK)
1499cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  shdr_mem.sh_info = ndx_section[sec->shdr.sh_info - 1];
1500cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1501cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (strtab != NULL)
1502cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  shdr_mem.sh_name = ebl_strtaboffset (sec->strent);
1503cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1504cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	Elf_Data *indata = elf_getdata (sec->scn, NULL);
1505cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ELF_CHECK (indata != NULL, _("cannot get section data: %s"));
1506cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	Elf_Data *outdata = elf_getdata (sec->outscn, NULL);
1507cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ELF_CHECK (outdata != NULL, _("cannot copy section data: %s"));
1508cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	*outdata = *indata;
1509cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	elf_flagdata (outdata, ELF_C_SET, ELF_F_DIRTY);
1510cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1511cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	/* Preserve the file layout of the allocated sections.  */
1512cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (stripped_ehdr->e_type != ET_REL && (shdr_mem.sh_flags & SHF_ALLOC))
1513cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  {
1514cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    shdr_mem.sh_offset = sec->shdr.sh_offset;
1515cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    placed[elf_ndxscn (sec->outscn) - 1] = true;
1516cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1517cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    const GElf_Off end_offset = (shdr_mem.sh_offset
1518cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					 + (shdr_mem.sh_type == SHT_NOBITS
1519cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					    ? 0 : shdr_mem.sh_size));
1520cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (end_offset > offset)
1521cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      offset = end_offset;
1522cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  }
1523cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1524cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ELF_CHECK (gelf_update_shdr (sec->outscn, &shdr_mem),
1525cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   _("cannot update section header: %s"));
1526cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1527cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (shdr_mem.sh_type == SHT_SYMTAB || shdr_mem.sh_type == SHT_DYNSYM)
1528cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  {
1529cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    /* We must adjust all the section indices in the symbol table.  */
1530cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1531cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    Elf_Data *shndxdata = NULL;	/* XXX */
1532cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1533cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    for (size_t i = 1; i < shdr_mem.sh_size / shdr_mem.sh_entsize; ++i)
1534cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      {
1535cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		GElf_Sym sym_mem;
1536cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		GElf_Word shndx = SHN_UNDEF;
1537cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		GElf_Sym *sym = gelf_getsymshndx (outdata, shndxdata,
1538cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						  i, &sym_mem, &shndx);
1539cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		ELF_CHECK (sym != NULL,
1540cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   _("cannot get symbol table entry: %s"));
1541cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		if (sym->st_shndx != SHN_XINDEX)
1542cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  shndx = sym->st_shndx;
1543cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1544cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		if (shndx != SHN_UNDEF && shndx < SHN_LORESERVE)
1545cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  {
1546cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    if (shndx >= stripped_shnum)
1547cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      error (EXIT_FAILURE, 0,
1548cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     _("symbol [%Zu] has invalid section index"), i);
1549cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1550cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    shndx = ndx_section[shndx - 1];
1551cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    if (shndx < SHN_LORESERVE)
1552cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      {
1553cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			sym->st_shndx = shndx;
1554cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			shndx = SHN_UNDEF;
1555cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      }
1556cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    else
1557cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      sym->st_shndx = SHN_XINDEX;
1558cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1559cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    ELF_CHECK (gelf_update_symshndx (outdata, shndxdata,
1560cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						     i, sym, shndx),
1561cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       _("cannot update symbol table: %s"));
1562cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  }
1563cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      }
1564cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1565cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (shdr_mem.sh_type == SHT_SYMTAB)
1566cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      stripped_symtab = sec;
1567cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (shdr_mem.sh_type == SHT_DYNSYM)
1568cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      stripped_dynsym = sec;
1569cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  }
1570cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
1571cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1572cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* We may need to update the symbol table.  */
1573cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *symdata = NULL;
1574cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct Ebl_Strtab *symstrtab = NULL;
1575cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *symstrdata = NULL;
1576cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (unstripped_symtab != NULL && (stripped_symtab != NULL
1577cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				    || check_prelink /* Section adjustments. */
1578cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				    || (stripped_ehdr->e_type != ET_REL
1579cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					&& bias != 0)))
1580cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1581cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Merge the stripped file's symbol table into the unstripped one.  */
1582cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const size_t stripped_nsym = (stripped_symtab == NULL ? 1
1583cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				    : (stripped_symtab->shdr.sh_size
1584cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				       / stripped_symtab->shdr.sh_entsize));
1585cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1586cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Shdr shdr_mem;
1587cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Shdr *shdr = gelf_getshdr (unstripped_symtab, &shdr_mem);
1588cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1589cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const size_t unstripped_nsym = shdr->sh_size / shdr->sh_entsize;
1590cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1591cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* First collect all the symbols from both tables.  */
1592cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1593cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const size_t total_syms = stripped_nsym - 1 + unstripped_nsym - 1;
1594cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      struct symbol symbols[total_syms];
1595cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      size_t symndx_map[total_syms];
1596cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1597cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (stripped_symtab != NULL)
1598cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	collect_symbols (unstripped, stripped_ehdr->e_type == ET_REL,
1599cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 stripped_symtab->scn,
1600cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 elf_getscn (stripped, stripped_symtab->shdr.sh_link),
1601cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 stripped_nsym, 0, ndx_section,
1602cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 symbols, symndx_map, NULL);
1603cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1604cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Elf_Scn *unstripped_strtab = elf_getscn (unstripped, shdr->sh_link);
1605cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      collect_symbols (unstripped, stripped_ehdr->e_type == ET_REL,
1606cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       unstripped_symtab, unstripped_strtab, unstripped_nsym,
1607cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       stripped_ehdr->e_type == ET_REL ? 0 : bias, NULL,
1608cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       &symbols[stripped_nsym - 1],
1609cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       &symndx_map[stripped_nsym - 1], split_bss);
1610cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1611cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Next, sort our array of all symbols.  */
1612cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      qsort (symbols, total_syms, sizeof symbols[0], compare_symbols);
1613cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1614cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Now we can weed out the duplicates.  Assign remaining symbols
1615cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 new slots, collecting a map from old indices to new.  */
1616cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      size_t nsym = 0;
1617cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (struct symbol *s = symbols; s < &symbols[total_syms]; ++s)
1618cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
1619cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Skip a section symbol for a removed section.  */
1620cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (s->shndx == SHN_UNDEF
1621cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      && GELF_ST_TYPE (s->info.info) == STT_SECTION)
1622cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1623cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      s->name = NULL;	/* Mark as discarded. */
1624cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      *s->map = STN_UNDEF;
1625cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      s->duplicate = NULL;
1626cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      continue;
1627cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1628cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1629cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  struct symbol *n = s;
1630cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  while (n + 1 < &symbols[total_syms] && !compare_symbols (s, n + 1))
1631cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ++n;
1632cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1633cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  while (s < n)
1634cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1635cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* This is a duplicate.  Its twin will get the next slot.  */
1636cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      s->name = NULL;	/* Mark as discarded. */
1637cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      s->duplicate = n->map;
1638cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ++s;
1639cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1640cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1641cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Allocate the next slot.  */
1642cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  *s->map = ++nsym;
1643cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
1644cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1645cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Now we sort again, to determine the order in the output.  */
1646cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      qsort (symbols, total_syms, sizeof symbols[0], compare_symbols_output);
1647cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1648cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (nsym < total_syms)
1649cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	/* The discarded symbols are now at the end of the table.  */
1650cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	assert (symbols[nsym].name == NULL);
1651cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1652cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Now a final pass updates the map with the final order,
1653cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 and builds up the new string table.  */
1654cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      symstrtab = ebl_strtabinit (true);
1655cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (size_t i = 0; i < nsym; ++i)
1656cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
1657cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  assert (symbols[i].name != NULL);
1658cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  assert (*symbols[i].map != 0);
1659cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  *symbols[i].map = 1 + i;
1660cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  symbols[i].strent = ebl_strtabadd (symstrtab, symbols[i].name, 0);
1661cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
1662cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1663cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Scan the discarded symbols too, just to update their slots
1664cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 in SYMNDX_MAP to refer to their live duplicates.  */
1665cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (size_t i = nsym; i < total_syms; ++i)
1666cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
1667cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  assert (symbols[i].name == NULL);
1668cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (symbols[i].duplicate == NULL)
1669cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    assert (*symbols[i].map == STN_UNDEF);
1670cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else
1671cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1672cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      assert (*symbols[i].duplicate != STN_UNDEF);
1673cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      *symbols[i].map = *symbols[i].duplicate;
1674cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1675cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
1676cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1677cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Now we are ready to write the new symbol table.  */
1678cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      symdata = elf_getdata (unstripped_symtab, NULL);
1679cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      symstrdata = elf_getdata (unstripped_strtab, NULL);
1680cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Elf_Data *shndxdata = NULL;	/* XXX */
1681cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1682cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ebl_strtabfinalize (symstrtab, symstrdata);
1683cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      elf_flagdata (symstrdata, ELF_C_SET, ELF_F_DIRTY);
1684cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1685cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      shdr->sh_size = symdata->d_size = (1 + nsym) * shdr->sh_entsize;
1686cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      symdata->d_buf = xmalloc (symdata->d_size);
1687cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1688cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Sym sym;
1689cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      memset (&sym, 0, sizeof sym);
1690cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, 0, &sym, SHN_UNDEF),
1691cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 _("cannot update symbol table: %s"));
1692cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1693cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      shdr->sh_info = 1;
1694cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (size_t i = 0; i < nsym; ++i)
1695cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
1696cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  struct symbol *s = &symbols[i];
1697cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1698cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Fill in the symbol details.  */
1699cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  sym.st_name = ebl_strtaboffset (s->strent);
1700cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  sym.st_value = s->value; /* Already biased to output address.  */
1701cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  sym.st_size = s->size;
1702cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  sym.st_shndx = s->shndx; /* Already mapped to output index.  */
1703cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  sym.st_info = s->info.info;
1704cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  sym.st_other = s->info.other;
1705cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1706cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Keep track of the number of leading local symbols.  */
1707cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (GELF_ST_BIND (sym.st_info) == STB_LOCAL)
1708cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1709cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      assert (shdr->sh_info == 1 + i);
1710cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      shdr->sh_info = 1 + i + 1;
1711cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1712cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1713cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, 1 + i,
1714cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					   &sym, SHN_UNDEF),
1715cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     _("cannot update symbol table: %s"));
1716cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1717cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
1718cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      elf_flagdata (symdata, ELF_C_SET, ELF_F_DIRTY);
1719cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (gelf_update_shdr (unstripped_symtab, shdr),
1720cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 _("cannot update section header: %s"));
1721cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1722cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (stripped_symtab != NULL)
1723cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
1724cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Adjust any relocations referring to the old symbol table.  */
1725cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  const size_t old_sh_link = elf_ndxscn (stripped_symtab->scn);
1726cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  for (const struct section *sec = sections;
1727cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       sec < &sections[stripped_shnum - 1];
1728cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       ++sec)
1729cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (sec->outscn != NULL && sec->shdr.sh_link == old_sh_link)
1730cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      adjust_relocs (sec->outscn, sec->scn, &sec->shdr,
1731cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     symndx_map, shdr);
1732cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
1733cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1734cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Also adjust references to the other old symbol table.  */
1735cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      adjust_all_relocs (unstripped, unstripped_symtab, shdr,
1736cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 &symndx_map[stripped_nsym - 1]);
1737cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1738cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else if (stripped_symtab != NULL && stripped_shnum != unstripped_shnum)
1739cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    check_symtab_section_symbols (unstripped,
1740cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  stripped_ehdr->e_type == ET_REL,
1741cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  stripped_symtab->scn,
1742cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  unstripped_shnum, unstripped_shstrndx,
1743cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  stripped_symtab->outscn,
1744cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  stripped_shnum, stripped_shstrndx,
1745cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  debuglink);
1746cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1747cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (stripped_dynsym != NULL)
1748cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    (void) check_symtab_section_symbols (unstripped,
1749cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					 stripped_ehdr->e_type == ET_REL,
1750cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					 stripped_dynsym->outscn,
1751cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					 unstripped_shnum,
1752cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					 unstripped_shstrndx,
1753cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					 stripped_dynsym->scn, stripped_shnum,
1754cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					 stripped_shstrndx, debuglink);
1755cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1756cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* We need to preserve the layout of the stripped file so the
1757cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     phdrs will match up.  This requires us to do our own layout of
1758cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     the added sections.  We do manual layout even for ET_REL just
1759cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     so we can try to match what the original probably had.  */
1760cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1761cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  elf_flagelf (unstripped, ELF_C_SET, ELF_F_LAYOUT);
1762cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1763cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (offset == 0)
1764cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    /* For ET_REL we are starting the layout from scratch.  */
1765cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    offset = gelf_fsize (unstripped, ELF_T_EHDR, 1, EV_CURRENT);
1766cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1767cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool skip_reloc = false;
1768cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  do
1769cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1770cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      skip_reloc = !skip_reloc;
1771cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (size_t i = 0; i < unstripped_shnum - 1; ++i)
1772cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (!placed[i])
1773cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  {
1774cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    scn = elf_getscn (unstripped, 1 + i);
1775cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1776cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    GElf_Shdr shdr_mem;
1777cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1778cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1779cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1780cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (skip_reloc
1781cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		&& (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
1782cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      continue;
1783cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1784cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    GElf_Off align = shdr->sh_addralign ?: 1;
1785cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    offset = (offset + align - 1) & -align;
1786cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    shdr->sh_offset = offset;
1787cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (shdr->sh_type != SHT_NOBITS)
1788cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      offset += shdr->sh_size;
1789cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1790cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ELF_CHECK (gelf_update_shdr (scn, shdr),
1791cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       _("cannot update section header: %s"));
1792cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1793cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (unstripped_shstrndx == 1 + i)
1794cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      {
1795cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		/* Place the section headers immediately after
1796cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   .shstrtab, and update the ELF header.  */
1797cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1798cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		GElf_Ehdr ehdr_mem;
1799cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		GElf_Ehdr *ehdr = gelf_getehdr (unstripped, &ehdr_mem);
1800cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		ELF_CHECK (ehdr != NULL, _("cannot get ELF header: %s"));
1801cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1802cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		GElf_Off sh_align = gelf_getclass (unstripped) * 4;
1803cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		offset = (offset + sh_align - 1) & -sh_align;
1804cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		ehdr->e_shnum = unstripped_shnum;
1805cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		ehdr->e_shoff = offset;
1806cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		offset += unstripped_shnum * ehdr->e_shentsize;
1807cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		ELF_CHECK (gelf_update_ehdr (unstripped, ehdr),
1808cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   _("cannot update ELF header: %s"));
1809cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      }
1810cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1811cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    placed[i] = true;
1812cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  }
1813cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    } while (skip_reloc);
1814cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1815cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (stripped_ehdr->e_phnum > 0)
1816cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ELF_CHECK (gelf_newphdr (unstripped, stripped_ehdr->e_phnum),
1817cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       _("cannot create program headers: %s"));
1818cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1819cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Copy each program header from the stripped file.  */
1820cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (uint_fast16_t i = 0; i < stripped_ehdr->e_phnum; ++i)
1821cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1822cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Phdr phdr_mem;
1823cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Phdr *phdr = gelf_getphdr (stripped, i, &phdr_mem);
1824cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (phdr != NULL, _("cannot get program header: %s"));
1825cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1826cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (gelf_update_phdr (unstripped, i, phdr),
1827cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 _("cannot update program header: %s"));
1828cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1829cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1830cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Finally, write out the file.  */
1831cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ELF_CHECK (elf_update (unstripped, ELF_C_WRITE) > 0,
1832cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     _("cannot write output file: %s"));
1833cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1834cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (strtab != NULL)
1835cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1836cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ebl_strtabfree (strtab);
1837cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      free (strtab_data->d_buf);
1838cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1839cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1840cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (symdata != NULL)
1841cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    free (symdata->d_buf);
1842cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (symstrtab != NULL)
1843cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1844cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ebl_strtabfree (symstrtab);
1845cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      free (symstrdata->d_buf);
1846cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1847cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
1848cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1849cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Process one pair of files, already opened.  */
1850cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
1851cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chenghandle_file (const char *output_file, bool create_dirs,
1852cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     Elf *stripped, const GElf_Ehdr *stripped_ehdr,
1853cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     Elf *unstripped)
1854cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
1855cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Determine the address bias between the debuginfo file and the main
1856cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     file, which may have been modified by prelinking.  */
1857cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Addr bias = 0;
1858cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (unstripped != NULL)
1859cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    for (uint_fast16_t i = 0; i < stripped_ehdr->e_phnum; ++i)
1860cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
1861cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Phdr phdr_mem;
1862cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Phdr *phdr = gelf_getphdr (stripped, i, &phdr_mem);
1863cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ELF_CHECK (phdr != NULL, _("cannot get program header: %s"));
1864cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (phdr->p_type == PT_LOAD)
1865cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  {
1866cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    GElf_Phdr unstripped_phdr_mem;
1867cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    GElf_Phdr *unstripped_phdr = gelf_getphdr (unstripped, i,
1868cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						       &unstripped_phdr_mem);
1869cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ELF_CHECK (unstripped_phdr != NULL,
1870cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       _("cannot get program header: %s"));
1871cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    bias = phdr->p_vaddr - unstripped_phdr->p_vaddr;
1872cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    break;
1873cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  }
1874cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
1875cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1876cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* One day we could adjust all the DWARF data (like prelink itself does).  */
1877cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (bias != 0)
1878cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1879cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (output_file == NULL)
1880cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	error (0, 0, _("\
1881cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengDWARF data not adjusted for prelinking bias; consider prelink -u"));
1882cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else
1883cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	error (0, 0, _("\
1884cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengDWARF data in '%s' not adjusted for prelinking bias; consider prelink -u"),
1885cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       output_file);
1886cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1887cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1888cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (output_file == NULL)
1889cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    /* Modify the unstripped file in place.  */
1890cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    copy_elided_sections (unstripped, stripped, stripped_ehdr, bias);
1891cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else
1892cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1893cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (create_dirs)
1894cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	make_directories (output_file);
1895cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1896cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Copy the unstripped file and then modify it.  */
1897cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      int outfd = open64 (output_file, O_RDWR | O_CREAT,
1898cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  stripped_ehdr->e_type == ET_REL ? 0666 : 0777);
1899cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (outfd < 0)
1900cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	error (EXIT_FAILURE, errno, _("cannot open '%s'"), output_file);
1901cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Elf *outelf = elf_begin (outfd, ELF_C_WRITE, NULL);
1902cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (outelf != NULL, _("cannot create ELF descriptor: %s"));
1903cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1904cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (unstripped == NULL)
1905cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
1906cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Actually, we are just copying out the main file as it is.  */
1907cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  copy_elf (outelf, stripped);
1908cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (stripped_ehdr->e_type != ET_REL)
1909cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    elf_flagelf (outelf, ELF_C_SET, ELF_F_LAYOUT);
1910cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ELF_CHECK (elf_update (outelf, ELF_C_WRITE) > 0,
1911cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     _("cannot write output file: %s"));
1912cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
1913cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else
1914cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
1915cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  copy_elf (outelf, unstripped);
1916cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  copy_elided_sections (outelf, stripped, stripped_ehdr, bias);
1917cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
1918cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1919cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      elf_end (outelf);
1920cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      close (outfd);
1921cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1922cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
1923cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1924cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic int
1925cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengopen_file (const char *file, bool writable)
1926cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
1927cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  int fd = open64 (file, writable ? O_RDWR : O_RDONLY);
1928cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (fd < 0)
1929cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    error (EXIT_FAILURE, errno, _("cannot open '%s'"), file);
1930cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return fd;
1931cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
1932cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1933cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Handle a pair of files we need to open by name.  */
1934cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
1935cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chenghandle_explicit_files (const char *output_file, bool create_dirs,
1936cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       const char *stripped_file, const char *unstripped_file)
1937cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
1938cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  int stripped_fd = open_file (stripped_file, false);
1939cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf *stripped = elf_begin (stripped_fd, ELF_C_READ, NULL);
1940cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Ehdr stripped_ehdr;
1941cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ELF_CHECK (gelf_getehdr (stripped, &stripped_ehdr),
1942cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     _("cannot create ELF descriptor: %s"));
1943cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1944cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  int unstripped_fd = -1;
1945cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf *unstripped = NULL;
1946cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (unstripped_file != NULL)
1947cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1948cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      unstripped_fd = open_file (unstripped_file, output_file == NULL);
1949cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      unstripped = elf_begin (unstripped_fd,
1950cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      (output_file == NULL ? ELF_C_RDWR : ELF_C_READ),
1951cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      NULL);
1952cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Ehdr unstripped_ehdr;
1953cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ELF_CHECK (gelf_getehdr (unstripped, &unstripped_ehdr),
1954cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 _("cannot create ELF descriptor: %s"));
1955cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1956cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (memcmp (stripped_ehdr.e_ident, unstripped_ehdr.e_ident, EI_NIDENT)
1957cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  || stripped_ehdr.e_type != unstripped_ehdr.e_type
1958cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  || stripped_ehdr.e_machine != unstripped_ehdr.e_machine
1959cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  || stripped_ehdr.e_phnum != unstripped_ehdr.e_phnum)
1960cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	error (EXIT_FAILURE, 0, _("'%s' and '%s' do not seem to match"),
1961cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       stripped_file, unstripped_file);
1962cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1963cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1964cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  handle_file (output_file, create_dirs, stripped, &stripped_ehdr, unstripped);
1965cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1966cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  elf_end (stripped);
1967cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  close (stripped_fd);
1968cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1969cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  elf_end (unstripped);
1970cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  close (unstripped_fd);
1971cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
1972cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1973cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1974cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Handle a pair of files opened implicitly by libdwfl for one module.  */
1975cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
1976cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chenghandle_dwfl_module (const char *output_file, bool create_dirs,
1977cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    Dwfl_Module *mod, bool all, bool ignore, bool relocate)
1978cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
1979cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Addr bias;
1980cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf *stripped = dwfl_module_getelf (mod, &bias);
1981cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (stripped == NULL)
1982cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1983cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (ignore)
1984cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	return;
1985cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1986cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const char *file;
1987cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
1988cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					      NULL, NULL, &file, NULL);
1989cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (file == NULL)
1990cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	error (EXIT_FAILURE, 0,
1991cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       _("cannot find stripped file for module '%s': %s"),
1992cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       modname, dwfl_errmsg (-1));
1993cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else
1994cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	error (EXIT_FAILURE, 0,
1995cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       _("cannot open stripped file '%s' for module '%s': %s"),
1996cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       modname, file, dwfl_errmsg (-1));
1997cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1998cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1999cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf *debug = dwarf_getelf (dwfl_module_getdwarf (mod, &bias));
2000cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (debug == NULL && !all)
2001cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2002cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (ignore)
2003cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	return;
2004cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2005cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const char *file;
2006cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
2007cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					      NULL, NULL, NULL, &file);
2008cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (file == NULL)
2009cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	error (EXIT_FAILURE, 0,
2010cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       _("cannot find debug file for module '%s': %s"),
2011cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       modname, dwfl_errmsg (-1));
2012cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else
2013cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	error (EXIT_FAILURE, 0,
2014cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       _("cannot open debug file '%s' for module '%s': %s"),
2015cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       modname, file, dwfl_errmsg (-1));
2016cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2017cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2018cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (debug == stripped)
2019cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2020cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (all)
2021cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	debug = NULL;
2022cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else
2023cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
2024cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  const char *file;
2025cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
2026cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						  NULL, NULL, &file, NULL);
2027cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  error (EXIT_FAILURE, 0, _("module '%s' file '%s' is not stripped"),
2028cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 modname, file);
2029cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
2030cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2031cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2032cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Ehdr stripped_ehdr;
2033cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ELF_CHECK (gelf_getehdr (stripped, &stripped_ehdr),
2034cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     _("cannot create ELF descriptor: %s"));
2035cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2036cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (stripped_ehdr.e_type == ET_REL)
2037cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2038cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (!relocate)
2039cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
2040cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* We can't use the Elf handles already open,
2041cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     because the DWARF sections have been relocated.  */
2042cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2043cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  const char *stripped_file = NULL;
2044cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  const char *unstripped_file = NULL;
2045cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  (void) dwfl_module_info (mod, NULL, NULL, NULL, NULL, NULL,
2046cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				   &stripped_file, &unstripped_file);
2047cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2048cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  handle_explicit_files (output_file, create_dirs,
2049cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				 stripped_file, unstripped_file);
2050cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  return;
2051cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
2052cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2053cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Relocation is what we want!  This ensures that all sections that can
2054cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 get sh_addr values assigned have them, even ones not used in DWARF.
2055cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 They might still be used in the symbol table.  */
2056cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (dwfl_module_relocations (mod) < 0)
2057cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	error (EXIT_FAILURE, 0,
2058cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       _("cannot cache section addresses for module '%s': %s"),
2059cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       dwfl_module_info (mod, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
2060cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       dwfl_errmsg (-1));
2061cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2062cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2063cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  handle_file (output_file, create_dirs, stripped, &stripped_ehdr, debug);
2064cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
2065cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2066cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Handle one module being written to the output directory.  */
2067cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
2068cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chenghandle_output_dir_module (const char *output_dir, Dwfl_Module *mod,
2069cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  bool all, bool ignore, bool modnames, bool relocate)
2070cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2071cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (! modnames)
2072cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2073cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Make sure we've searched for the ELF file.  */
2074cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Addr bias;
2075cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      (void) dwfl_module_getelf (mod, &bias);
2076cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2077cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2078cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const char *file;
2079cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const char *name = dwfl_module_info (mod, NULL, NULL, NULL,
2080cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				       NULL, NULL, &file, NULL);
2081cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2082cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (file == NULL && ignore)
2083cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return;
2084cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2085cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  char *output_file;
2086cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (asprintf (&output_file, "%s/%s", output_dir, modnames ? name : file) < 0)
2087cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    error (EXIT_FAILURE, 0, _("memory exhausted"));
2088cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2089cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  handle_dwfl_module (output_file, true, mod, all, ignore, relocate);
2090cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
2091cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2092cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2093cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
2094cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chenglist_module (Dwfl_Module *mod)
2095cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2096cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Make sure we have searched for the files.  */
2097cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Addr bias;
2098cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool have_elf = dwfl_module_getelf (mod, &bias) != NULL;
2099cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool have_dwarf = dwfl_module_getdwarf (mod, &bias) != NULL;
2100cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2101cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const char *file;
2102cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const char *debug;
2103cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Dwarf_Addr start;
2104cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Dwarf_Addr end;
2105cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const char *name = dwfl_module_info (mod, NULL, &start, &end,
2106cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				       NULL, NULL, &file, &debug);
2107cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (file != NULL && debug != NULL && (debug == file || !strcmp (debug, file)))
2108cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    debug = ".";
2109cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2110cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const unsigned char *id;
2111cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Addr id_vaddr;
2112cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  int id_len = dwfl_module_build_id (mod, &id, &id_vaddr);
2113cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2114cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  printf ("%#" PRIx64 "+%#" PRIx64 " ", start, end - start);
2115cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2116cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (id_len > 0)
2117cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2118cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      do
2119cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	printf ("%02" PRIx8, *id++);
2120cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      while (--id_len > 0);
2121cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (id_vaddr != 0)
2122cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	printf ("@%#" PRIx64, id_vaddr);
2123cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2124cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else
2125cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    putchar ('-');
2126cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2127cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  printf (" %s %s %s\n",
2128cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  file ?: have_elf ? "." : "-",
2129cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  debug ?: have_dwarf ? "." : "-",
2130cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  name);
2131cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
2132cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2133cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2134cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstruct match_module_info
2135cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2136cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  char **patterns;
2137cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Dwfl_Module *found;
2138cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool match_files;
2139cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng};
2140cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2141cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic int
2142cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengmatch_module (Dwfl_Module *mod,
2143cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      void **userdata __attribute__ ((unused)),
2144cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      const char *name,
2145cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      Dwarf_Addr start __attribute__ ((unused)),
2146cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      void *arg)
2147cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2148cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct match_module_info *info = arg;
2149cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2150cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (info->patterns[0] == NULL) /* Match all.  */
2151cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2152cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    match:
2153cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      info->found = mod;
2154cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return DWARF_CB_ABORT;
2155cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2156cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2157cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (info->match_files)
2158cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2159cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Make sure we've searched for the ELF file.  */
2160cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Addr bias;
2161cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      (void) dwfl_module_getelf (mod, &bias);
2162cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2163cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const char *file;
2164cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const char *check = dwfl_module_info (mod, NULL, NULL, NULL,
2165cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					    NULL, NULL, &file, NULL);
2166cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      assert (check == name);
2167cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (file == NULL)
2168cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	return DWARF_CB_OK;
2169cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2170cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      name = file;
2171cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2172cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2173cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (char **p = info->patterns; *p != NULL; ++p)
2174cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (fnmatch (*p, name, 0) == 0)
2175cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      goto match;
2176cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2177cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return DWARF_CB_OK;
2178cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
2179cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2180cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Handle files opened implicitly via libdwfl.  */
2181cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
2182cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chenghandle_implicit_modules (const struct arg_info *info)
2183cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2184cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct match_module_info mmi = { info->args, NULL, info->match_files };
2185cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  inline ptrdiff_t next (ptrdiff_t offset)
2186cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2187cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return dwfl_getmodules (info->dwfl, &match_module, &mmi, offset);
2188cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2189cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ptrdiff_t offset = next (0);
2190cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (offset == 0)
2191cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    error (EXIT_FAILURE, 0, _("no matching modules found"));
2192cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2193cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (info->list)
2194cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    do
2195cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      list_module (mmi.found);
2196cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    while ((offset = next (offset)) > 0);
2197cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else if (info->output_dir == NULL)
2198cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2199cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (next (offset) != 0)
2200cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	error (EXIT_FAILURE, 0, _("matched more than one module"));
2201cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      handle_dwfl_module (info->output_file, false, mmi.found,
2202cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  info->all, info->ignore, info->relocate);
2203cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2204cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else
2205cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    do
2206cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      handle_output_dir_module (info->output_dir, mmi.found,
2207cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				info->all, info->ignore,
2208cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				info->modnames, info->relocate);
2209cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    while ((offset = next (offset)) > 0);
2210cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
2211cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2212cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengint
2213cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengmain (int argc, char **argv)
2214cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2215cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Make memory leak detection possible.  */
2216cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  mtrace ();
2217cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2218cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* We use no threads here which can interfere with handling a stream.  */
2219cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  __fsetlocking (stdin, FSETLOCKING_BYCALLER);
2220cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  __fsetlocking (stdout, FSETLOCKING_BYCALLER);
2221cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  __fsetlocking (stderr, FSETLOCKING_BYCALLER);
2222cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2223cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Set locale.  */
2224cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  setlocale (LC_ALL, "");
2225cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2226cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Make sure the message catalog can be found.  */
2227cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
2228cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2229cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Initialize the message catalog.  */
2230cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  textdomain (PACKAGE_TARNAME);
2231cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2232cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Parse and process arguments.  */
2233cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const struct argp_child argp_children[] =
2234cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2235cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
2236cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	.argp = dwfl_standard_argp (),
2237cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	.header = N_("Input selection options:"),
2238cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	.group = 1,
2239cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      },
2240cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      { .argp = NULL },
2241cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    };
2242cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const struct argp argp =
2243cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2244cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      .options = options,
2245cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      .parser = parse_opt,
2246cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      .children = argp_children,
2247cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      .args_doc = N_("STRIPPED-FILE DEBUG-FILE\n[MODULE...]"),
2248cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      .doc = N_("\
2249cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengCombine stripped files with separate symbols and debug information.\v\
2250cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengThe first form puts the result in DEBUG-FILE if -o was not given.\n\
2251cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng\n\
2252cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengMODULE arguments give file name patterns matching modules to process.\n\
2253cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengWith -f these match the file name of the main (stripped) file \
2254cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng(slashes are never special), otherwise they match the simple module names.  \
2255cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengWith no arguments, process all modules found.\n\
2256cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng\n\
2257cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengMultiple modules are written to files under OUTPUT-DIRECTORY, \
2258cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcreating subdirectories as needed.  \
2259cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengWith -m these files have simple module names, otherwise they have the \
2260cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengname of the main file complete with directory underneath OUTPUT-DIRECTORY.\n\
2261cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng\n\
2262cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengWith -n no files are written, but one line to standard output for each module:\
2263cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng\n\tSTART+SIZE BUILDID FILE DEBUGFILE MODULENAME\n\
2264cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengSTART and SIZE are hexadecimal giving the address bounds of the module.  \
2265cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengBUILDID is hexadecimal for the build ID bits, or - if no ID is known; \
2266cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengthe hexadecimal may be followed by @0xADDR giving the address where the \
2267cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengID resides if that is known.  \
2268cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengFILE is the file name found for the module, or - if none was found, \
2269cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengor . if an ELF image is available but not from any named file.  \
2270cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengDEBUGFILE is the separate debuginfo file name, \
2271cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengor - if no debuginfo was found, or . if FILE contains the debug information.\
2272cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng")
2273cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    };
2274cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2275cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  int remaining;
2276cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct arg_info info = { .args = NULL };
2277cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  error_t result = argp_parse (&argp, argc, argv, 0, &remaining, &info);
2278cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (result == ENOSYS)
2279cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    assert (info.dwfl == NULL);
2280cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else if (result)
2281cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return EXIT_FAILURE;
2282cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  assert (info.args != NULL);
2283cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2284cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Tell the library which version we are expecting.  */
2285cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  elf_version (EV_CURRENT);
2286cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2287cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (info.dwfl == NULL)
2288cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2289cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      assert (result == ENOSYS);
2290cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2291cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (info.output_dir != NULL)
2292cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
2293cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  char *file;
2294cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (asprintf (&file, "%s/%s", info.output_dir, info.args[0]) < 0)
2295cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    error (EXIT_FAILURE, 0, _("memory exhausted"));
2296cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  handle_explicit_files (file, true, info.args[0], info.args[1]);
2297cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  free (file);
2298cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
2299cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else
2300cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	handle_explicit_files (info.output_file, false,
2301cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       info.args[0], info.args[1]);
2302cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2303cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else
2304cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2305cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* parse_opt checked this.  */
2306cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      assert (info.output_file != NULL || info.output_dir != NULL || info.list);
2307cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2308cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      handle_implicit_modules (&info);
2309cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2310cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      dwfl_end (info.dwfl);
2311cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2312cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2313cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return 0;
2314cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
2315cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2316cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2317cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include "debugpred.h"
2318