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