mirror of
https://github.com/openharmony/third_party_elfutils.git
synced 2026-07-01 06:41:51 -04:00
strip: Add --reloc-debug-sections option.
This commit is contained in:
@@ -1,3 +1,12 @@
|
||||
2011-05-23 Mark Wielaard <mjw@redhat.com>
|
||||
|
||||
* strip.c (OPT_RELOC_DEBUG): New option.
|
||||
(argp_option): Add new --reloc-debug-sections option.
|
||||
(main): Check new option.
|
||||
(parse_opt): Likewise.
|
||||
(handle_elf): Remove any relocations between debug sections
|
||||
in ET_REL for the debug file when requested.
|
||||
|
||||
2011-05-18 Mark Wielaard <mjw@redhat.com>
|
||||
|
||||
* strip.c (handle_elf): Make sure all sections of a removed group
|
||||
|
||||
+213
-2
@@ -53,6 +53,7 @@
|
||||
#include <libebl.h>
|
||||
#include <system.h>
|
||||
|
||||
typedef uint8_t GElf_Byte;
|
||||
|
||||
/* Name and version of program. */
|
||||
static void print_version (FILE *stream, struct argp_state *state);
|
||||
@@ -66,6 +67,7 @@ ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
|
||||
#define OPT_REMOVE_COMMENT 0x100
|
||||
#define OPT_PERMISSIVE 0x101
|
||||
#define OPT_STRIP_SECTIONS 0x102
|
||||
#define OPT_RELOC_DEBUG 0x103
|
||||
|
||||
|
||||
/* Definitions of arguments for argp functions. */
|
||||
@@ -85,6 +87,8 @@ static const struct argp_option options[] =
|
||||
N_("Remove section headers (not recommended)"), 0 },
|
||||
{ "preserve-dates", 'p', NULL, 0,
|
||||
N_("Copy modified/access timestamps to the output"), 0 },
|
||||
{ "reloc-debug-sections", OPT_RELOC_DEBUG, NULL, 0,
|
||||
N_("Resolve all trivial relocations between debug sections if the removed sections are placed in a debug file (only relevant for ET_REL files, operation is not reversable, needs -f)"), 0 },
|
||||
{ "remove-comment", OPT_REMOVE_COMMENT, NULL, 0,
|
||||
N_("Remove .comment section"), 0 },
|
||||
{ "remove-section", 'R', "SECTION", OPTION_HIDDEN, NULL, 0 },
|
||||
@@ -149,6 +153,9 @@ static bool remove_shdrs;
|
||||
/* If true relax some ELF rules for input files. */
|
||||
static bool permissive;
|
||||
|
||||
/* If true perform relocations between debug sections. */
|
||||
static bool reloc_debug;
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
@@ -177,6 +184,10 @@ main (int argc, char *argv[])
|
||||
if (argp_parse (&argp, argc, argv, 0, &remaining, NULL) != 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (reloc_debug && debug_fname == NULL)
|
||||
error (EXIT_FAILURE, 0,
|
||||
gettext ("--reloc-debug-sections used without -f"));
|
||||
|
||||
/* Tell the library which version we are expecting. */
|
||||
elf_version (EV_CURRENT);
|
||||
|
||||
@@ -253,6 +264,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
preserve_dates = true;
|
||||
break;
|
||||
|
||||
case OPT_RELOC_DEBUG:
|
||||
reloc_debug = true;
|
||||
break;
|
||||
|
||||
case OPT_REMOVE_COMMENT:
|
||||
remove_comment = true;
|
||||
break;
|
||||
@@ -447,10 +462,12 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
|
||||
|
||||
int debug_fd = -1;
|
||||
|
||||
/* Get the EBL handling. The -g option is currently the only reason
|
||||
/* Get the EBL handling. Removing all debugging symbols with the -g
|
||||
option or resolving all relocations between debug sections with
|
||||
the --reloc-debug-sections option are currently the only reasons
|
||||
we need EBL so don't open the backend unless necessary. */
|
||||
Ebl *ebl = NULL;
|
||||
if (remove_debug)
|
||||
if (remove_debug || reloc_debug)
|
||||
{
|
||||
ebl = ebl_openbackend (elf);
|
||||
if (ebl == NULL)
|
||||
@@ -1609,6 +1626,200 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove any relocations between debug sections in ET_REL
|
||||
for the debug file when requested. These relocations are always
|
||||
zero based between the unallocated sections. */
|
||||
if (debug_fname != NULL && reloc_debug && ehdr->e_type == ET_REL)
|
||||
{
|
||||
scn = NULL;
|
||||
cnt = 0;
|
||||
while ((scn = elf_nextscn (debugelf, scn)) != NULL)
|
||||
{
|
||||
cnt++;
|
||||
/* We need the actual section and header from the debugelf
|
||||
not just the cached original in shdr_info because we
|
||||
might want to change the size. */
|
||||
GElf_Shdr shdr_mem;
|
||||
GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
|
||||
if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
|
||||
{
|
||||
/* Make sure that this relocation section points to a
|
||||
section to relocate with contents, that isn't
|
||||
allocated and that is a debug section. */
|
||||
Elf_Scn *tscn = elf_getscn (debugelf, shdr->sh_info);
|
||||
GElf_Shdr tshdr_mem;
|
||||
GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
|
||||
if (tshdr->sh_type == SHT_NOBITS
|
||||
|| tshdr->sh_size == 0
|
||||
|| (tshdr->sh_flags & SHF_ALLOC) != 0)
|
||||
continue;
|
||||
|
||||
const char *tname = elf_strptr (debugelf, shstrndx,
|
||||
tshdr->sh_name);
|
||||
if (! tname || ! ebl_debugscn_p (ebl, tname))
|
||||
continue;
|
||||
|
||||
/* OK, lets relocate all trivial cross debug section
|
||||
relocations. */
|
||||
Elf_Data *reldata = elf_getdata (scn, NULL);
|
||||
/* We actually wanted the rawdata, but since we already
|
||||
accessed it earlier as elf_getdata () that won't
|
||||
work. But debug sections are all ELF_T_BYTE, so it
|
||||
doesn't really matter. */
|
||||
Elf_Data *tdata = elf_getdata (tscn, NULL);
|
||||
if (tdata->d_type != ELF_T_BYTE)
|
||||
INTERNAL_ERROR (fname);
|
||||
|
||||
/* Pick up the symbol table and shndx table to
|
||||
resolve relocation symbol indexes. */
|
||||
Elf64_Word symt = shdr->sh_link;
|
||||
Elf_Data *symdata, *xndxdata;
|
||||
symdata = (shdr_info[symt].debug_data
|
||||
?: shdr_info[symt].data);
|
||||
xndxdata = (shdr_info[shdr_info[symt].symtab_idx].debug_data
|
||||
?: shdr_info[shdr_info[symt].symtab_idx].data);
|
||||
|
||||
/* Apply one relocation. Returns true when trivial
|
||||
relocation actually done. */
|
||||
bool relocate (GElf_Addr offset, const GElf_Sxword addend,
|
||||
int rtype, int symndx)
|
||||
{
|
||||
/* R_*_NONE relocs can always just be removed. */
|
||||
if (rtype == 0)
|
||||
return true;
|
||||
|
||||
/* We only do simple absolute relocations. */
|
||||
Elf_Type type = ebl_reloc_simple_type (ebl, rtype);
|
||||
if (type == ELF_T_NUM)
|
||||
return false;
|
||||
|
||||
/* These are the types we can relocate. */
|
||||
#define TYPES DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half); \
|
||||
DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword); \
|
||||
DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
|
||||
|
||||
/* And only for relocations against other debug sections. */
|
||||
GElf_Sym sym_mem;
|
||||
Elf32_Word xndx;
|
||||
GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
|
||||
symndx, &sym_mem,
|
||||
&xndx);
|
||||
if (GELF_ST_TYPE (sym->st_info) == STT_SECTION)
|
||||
{
|
||||
Elf32_Word sec = (sym->st_shndx == SHN_XINDEX
|
||||
? xndx : sym->st_shndx);
|
||||
if (ebl_debugscn_p (ebl, shdr_info[sec].name))
|
||||
{
|
||||
size_t size;
|
||||
switch (type)
|
||||
{
|
||||
#define DO_TYPE(NAME, Name) \
|
||||
case ELF_T_##NAME: \
|
||||
size = sizeof (GElf_##Name); \
|
||||
break;
|
||||
TYPES;
|
||||
#undef DO_TYPE
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offset + size > tdata->d_size)
|
||||
error (0, 0, gettext ("bad relocation"));
|
||||
|
||||
/* For SHT_REL sections this is all that needs
|
||||
to be checked. The addend is contained in
|
||||
the original data at the offset already.
|
||||
And the (section) symbol address is zero.
|
||||
So just remove the relocation, it isn't
|
||||
needed anymore. */
|
||||
if (addend == 0)
|
||||
return true;
|
||||
|
||||
#define DO_TYPE(NAME, Name) GElf_##Name Name;
|
||||
union { TYPES; } tmpbuf;
|
||||
#undef DO_TYPE
|
||||
Elf_Data tmpdata =
|
||||
{
|
||||
.d_type = type,
|
||||
.d_buf = &tmpbuf,
|
||||
.d_size = size,
|
||||
.d_version = EV_CURRENT,
|
||||
};
|
||||
Elf_Data rdata =
|
||||
{
|
||||
.d_type = type,
|
||||
.d_buf = tdata->d_buf + offset,
|
||||
.d_size = size,
|
||||
.d_version = EV_CURRENT,
|
||||
};
|
||||
|
||||
/* For SHT_RELA sections we just take the
|
||||
addend and put it into the relocation slot.
|
||||
The (section) symbol address can be
|
||||
ignored, since it is zero. */
|
||||
switch (type)
|
||||
{
|
||||
#define DO_TYPE(NAME, Name) \
|
||||
case ELF_T_##NAME: \
|
||||
tmpbuf.Name = addend; \
|
||||
break;
|
||||
TYPES;
|
||||
#undef DO_TYPE
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
Elf_Data *s = gelf_xlatetof (debugelf, &rdata,
|
||||
&tmpdata,
|
||||
ehdr->e_ident[EI_DATA]);
|
||||
if (s == NULL)
|
||||
INTERNAL_ERROR (fname);
|
||||
assert (s == &rdata);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t nrels = shdr->sh_size / shdr->sh_entsize;
|
||||
size_t next = 0;
|
||||
if (shdr->sh_type == SHT_REL)
|
||||
for (size_t relidx = 0; relidx < nrels; ++relidx)
|
||||
{
|
||||
GElf_Rel rel_mem;
|
||||
GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
|
||||
if (! relocate (r->r_offset, 0,
|
||||
GELF_R_TYPE (r->r_info),
|
||||
GELF_R_SYM (r->r_info)))
|
||||
{
|
||||
if (relidx != next)
|
||||
gelf_update_rel (reldata, next, r);
|
||||
++next;
|
||||
}
|
||||
}
|
||||
else
|
||||
for (size_t relidx = 0; relidx < nrels; ++relidx)
|
||||
{
|
||||
GElf_Rela rela_mem;
|
||||
GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
|
||||
if (! relocate (r->r_offset, r->r_addend,
|
||||
GELF_R_TYPE (r->r_info),
|
||||
GELF_R_SYM (r->r_info)))
|
||||
{
|
||||
if (relidx != next)
|
||||
gelf_update_rela (reldata, next, r);
|
||||
++next;
|
||||
}
|
||||
}
|
||||
|
||||
nrels = next;
|
||||
shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize;
|
||||
gelf_update_shdr (scn, shdr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now that we have done all adjustments to the data,
|
||||
we can actually write out the debug file. */
|
||||
if (debug_fname != NULL)
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
2011-05-23 Mark Wielaard <mjw@redhat.com>
|
||||
|
||||
* Makefile.am (TESTS): Add run-strip-reloc.sh.
|
||||
(EXTRA_DIST): Add run-strip-reloc.sh, hello_i386.ko.bz2
|
||||
hello_x86_64.ko.bz2 and hello_ppc64.ko.bz2
|
||||
* run-strip-reloc.sh: New test.
|
||||
* hello_i386.ko.bz2: New test file.
|
||||
* hello_x86_64.ko.bz2: Likewise.
|
||||
* hello_ppc64.ko.bz2: Likewise.
|
||||
|
||||
2011-05-18 Mark Wielaard <mjw@redhat.com>
|
||||
|
||||
* run-strip-groups.sh: New test.
|
||||
|
||||
+4
-1
@@ -70,7 +70,8 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
|
||||
newscn run-strip-test.sh run-strip-test2.sh \
|
||||
run-strip-test3.sh run-strip-test4.sh run-strip-test5.sh \
|
||||
run-strip-test6.sh run-strip-test7.sh run-strip-test8.sh \
|
||||
run-strip-groups.sh run-unstrip-test.sh run-unstrip-test2.sh \
|
||||
run-strip-groups.sh run-strip-reloc.sh \
|
||||
run-unstrip-test.sh run-unstrip-test2.sh \
|
||||
run-ecp-test.sh run-ecp-test2.sh run-alldts.sh \
|
||||
run-elflint-test.sh run-elflint-self.sh run-ranlib-test.sh \
|
||||
run-ranlib-test2.sh run-ranlib-test3.sh run-ranlib-test4.sh \
|
||||
@@ -111,6 +112,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
|
||||
run-line2addr.sh run-elflint-test.sh testfile14.bz2 \
|
||||
run-strip-test4.sh run-strip-test5.sh run-strip-test6.sh \
|
||||
run-strip-test7.sh run-strip-test8.sh run-strip-groups.sh \
|
||||
run-strip-reloc.sh hello_i386.ko.bz2 hello_x86_64.ko.bz2 \
|
||||
hello_ppc64.ko.bz2 \
|
||||
run-unstrip-test.sh run-unstrip-test2.sh \
|
||||
run-elflint-self.sh run-ranlib-test.sh run-ranlib-test2.sh \
|
||||
run-ranlib-test3.sh run-ranlib-test4.sh \
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Executable
+114
@@ -0,0 +1,114 @@
|
||||
#! /bin/sh
|
||||
# Copyright (C) 2011 Red Hat, Inc.
|
||||
# This file is part of Red Hat elfutils.
|
||||
#
|
||||
# Red Hat elfutils is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation; version 2 of the License.
|
||||
#
|
||||
# Red Hat elfutils is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with Red Hat elfutils; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
|
||||
#
|
||||
# Red Hat elfutils is an included package of the Open Invention Network.
|
||||
# An included package of the Open Invention Network is a package for which
|
||||
# Open Invention Network licensees cross-license their patents. No patent
|
||||
# license is granted, either expressly or impliedly, by designation as an
|
||||
# included package. Should you wish to participate in the Open Invention
|
||||
# Network licensing program, please visit www.openinventionnetwork.com
|
||||
# <http://www.openinventionnetwork.com>.
|
||||
|
||||
. $srcdir/test-subr.sh
|
||||
|
||||
testfiles hello_i386.ko hello_x86_64.ko hello_ppc64.ko
|
||||
|
||||
status=0
|
||||
runtest() {
|
||||
infile=$1
|
||||
is_ET_REL=$2
|
||||
outfile1=out.stripped1
|
||||
debugfile1=out.debug1
|
||||
outfile2=out.stripped2
|
||||
debugfile2=out.debug2
|
||||
|
||||
testrun ../src/strip -o $outfile1 -f $debugfile1 $infile ||
|
||||
{ echo "*** failure strip $infile"; status=1; }
|
||||
|
||||
testrun ../src/strip --reloc-debug-sections -o $outfile2 \
|
||||
-f $debugfile2 $infile ||
|
||||
{ echo "*** failure strip --reloc-debug-sections $infile"; status=1; }
|
||||
|
||||
# shouldn't make any difference for stripped files.
|
||||
testrun ../src/readelf -a $outfile1 > readelf.out ||
|
||||
{ echo "*** failure readelf -a outfile1 $infile"; status=1; }
|
||||
|
||||
testrun_compare ../src/readelf -a $outfile2 < readelf.out ||
|
||||
{ echo "*** failure compare stripped files $infile"; status=1; }
|
||||
|
||||
# debug files however should be smaller, when ET_REL.
|
||||
SIZE1=$(stat -c%s $debugfile1)
|
||||
SIZE2=$(stat -c%s $debugfile2)
|
||||
test \( \( $is_ET_REL -eq 1 \) -a \( $SIZE1 -gt $SIZE2 \) \) \
|
||||
-o \( \( $is_ET_REL -eq 0 \) -a \( $SIZE1 -eq $SIZE2 \) \) ||
|
||||
{ echo "*** failure --reloc-debug-sections not smaller $infile"; status=1; }
|
||||
|
||||
# Strip of DWARF section lines, offset will not match.
|
||||
# Everything else should match.
|
||||
testrun ../src/readelf -w $debugfile1 \
|
||||
| grep -v ^DWARF\ section > readelf.out1 ||
|
||||
{ echo "*** failure readelf -w debugfile1 $infile"; status=1; }
|
||||
|
||||
testrun ../src/readelf -w $debugfile2 \
|
||||
| grep -v ^DWARF\ section > readelf.out2 ||
|
||||
{ echo "*** failure readelf -w debugfile2 $infile"; status=1; }
|
||||
|
||||
testrun_compare cat readelf.out1 < readelf.out2 ||
|
||||
{ echo "*** failure readelf -w compare $infile"; status=1; }
|
||||
|
||||
rm -f $outfile1 $debugfile1 $outfile2 $debugfile2 readelf.out*
|
||||
}
|
||||
|
||||
# Most simple hello world kernel module for various architectures.
|
||||
# ::::::::::::::
|
||||
# Makefile
|
||||
# ::::::::::::::
|
||||
# obj-m := hello.o
|
||||
# hello-y := init.o exit.o
|
||||
#
|
||||
# all:
|
||||
# make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
|
||||
# ::::::::::::::
|
||||
# init.c
|
||||
# ::::::::::::::
|
||||
# #include <linux/kernel.h>
|
||||
# #include <linux/module.h>
|
||||
#
|
||||
# int init_module(void)
|
||||
# {
|
||||
# printk(KERN_INFO "Hello, world!\n");
|
||||
# return 0;
|
||||
# }
|
||||
# ::::::::::::::
|
||||
# exit.c
|
||||
# ::::::::::::::
|
||||
# #include <linux/kernel.h>
|
||||
# #include <linux/module.h>
|
||||
#
|
||||
# void cleanup_module()
|
||||
# {
|
||||
# printk(KERN_INFO "Goodbye, World!\n");
|
||||
# }
|
||||
runtest hello_i386.ko 1
|
||||
runtest hello_x86_64.ko 1
|
||||
runtest hello_ppc64.ko 1
|
||||
|
||||
# self test, shouldn't impact non-ET_REL files at all.
|
||||
runtest ../src/strip 0
|
||||
runtest ../src/strip.o 1
|
||||
|
||||
exit $status
|
||||
Reference in New Issue
Block a user