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