summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog149
-rw-r--r--src/addr2line.c6
-rw-r--r--src/ar.c10
-rw-r--r--src/arlib.c3
-rw-r--r--src/elflint.c50
-rw-r--r--src/findtextrel.c23
-rw-r--r--src/readelf.c153
-rw-r--r--src/size.c6
-rw-r--r--src/strip.c874
-rw-r--r--src/unstrip.c102
10 files changed, 982 insertions, 394 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index b0db6fbd..b6fd9d22 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -27,6 +27,155 @@
* ar.c: Open files in O_BINARY.
+2018-11-10 Mark Wielaard <mark@klomp.org>
+
+ * elflint.c (check_program_header): Allow PT_GNU_EH_FRAME segment
+ to be matched against SHT_X86_64_UNWIND section.
+
+2018-11-09 Mark Wielaard <mark@klomp.org>
+
+ * strip.c (remove_debug_relocations): Check if section is gnu
+ compressed and decompress and recompress it.
+
+2018-11-12 Mark Wielaard <mark@klomp.org>
+
+ * elflint.c (check_note_data): Recognize NT_GNU_BUILD_ATTRIBUTE_OPEN
+ and NT_GNU_BUILD_ATTRIBUTE_OPEN.
+ * readelf.c (handle_notes_data): Handle
+ ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX. Pass nhdr.n_namesz to
+ ebl_object_note.
+
+2018-11-11 Mark Wielaard <mark@klomp.org>
+
+ * readelf.c (handle_notes_data): Pass n_descsz to
+ ebl_object_note_type_name.
+ * elflint.c (check_note_data): Recognize NT_VERSION, add owner
+ name to unknown note error.
+
+2018-10-20 Mark Wielaard <mark@klomp.org>
+
+ * readelf.c (process_elf_file): Use dwelf_elf_begin to open pure_elf.
+
+2018-10-26 Mark Wielaard <mark@klomp.org>
+
+ * strip.c (OPT_RELOC_DEBUG_ONLY): New define.
+ (options): Add reloc-debug-sections-only.
+ (reloc_debug_only): New static bool.
+ (main): Check reloc_debug_only is the only strip option used.
+ (parse_opt): Handle OPT_RELOC_DEBUG_ONLY.
+ (handle_debug_relocs): New function.
+ (handle_elf): Add local variables lastsec_offset and lastsec_size.
+ Handle reloc_debug_only.
+
+2018-10-24 Mark Wielaard <mark@klomp.org>
+
+ * strip.c (handle_elf): Extract code to update shdrstrndx into...
+ (update_shdrstrndx): ... this new function.
+
+2018-10-24 Mark Wielaard <mark@klomp.org>
+
+ * strip.c (handle_elf): Extract code into separate functions...
+ (secndx_name): ... new function.
+ (get_xndxdata): Likewise.
+ (remove_debug_relocations): Likewise.
+
+2018-10-24 Mark Wielaard <mark@klomp.org>
+
+ * strip.c (handle_elf): Always copy over phdrs if there are any
+ and check phnum instead of e_type to determine whether to move
+ allocated sections.
+
+2018-11-02 Mark Wielaard <mark@klomp.org>
+
+ * unstrip.c (copy_elf): Add ELF_CHECK to make sure gelf_getehdr ()
+ doesn't return NULL.
+
+2018-10-18 Mark Wielaard <mark@klomp.org>
+
+ * elflint.c (check_note_data): Recognize NT_GNU_PROPERTY_TYPE_0.
+ (check_note): Use p_align to pass either ELF_T_NHDR or ELF_T_NHDR8 to
+ elf_getdata_rawchunk.
+ * readelf (handle_notes): Likewise.
+
+2018-10-24 Mark Wielaard <mark@klomp.org>
+
+ * addr2line.c (print_addrsym): Use elf_getshdrstrndx instead of
+ Ehdr field.
+
+2018-10-24 Mark Wielaard <mark@klomp.org>
+
+ * readelf.c (section_name): Remove ehdr argument, lookup shstrndx.
+ (print_debug_abbrev_section): Don't pass ehdr.
+ (print_debug_addr_section): Likewise.
+ (print_decoded_aranges_section): Likewise.
+ (print_debug_aranges_section): Likewise.
+ (print_debug_rnglists_section): Likewise.
+ (print_debug_ranges_section): Likewise.
+ (print_debug_units): Likewise.
+ (print_decoded_line_section): Likewise.
+ (print_debug_line_section): Likewise.
+ (print_debug_loclists_section): Likewise.
+ (print_debug_loc_section): Likewise.
+ (print_debug_macinfo_section): Likewise.
+ (print_debug_macro_section): Likewise.
+ (print_debug_pubnames_section): Likewise.
+ (print_debug_str_section): Liekwise.
+ (print_debug_str_offsets_section): Likewise.
+ (print_gdb_index_section): Likewise.
+
+2018-10-16 Mark Wielaard <mark@klomp.org>
+
+ * readelf.c (print_debug_frame_section): Make sure readp is never
+ greater than cieend.
+
+2018-10-19 Mark Wielaard <mark@klomp.org>
+
+ * dwfl_module_getdwarf.c (adjust_relocs): Check sh_entsize is not
+ zero.
+ (add_new_section_symbols): Likewise.
+ (copy_elided_sections): Likewise.
+
+2018-10-18 Mark Wielaard <mark@klomp.org>
+
+ * size.c (handle_ar): Only close elf if prefix was NULL.
+
+2018-10-18 Mark Wielaard <mark@klomp.org>
+
+ * arlib.c (arlib_add_symbols): Check that sh_entsize is not zero.
+
+2018-10-14 Mark Wielaard <mark@klomp.org>
+
+ * ar.c (do_oper_extract): Assume epoch if ar_date is bogus.
+
+2018-10-14 Mark Wielaard <mark@klomp.org>
+
+ * findtextrel.c (process_file): Check that sh_entsize is not zero.
+
+2018-10-13 Mark Wielaard <mark@klomp.org>
+
+ * readelf.c (print_debug_macro_section): Use elf_getdata. Print
+ decoded flag string.
+
+2018-10-19 Mark Wielaard <mark@klomp.org>
+
+ * unstrip.c (copy_elided_sections): Renumber group section indexes.
+
+2018-10-12 Mark Wielaard <mark@klomp.org>
+
+ * strip.c (handle_elf): Don't remove SHF_GROUP flag from sections.
+ Skip group section flag when renumbering section indexes.
+ * unstrip.c (struct section): Add sig field.
+ (compare_unalloc_sections): Take and use sig1 and sig2 as arguments.
+ (compare_sections): Pass signatures to compare_unalloc_sections.
+ (get_group_sig): New function.
+ (find_alloc_sections_prelink): Set signature.
+ (copy_elided_sections): Likewise and pass them on.
+ (find_unalloc_section): Take and pass signatures.
+
+2018-10-02 Andreas Schwab <schwab@suse.de>
+
+ * strip.c (handle_elf): Handle ADD/SUB relocation.
+
2018-09-13 Mark Wielaard <mark@klomp.org>
* readelf.c (print_shdr): Get number of section with elf_getshdrnum.
diff --git a/src/addr2line.c b/src/addr2line.c
index 32660f7a..8bd974cb 100644
--- a/src/addr2line.c
+++ b/src/addr2line.c
@@ -446,9 +446,9 @@ print_addrsym (Dwfl_Module *mod, GElf_Addr addr)
if (shdr != NULL)
{
Elf *elf = dwfl_module_getelf (mod, &ebias);
- GElf_Ehdr ehdr;
- if (gelf_getehdr (elf, &ehdr) != NULL)
- printf (" (%s)", elf_strptr (elf, ehdr.e_shstrndx,
+ size_t shstrndx;
+ if (elf_getshdrstrndx (elf, &shstrndx) >= 0)
+ printf (" (%s)", elf_strptr (elf, shstrndx,
shdr->sh_name));
}
}
diff --git a/src/ar.c b/src/ar.c
index 44edbd35..7634d318 100644
--- a/src/ar.c
+++ b/src/ar.c
@@ -519,8 +519,14 @@ do_oper_extract (int oper, const char *arfname, char **argv, int argc,
else if (oper == oper_list)
{
char datestr[100];
- strftime (datestr, sizeof (datestr), "%b %d %H:%M %Y",
- localtime (&arhdr->ar_date));
+ struct tm *tp = localtime (&arhdr->ar_date);
+ if (tp == NULL)
+ {
+ time_t time = 0;
+ tp = localtime (&time);
+ }
+
+ strftime (datestr, sizeof (datestr), "%b %d %H:%M %Y", tp);
printf ("%c%c%c%c%c%c%c%c%c %u/%u %6ju %s %s\n",
(arhdr->ar_mode & S_IRUSR) ? 'r' : '-',
diff --git a/src/arlib.c b/src/arlib.c
index 778e0878..a6521e30 100644
--- a/src/arlib.c
+++ b/src/arlib.c
@@ -252,6 +252,9 @@ arlib_add_symbols (Elf *elf, const char *arfname, const char *membername,
if (data == NULL)
continue;
+ if (shdr->sh_entsize == 0)
+ continue;
+
int nsyms = shdr->sh_size / shdr->sh_entsize;
for (int ndx = shdr->sh_info; ndx < nsyms; ++ndx)
{
diff --git a/src/elflint.c b/src/elflint.c
index e6efda56..e0ef95ce 100644
--- a/src/elflint.c
+++ b/src/elflint.c
@@ -1,5 +1,5 @@
/* Pedantic checking of ELF files compliance with gABI/psABI spec.
- Copyright (C) 2001-2015, 2017 Red Hat, Inc.
+ Copyright (C) 2001-2015, 2017, 2018 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2001.
@@ -4331,7 +4331,31 @@ section [%2d] '%s': unknown core file note type %" PRIu32
case NT_GNU_HWCAP:
case NT_GNU_BUILD_ID:
case NT_GNU_GOLD_VERSION:
- break;
+ case NT_GNU_PROPERTY_TYPE_0:
+ if (nhdr.n_namesz == sizeof ELF_NOTE_GNU
+ && strcmp (data->d_buf + name_offset, ELF_NOTE_GNU) == 0)
+ break;
+ else
+ {
+ /* NT_VERSION is 1, same as NT_GNU_ABI_TAG. It has no
+ descriptor and (ab)uses the name as version string. */
+ if (nhdr.n_descsz == 0 && nhdr.n_type == NT_VERSION)
+ break;
+ }
+ goto unknown_note;
+
+ case NT_GNU_BUILD_ATTRIBUTE_OPEN:
+ case NT_GNU_BUILD_ATTRIBUTE_FUNC:
+ /* GNU Build Attributes store most data in the owner
+ name, which must start with the
+ ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX "GA". */
+ if (nhdr.n_namesz >= sizeof ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX
+ && strncmp (data->d_buf + name_offset,
+ ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX,
+ strlen (ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX)) == 0)
+ break;
+ else
+ goto unknown_note;
case 0:
/* Linux vDSOs use a type 0 note for the kernel version word. */
@@ -4340,16 +4364,21 @@ section [%2d] '%s': unknown core file note type %" PRIu32
break;
FALLTHROUGH;
default:
+ {
+ unknown_note:
if (shndx == 0)
ERROR (gettext ("\
-phdr[%d]: unknown object file note type %" PRIu32 " at offset %zu\n"),
- phndx, (uint32_t) nhdr.n_type, offset);
+phdr[%d]: unknown object file note type %" PRIu32 " with owner name '%s' at offset %zu\n"),
+ phndx, (uint32_t) nhdr.n_type,
+ (char *) data->d_buf + name_offset, offset);
else
ERROR (gettext ("\
section [%2d] '%s': unknown object file note type %" PRIu32
- " at offset %zu\n"),
+ " with owner name '%s' at offset %zu\n"),
shndx, section_name (ebl, shndx),
- (uint32_t) nhdr.n_type, offset);
+ (uint32_t) nhdr.n_type,
+ (char *) data->d_buf + name_offset, offset);
+ }
}
}
@@ -4376,7 +4405,8 @@ phdr[%d]: no note entries defined for the type of file\n"),
GElf_Off notes_size = 0;
Elf_Data *data = elf_getdata_rawchunk (ebl->elf,
phdr->p_offset, phdr->p_filesz,
- ELF_T_NHDR);
+ (phdr->p_align == 8
+ ? ELF_T_NHDR8 : ELF_T_NHDR));
if (data != NULL && data->d_buf != NULL)
notes_size = check_note_data (ebl, ehdr, data, 0, cnt, phdr->p_offset);
@@ -4603,8 +4633,10 @@ program header offset in ELF header and PHDR entry do not match"));
any = true;
shdr = gelf_getshdr (scn, &shdr_mem);
if (shdr != NULL
- && shdr->sh_type == (is_debuginfo
- ? SHT_NOBITS : SHT_PROGBITS)
+ && ((is_debuginfo && shdr->sh_type == SHT_NOBITS)
+ || (! is_debuginfo
+ && (shdr->sh_type == SHT_PROGBITS
+ || shdr->sh_type == SHT_X86_64_UNWIND)))
&& elf_strptr (ebl->elf, shstrndx, shdr->sh_name) != NULL
&& ! strcmp (".eh_frame_hdr",
elf_strptr (ebl->elf, shstrndx, shdr->sh_name)))
diff --git a/src/findtextrel.c b/src/findtextrel.c
index 76456195..5c26715e 100644
--- a/src/findtextrel.c
+++ b/src/findtextrel.c
@@ -1,5 +1,5 @@
/* Locate source files or functions which caused text relocations.
- Copyright (C) 2005-2010, 2012, 2014 Red Hat, Inc.
+ Copyright (C) 2005-2010, 2012, 2014, 2018 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2005.
@@ -263,9 +263,10 @@ process_file (const char *fname, bool more_than_one)
seen_dynamic = true;
Elf_Data *data = elf_getdata (scn, NULL);
+ size_t entries = (shdr->sh_entsize == 0
+ ? 0 : shdr->sh_size / shdr->sh_entsize);
- for (size_t cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize;
- ++cnt)
+ for (size_t cnt = 0; cnt < entries; ++cnt)
{
GElf_Dyn dynmem;
GElf_Dyn *dyn;
@@ -413,10 +414,11 @@ cannot get symbol table section %zu in '%s': %s"),
if (shdr->sh_type == SHT_REL)
{
Elf_Data *data = elf_getdata (scn, NULL);
+ size_t entries = (shdr->sh_entsize == 0
+ ? 0 : shdr->sh_size / shdr->sh_entsize);
for (int cnt = 0;
- (size_t) cnt < shdr->sh_size / shdr->sh_entsize;
- ++cnt)
+ (size_t) cnt < entries; ++cnt)
{
GElf_Rel rel_mem;
GElf_Rel *rel = gelf_getrel (data, cnt, &rel_mem);
@@ -436,10 +438,10 @@ cannot get relocation at index %d in section %zu in '%s': %s"),
else if (shdr->sh_type == SHT_RELA)
{
Elf_Data *data = elf_getdata (scn, NULL);
+ size_t entries = (shdr->sh_entsize == 0
+ ? 0 : shdr->sh_size / shdr->sh_entsize);
- for (int cnt = 0;
- (size_t) cnt < shdr->sh_size / shdr->sh_entsize;
- ++cnt)
+ for (int cnt = 0; (size_t) cnt < entries; ++cnt)
{
GElf_Rela rela_mem;
GElf_Rela *rela = gelf_getrela (data, cnt, &rela_mem);
@@ -531,9 +533,10 @@ check_rel (size_t nsegments, struct segments segments[nsegments],
int highidx = -1;
GElf_Sym sym_mem;
GElf_Sym *sym;
+ size_t entries = (shdr->sh_entsize == 0
+ ? 0 : shdr->sh_size / shdr->sh_entsize);
- for (int i = 0; (size_t) i < shdr->sh_size / shdr->sh_entsize;
- ++i)
+ for (int i = 0; (size_t) i < entries; ++i)
{
sym = gelf_getsym (symdata, i, &sym_mem);
if (sym == NULL)
diff --git a/src/readelf.c b/src/readelf.c
index 90a14061..c8c9851b 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -910,7 +910,6 @@ process_elf_file (Dwfl_Module *dwflmod, int fd)
if (ehdr == NULL)
{
- elf_error:
error (0, 0, gettext ("cannot read ELF header: %s"), elf_errmsg (-1));
return;
}
@@ -953,7 +952,7 @@ process_elf_file (Dwfl_Module *dwflmod, int fd)
{
/* Read the file afresh. */
off_t aroff = elf_getaroff (elf);
- pure_elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
+ pure_elf = dwelf_elf_begin (fd);
if (aroff > 0)
{
/* Archive member. */
@@ -963,7 +962,10 @@ process_elf_file (Dwfl_Module *dwflmod, int fd)
pure_elf = armem;
}
if (pure_elf == NULL)
- goto elf_error;
+ {
+ error (0, 0, gettext ("cannot read ELF: %s"), elf_errmsg (-1));
+ return;
+ }
pure_ebl = ebl_openbackend (pure_elf);
if (pure_ebl == NULL)
goto ebl_error;
@@ -1535,9 +1537,12 @@ print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
static const char *
-section_name (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr)
+section_name (Ebl *ebl, GElf_Shdr *shdr)
{
- return elf_strptr (ebl->elf, ehdr->e_shstrndx, shdr->sh_name) ?: "???";
+ size_t shstrndx;
+ if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0)
+ return "???";
+ return elf_strptr (ebl->elf, shstrndx, shdr->sh_name) ?: "???";
}
@@ -5008,7 +5013,7 @@ listptr_cu (struct listptr_table *table, size_t *idxp,
static void
print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
- Ebl *ebl, GElf_Ehdr *ehdr,
+ Ebl *ebl, GElf_Ehdr *ehdr __attribute__ ((unused)),
Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
{
const size_t sh_size = (dbg->sectiondata[IDX_debug_abbrev] ?
@@ -5016,7 +5021,7 @@ print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"
" [ Code]\n"),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ elf_ndxscn (scn), section_name (ebl, shdr),
(uint64_t) shdr->sh_offset);
Dwarf_Off offset = 0;
@@ -5086,7 +5091,7 @@ print_debug_addr_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
{
printf (gettext ("\
\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ elf_ndxscn (scn), section_name (ebl, shdr),
(uint64_t) shdr->sh_offset);
if (shdr->sh_size == 0)
@@ -5334,7 +5339,7 @@ print_decoded_aranges_section (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
"\
\nDWARF section [%2zu] '%s' at offset %#" PRIx64 " contains %zu entries:\n",
cnt),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ elf_ndxscn (scn), section_name (ebl, shdr),
(uint64_t) shdr->sh_offset, cnt);
/* Compute floor(log16(cnt)). */
@@ -5395,7 +5400,7 @@ print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
printf (gettext ("\
\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ elf_ndxscn (scn), section_name (ebl, shdr),
(uint64_t) shdr->sh_offset);
const unsigned char *readp = data->d_buf;
@@ -5411,7 +5416,7 @@ print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
{
invalid_data:
error (0, 0, gettext ("invalid data in section [%zu] '%s'"),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr));
+ elf_ndxscn (scn), section_name (ebl, shdr));
return;
}
@@ -5555,13 +5560,14 @@ split_dwarf_cu_base (Dwarf *dbg, Dwarf_CU **cu, Dwarf_Addr *cu_base)
/* Print content of DWARF .debug_rnglists section. */
static void
print_debug_rnglists_section (Dwfl_Module *dwflmod,
- Ebl *ebl, GElf_Ehdr *ehdr,
+ Ebl *ebl,
+ GElf_Ehdr *ehdr __attribute__ ((unused)),
Elf_Scn *scn, GElf_Shdr *shdr,
Dwarf *dbg __attribute__((unused)))
{
printf (gettext ("\
\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ elf_ndxscn (scn), section_name (ebl, shdr),
(uint64_t) shdr->sh_offset);
Elf_Data *data =(dbg->sectiondata[IDX_debug_rnglists]
@@ -5586,7 +5592,7 @@ print_debug_rnglists_section (Dwfl_Module *dwflmod,
{
invalid_data:
error (0, 0, gettext ("invalid data in section [%zu] '%s'"),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr));
+ elf_ndxscn (scn), section_name (ebl, shdr));
return;
}
@@ -5946,7 +5952,7 @@ print_debug_ranges_section (Dwfl_Module *dwflmod,
printf (gettext ("\
\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ elf_ndxscn (scn), section_name (ebl, shdr),
(uint64_t) shdr->sh_offset);
sort_listptr (&known_rangelistptr, "rangelistptr");
@@ -6603,18 +6609,24 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
ptrdiff_t start = readp - (unsigned char *) data->d_buf;
const unsigned char *const cieend = readp + unit_length;
- if (unlikely (cieend > dataend || readp + 8 > dataend))
+ if (unlikely (cieend > dataend))
goto invalid_data;
Dwarf_Off cie_id;
if (length == 4)
{
+ if (unlikely (cieend - readp < 4))
+ goto invalid_data;
cie_id = read_4ubyte_unaligned_inc (dbg, readp);
if (!is_eh_frame && cie_id == DW_CIE_ID_32)
cie_id = DW_CIE_ID_64;
}
else
- cie_id = read_8ubyte_unaligned_inc (dbg, readp);
+ {
+ if (unlikely (cieend - readp < 8))
+ goto invalid_data;
+ cie_id = read_8ubyte_unaligned_inc (dbg, readp);
+ }
uint_fast8_t version = 2;
unsigned int code_alignment_factor;
@@ -6626,6 +6638,8 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
if (cie_id == (is_eh_frame ? 0 : DW_CIE_ID_64))
{
+ if (unlikely (cieend - readp < 2))
+ goto invalid_data;
version = *readp++;
const char *const augmentation = (const char *) readp;
readp = memchr (readp, '\0', cieend - readp);
@@ -7532,12 +7546,12 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
static void
print_debug_units (Dwfl_Module *dwflmod,
- Ebl *ebl, GElf_Ehdr *ehdr,
+ Ebl *ebl, GElf_Ehdr *ehdr __attribute__ ((unused)),
Elf_Scn *scn, GElf_Shdr *shdr,
Dwarf *dbg, bool debug_types)
{
const bool silent = !(print_debug_sections & section_info) && !debug_types;
- const char *secname = section_name (ebl, ehdr, shdr);
+ const char *secname = section_name (ebl, shdr);
if (!silent)
printf (gettext ("\
@@ -7834,12 +7848,13 @@ print_debug_types_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
static void
-print_decoded_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
+print_decoded_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
+ GElf_Ehdr *ehdr __attribute__ ((unused)),
Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
{
printf (gettext ("\
\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n\n"),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ elf_ndxscn (scn), section_name (ebl, shdr),
(uint64_t) shdr->sh_offset);
size_t address_size
@@ -8188,7 +8203,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
printf (gettext ("\
\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ elf_ndxscn (scn), section_name (ebl, shdr),
(uint64_t) shdr->sh_offset);
if (shdr->sh_size == 0)
@@ -8225,7 +8240,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
{
invalid_data:
error (0, 0, gettext ("invalid data in section [%zu] '%s'"),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr));
+ elf_ndxscn (scn), section_name (ebl, shdr));
return;
}
unit_length = read_8ubyte_unaligned_inc (dbg, linep);
@@ -8352,7 +8367,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
error (0, 0,
gettext ("invalid data at offset %tu in section [%zu] '%s'"),
linep - (const unsigned char *) data->d_buf,
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr));
+ elf_ndxscn (scn), section_name (ebl, shdr));
linep = lineendp;
continue;
}
@@ -8852,13 +8867,14 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
static void
print_debug_loclists_section (Dwfl_Module *dwflmod,
- Ebl *ebl, GElf_Ehdr *ehdr,
+ Ebl *ebl,
+ GElf_Ehdr *ehdr __attribute__ ((unused)),
Elf_Scn *scn, GElf_Shdr *shdr,
Dwarf *dbg)
{
printf (gettext ("\
\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ elf_ndxscn (scn), section_name (ebl, shdr),
(uint64_t) shdr->sh_offset);
Elf_Data *data = (dbg->sectiondata[IDX_debug_loclists]
@@ -8883,7 +8899,7 @@ print_debug_loclists_section (Dwfl_Module *dwflmod,
{
invalid_data:
error (0, 0, gettext ("invalid data in section [%zu] '%s'"),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr));
+ elf_ndxscn (scn), section_name (ebl, shdr));
return;
}
@@ -9294,7 +9310,7 @@ print_debug_loc_section (Dwfl_Module *dwflmod,
printf (gettext ("\
\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ elf_ndxscn (scn), section_name (ebl, shdr),
(uint64_t) shdr->sh_offset);
sort_listptr (&known_locsptr, "loclistptr");
@@ -9533,12 +9549,13 @@ mac_compare (const void *p1, const void *p2)
static void
print_debug_macinfo_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
- Ebl *ebl, GElf_Ehdr *ehdr,
+ Ebl *ebl,
+ GElf_Ehdr *ehdr __attribute__ ((unused)),
Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
{
printf (gettext ("\
\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ elf_ndxscn (scn), section_name (ebl, shdr),
(uint64_t) shdr->sh_offset);
putc_unlocked ('\n', stdout);
@@ -9698,17 +9715,17 @@ print_debug_macinfo_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
static void
print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
- Ebl *ebl, GElf_Ehdr *ehdr,
+ Ebl *ebl,
+ GElf_Ehdr *ehdr __attribute__ ((unused)),
Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
{
printf (gettext ("\
\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ elf_ndxscn (scn), section_name (ebl, shdr),
(uint64_t) shdr->sh_offset);
putc_unlocked ('\n', stdout);
- Elf_Data *data = (dbg->sectiondata[IDX_debug_macro]
- ?: elf_rawdata (scn, NULL));
+ Elf_Data *data = elf_getdata (scn, NULL);
if (unlikely (data == NULL))
{
error (0, 0, gettext ("cannot get macro information section data: %s"),
@@ -9777,7 +9794,33 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
if (readp + 1 > readendp)
goto invalid_data;
const unsigned char flag = *readp++;
- printf (gettext (" Flag: 0x%" PRIx8 "\n"), flag);
+ printf (gettext (" Flag: 0x%" PRIx8), flag);
+ if (flag != 0)
+ {
+ printf (" (");
+ if ((flag & 0x01) != 0)
+ {
+ printf ("offset_size");
+ if ((flag & 0xFE) != 0)
+ printf (", ");
+ }
+ if ((flag & 0x02) != 0)
+ {
+ printf ("debug_line_offset");
+ if ((flag & 0xFC) != 0)
+ printf (", ");
+ }
+ if ((flag & 0x04) != 0)
+ {
+ printf ("operands_table");
+ if ((flag & 0xF8) != 0)
+ printf (", ");
+ }
+ if ((flag & 0xF8) != 0)
+ printf ("unknown");
+ printf (")");
+ }
+ printf ("\n");
unsigned int offset_len = (flag & 0x01) ? 8 : 4;
printf (gettext (" Offset length: %" PRIu8 "\n"), offset_len);
@@ -10059,11 +10102,12 @@ print_pubnames (Dwarf *dbg __attribute__ ((unused)), Dwarf_Global *global,
/* Print the known exported symbols in the DWARF section '.debug_pubnames'. */
static void
print_debug_pubnames_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
- Ebl *ebl, GElf_Ehdr *ehdr,
+ Ebl *ebl,
+ GElf_Ehdr *ehdr __attribute__ ((unused)),
Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
{
printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ elf_ndxscn (scn), section_name (ebl, shdr),
(uint64_t) shdr->sh_offset);
int n = 0;
@@ -10073,7 +10117,8 @@ print_debug_pubnames_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
/* Print the content of the DWARF string section '.debug_str'. */
static void
print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
- Ebl *ebl, GElf_Ehdr *ehdr,
+ Ebl *ebl,
+ GElf_Ehdr *ehdr __attribute__ ((unused)),
Elf_Scn *scn, GElf_Shdr *shdr,
Dwarf *dbg __attribute__ ((unused)))
{
@@ -10093,7 +10138,7 @@ print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"
" %*s String\n"),
elf_ndxscn (scn),
- section_name (ebl, ehdr, shdr), (uint64_t) shdr->sh_offset,
+ section_name (ebl, shdr), (uint64_t) shdr->sh_offset,
/* TRANS: the debugstr| prefix makes the string unique. */
digits + 2, sgettext ("debugstr|Offset"));
@@ -10117,12 +10162,13 @@ print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
static void
print_debug_str_offsets_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
- Ebl *ebl, GElf_Ehdr *ehdr,
+ Ebl *ebl,
+ GElf_Ehdr *ehdr __attribute__ ((unused)),
Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
{
printf (gettext ("\
\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ elf_ndxscn (scn), section_name (ebl, shdr),
(uint64_t) shdr->sh_offset);
if (shdr->sh_size == 0)
@@ -10586,12 +10632,13 @@ print_debug_exception_table (Dwfl_Module *dwflmod __attribute__ ((unused)),
http://sourceware.org/gdb/current/onlinedocs/gdb/Index-Section-Format.html
*/
static void
-print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
+print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl,
+ GElf_Ehdr *ehdr __attribute__ ((unused)),
Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
{
printf (gettext ("\nGDB section [%2zu] '%s' at offset %#" PRIx64
" contains %" PRId64 " bytes :\n"),
- elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ elf_ndxscn (scn), section_name (ebl, shdr),
(uint64_t) shdr->sh_offset, (uint64_t) shdr->sh_size);
Elf_Data *data = elf_rawdata (scn, NULL);
@@ -12150,14 +12197,26 @@ handle_notes_data (Ebl *ebl, const GElf_Ehdr *ehdr,
const char *name = nhdr.n_namesz == 0 ? "" : data->d_buf + name_offset;
const char *desc = data->d_buf + desc_offset;
+ /* GNU Build Attributes are weird, they store most of their data
+ into the owner name field. Extract just the owner name
+ prefix here, then use the rest later as data. */
+ bool is_gnu_build_attr
+ = strncmp (name, ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX,
+ strlen (ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX)) == 0;
+ const char *print_name = (is_gnu_build_attr
+ ? ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX : name);
+ size_t print_namesz = (is_gnu_build_attr
+ ? strlen (print_name) : nhdr.n_namesz);
+
char buf[100];
char buf2[100];
printf (gettext (" %-13.*s %9" PRId32 " %s\n"),
- (int) nhdr.n_namesz, name, nhdr.n_descsz,
+ (int) print_namesz, print_name, nhdr.n_descsz,
ehdr->e_type == ET_CORE
? ebl_core_note_type_name (ebl, nhdr.n_type,
buf, sizeof (buf))
: ebl_object_note_type_name (ebl, name, nhdr.n_type,
+ nhdr.n_descsz,
buf2, sizeof (buf2)));
/* Filter out invalid entries. */
@@ -12193,7 +12252,8 @@ handle_notes_data (Ebl *ebl, const GElf_Ehdr *ehdr,
handle_core_note (ebl, &nhdr, name, desc);
}
else
- ebl_object_note (ebl, name, nhdr.n_type, nhdr.n_descsz, desc);
+ ebl_object_note (ebl, nhdr.n_namesz, name, nhdr.n_type,
+ nhdr.n_descsz, desc);
}
}
@@ -12259,7 +12319,8 @@ handle_notes (Ebl *ebl, GElf_Ehdr *ehdr)
handle_notes_data (ebl, ehdr, phdr->p_offset,
elf_getdata_rawchunk (ebl->elf,
phdr->p_offset, phdr->p_filesz,
- ELF_T_NHDR));
+ (phdr->p_align == 8
+ ? ELF_T_NHDR8 : ELF_T_NHDR)));
}
}
diff --git a/src/size.c b/src/size.c
index d9b98672..3419e39f 100644
--- a/src/size.c
+++ b/src/size.c
@@ -374,8 +374,10 @@ handle_ar (int fd, Elf *elf, const char *prefix, const char *fname)
INTERNAL_ERROR (fname);
}
- if (unlikely (elf_end (elf) != 0))
- INTERNAL_ERROR (fname);
+ /* Only close ELF handle if this was a "top level" ar file. */
+ if (prefix == NULL)
+ if (unlikely (elf_end (elf) != 0))
+ INTERNAL_ERROR (fname);
return result;
}
diff --git a/src/strip.c b/src/strip.c
index a85a2306..15a43ff7 100644
--- a/src/strip.c
+++ b/src/strip.c
@@ -1,5 +1,5 @@
/* Discard section not used at runtime from object files.
- Copyright (C) 2000-2012, 2014, 2015, 2016, 2017 Red Hat, Inc.
+ Copyright (C) 2000-2012, 2014, 2015, 2016, 2017, 2018 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2000.
@@ -61,6 +61,7 @@ ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
#define OPT_STRIP_SECTIONS 0x102
#define OPT_RELOC_DEBUG 0x103
#define OPT_KEEP_SECTION 0x104
+#define OPT_RELOC_DEBUG_ONLY 0x105
/* Definitions of arguments for argp functions. */
@@ -82,6 +83,8 @@ static const struct argp_option options[] =
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 },
+ { "reloc-debug-sections-only", OPT_RELOC_DEBUG_ONLY, NULL, 0,
+ N_("Similar to --reloc-debug-sections, but resolve all trivial relocations between debug sections in place. No other stripping is performed (operation is not reversable, incompatible with -f, -g, --remove-comment and --remove-section)"), 0 },
{ "remove-comment", OPT_REMOVE_COMMENT, NULL, 0,
N_("Remove .comment section"), 0 },
{ "remove-section", 'R', "SECTION", 0, N_("Remove the named section. SECTION is an extended wildcard pattern. May be given more than once. Only non-allocated sections can be removed."), 0 },
@@ -159,6 +162,9 @@ static bool permissive;
/* If true perform relocations between debug sections. */
static bool reloc_debug;
+/* If true perform relocations between debug sections only. */
+static bool reloc_debug_only;
+
/* Sections the user explicitly wants to keep or remove. */
struct section_pattern
{
@@ -240,6 +246,12 @@ main (int argc, char *argv[])
error (EXIT_FAILURE, 0,
gettext ("--reloc-debug-sections used without -f"));
+ if (reloc_debug_only &&
+ (debug_fname != NULL || remove_secs != NULL
+ || remove_comment == true || remove_debug == true))
+ error (EXIT_FAILURE, 0,
+ gettext ("--reloc-debug-sections-only incompatible with -f, -g, --remove-comment and --remove-section"));
+
/* Tell the library which version we are expecting. */
elf_version (EV_CURRENT);
@@ -307,6 +319,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
reloc_debug = true;
break;
+ case OPT_RELOC_DEBUG_ONLY:
+ reloc_debug_only = true;
+ break;
+
case OPT_REMOVE_COMMENT:
remove_comment = true;
break;
@@ -354,6 +370,345 @@ parse_opt (int key, char *arg, struct argp_state *state)
return 0;
}
+static const char *
+secndx_name (Elf *elf, size_t ndx)
+{
+ size_t shstrndx;
+ GElf_Shdr mem;
+ Elf_Scn *sec = elf_getscn (elf, ndx);
+ GElf_Shdr *shdr = gelf_getshdr (sec, &mem);
+ if (shdr == NULL || elf_getshdrstrndx (elf, &shstrndx) < 0)
+ return "???";
+ return elf_strptr (elf, shstrndx, shdr->sh_name) ?: "???";
+}
+
+/* Get the extended section index table data for a symbol table section. */
+static Elf_Data *
+get_xndxdata (Elf *elf, Elf_Scn *symscn)
+{
+ Elf_Data *xndxdata = NULL;
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (symscn, &shdr_mem);
+ if (shdr != NULL && shdr->sh_type == SHT_SYMTAB)
+ {
+ size_t scnndx = elf_ndxscn (symscn);
+ Elf_Scn *xndxscn = NULL;
+ while ((xndxscn = elf_nextscn (elf, xndxscn)) != NULL)
+ {
+ GElf_Shdr xndxshdr_mem;
+ GElf_Shdr *xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
+
+ if (xndxshdr != NULL
+ && xndxshdr->sh_type == SHT_SYMTAB_SHNDX
+ && xndxshdr->sh_link == scnndx)
+ {
+ xndxdata = elf_getdata (xndxscn, NULL);
+ break;
+ }
+ }
+ }
+
+ return xndxdata;
+}
+
+/* Updates the shdrstrndx for the given Elf by updating the Ehdr and
+ possibly the section zero extension field. Returns zero on success. */
+static int
+update_shdrstrndx (Elf *elf, size_t shdrstrndx)
+{
+ GElf_Ehdr ehdr;
+ if (gelf_getehdr (elf, &ehdr) == 0)
+ return 1;
+
+ if (shdrstrndx < SHN_LORESERVE)
+ ehdr.e_shstrndx = shdrstrndx;
+ else
+ {
+ ehdr.e_shstrndx = SHN_XINDEX;
+ Elf_Scn *scn0 = elf_getscn (elf, 0);
+ GElf_Shdr shdr0_mem;
+ GElf_Shdr *shdr0 = gelf_getshdr (scn0, &shdr0_mem);
+ if (shdr0 == NULL)
+ return 1;
+
+ shdr0->sh_link = shdrstrndx;
+ if (gelf_update_shdr (scn0, shdr0) == 0)
+ return 1;
+ }
+
+ if (unlikely (gelf_update_ehdr (elf, &ehdr) == 0))
+ return 1;
+
+ return 0;
+}
+
+/* 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. */
+static void
+remove_debug_relocations (Ebl *ebl, Elf *elf, GElf_Ehdr *ehdr,
+ const char *fname, size_t shstrndx)
+{
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (elf, scn)) != NULL)
+ {
+ /* We need the actual section and header from the elf
+ 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 (elf, 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 (elf, 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);
+ if (reldata == NULL || reldata->d_buf == NULL)
+ INTERNAL_ERROR (fname);
+
+ /* Make sure we adjust the uncompressed debug data
+ (and recompress if necessary at the end). */
+ GElf_Chdr tchdr;
+ int tcompress_type = 0;
+ bool is_gnu_compressed = false;
+ if (strncmp (tname, ".zdebug", strlen ("zdebug")) == 0)
+ {
+ is_gnu_compressed = true;
+ if (elf_compress_gnu (tscn, 0, 0) != 1)
+ INTERNAL_ERROR (fname);
+ }
+ else
+ {
+ if (gelf_getchdr (tscn, &tchdr) != NULL)
+ {
+ tcompress_type = tchdr.ch_type;
+ if (elf_compress (tscn, 0, 0) != 1)
+ INTERNAL_ERROR (fname);
+ }
+ }
+
+ Elf_Data *tdata = elf_getdata (tscn, NULL);
+ if (tdata == NULL || tdata->d_buf == NULL
+ || 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;
+ Elf_Scn * symscn = elf_getscn (elf, symt);
+ symdata = elf_getdata (symscn, NULL);
+ xndxdata = get_xndxdata (elf, symscn);
+ if (symdata == NULL)
+ INTERNAL_ERROR (fname);
+
+ /* Apply one relocation. Returns true when trivial
+ relocation actually done. */
+ bool relocate (GElf_Addr offset, const GElf_Sxword addend,
+ bool is_rela, int rtype, int symndx)
+ {
+ /* R_*_NONE relocs can always just be removed. */
+ if (rtype == 0)
+ return true;
+
+ /* We only do simple absolute relocations. */
+ int addsub = 0;
+ Elf_Type type = ebl_reloc_simple_type (ebl, rtype, &addsub);
+ 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);
+ Elf32_Word sec = (sym->st_shndx == SHN_XINDEX
+ ? xndx : sym->st_shndx);
+
+ if (ebl_debugscn_p (ebl, secndx_name (elf, sec)))
+ {
+ size_t size;
+
+#define DO_TYPE(NAME, Name) GElf_##Name Name;
+ union { TYPES; } tmpbuf;
+#undef DO_TYPE
+
+ switch (type)
+ {
+#define DO_TYPE(NAME, Name) \
+ case ELF_T_##NAME: \
+ size = sizeof (GElf_##Name); \
+ tmpbuf.Name = 0; \
+ break;
+ TYPES;
+#undef DO_TYPE
+ default:
+ return false;
+ }
+
+ if (offset > tdata->d_size
+ || tdata->d_size - offset < size)
+ {
+ cleanup_debug ();
+ error (EXIT_FAILURE, 0, gettext ("bad relocation"));
+ }
+
+ /* When the symbol value is zero then for SHT_REL
+ sections this is all that needs to be checked.
+ The addend is contained in the original data at
+ the offset already. So if the (section) symbol
+ address is zero and the given addend is zero
+ just remove the relocation, it isn't needed
+ anymore. */
+ if (addend == 0 && sym->st_value == 0)
+ return true;
+
+ 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,
+ };
+
+ GElf_Addr value = sym->st_value;
+ if (is_rela)
+ {
+ /* For SHT_RELA sections we just take the
+ given addend and add it to the value. */
+ value += addend;
+ /* For ADD/SUB relocations we need to fetch the
+ current section contents. */
+ if (addsub != 0)
+ {
+ Elf_Data *d = gelf_xlatetom (elf, &tmpdata,
+ &rdata,
+ ehdr->e_ident[EI_DATA]);
+ if (d == NULL)
+ INTERNAL_ERROR (fname);
+ assert (d == &tmpdata);
+ }
+ }
+ else
+ {
+ /* For SHT_REL sections we have to peek at
+ what is already in the section at the given
+ offset to get the addend. */
+ Elf_Data *d = gelf_xlatetom (elf, &tmpdata,
+ &rdata,
+ ehdr->e_ident[EI_DATA]);
+ if (d == NULL)
+ INTERNAL_ERROR (fname);
+ assert (d == &tmpdata);
+ }
+
+ switch (type)
+ {
+#define DO_TYPE(NAME, Name) \
+ case ELF_T_##NAME: \
+ if (addsub < 0) \
+ tmpbuf.Name -= (GElf_##Name) value; \
+ else \
+ tmpbuf.Name += (GElf_##Name) value; \
+ break;
+ TYPES;
+#undef DO_TYPE
+ default:
+ abort ();
+ }
+
+ /* Now finally put in the new value. */
+ Elf_Data *s = gelf_xlatetof (elf, &rdata,
+ &tmpdata,
+ ehdr->e_ident[EI_DATA]);
+ if (s == NULL)
+ INTERNAL_ERROR (fname);
+ assert (s == &rdata);
+
+ return true;
+ }
+ return false;
+ }
+
+ if (shdr->sh_entsize == 0)
+ INTERNAL_ERROR (fname);
+
+ 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, false,
+ 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, true,
+ 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);
+
+ if (is_gnu_compressed)
+ {
+ if (elf_compress_gnu (tscn, 1, ELF_CHF_FORCE) != 1)
+ INTERNAL_ERROR (fname);
+ }
+ else if (tcompress_type != 0)
+ {
+ if (elf_compress (tscn, tcompress_type, ELF_CHF_FORCE) != 1)
+ INTERNAL_ERROR (fname);
+ }
+ }
+ }
+}
static int
process_file (const char *fname)
@@ -444,6 +799,116 @@ process_file (const char *fname)
return result;
}
+/* Processing for --reloc-debug-sections-only. */
+static int
+handle_debug_relocs (Elf *elf, Ebl *ebl, Elf *new_elf,
+ GElf_Ehdr *ehdr, const char *fname, size_t shstrndx,
+ GElf_Off *last_offset, GElf_Xword *last_size)
+{
+
+ /* Copy over the ELF header. */
+ if (gelf_update_ehdr (new_elf, ehdr) == 0)
+ {
+ error (0, 0, "couldn't update new ehdr: %s", elf_errmsg (-1));
+ return 1;
+ }
+
+ /* Copy over sections and record end of allocated sections. */
+ GElf_Off lastoffset = 0;
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (elf, scn)) != NULL)
+ {
+ /* Get the header. */
+ GElf_Shdr shdr;
+ if (gelf_getshdr (scn, &shdr) == NULL)
+ {
+ error (0, 0, "couldn't get shdr: %s", elf_errmsg (-1));
+ return 1;
+ }
+
+ /* Create new section. */
+ Elf_Scn *new_scn = elf_newscn (new_elf);
+ if (new_scn == NULL)
+ {
+ error (0, 0, "couldn't create new section: %s", elf_errmsg (-1));
+ return 1;
+ }
+
+ if (gelf_update_shdr (new_scn, &shdr) == 0)
+ {
+ error (0, 0, "couldn't update shdr: %s", elf_errmsg (-1));
+ return 1;
+ }
+
+ /* Copy over section data. */
+ Elf_Data *data = NULL;
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ Elf_Data *new_data = elf_newdata (new_scn);
+ if (new_data == NULL)
+ {
+ error (0, 0, "couldn't create new section data: %s",
+ elf_errmsg (-1));
+ return 1;
+ }
+ *new_data = *data;
+ }
+
+ /* Record last offset of allocated section. */
+ if ((shdr.sh_flags & SHF_ALLOC) != 0)
+ {
+ GElf_Off filesz = (shdr.sh_type != SHT_NOBITS
+ ? shdr.sh_size : 0);
+ if (lastoffset < shdr.sh_offset + filesz)
+ lastoffset = shdr.sh_offset + filesz;
+ }
+ }
+
+ /* Make sure section header name table is setup correctly, we'll
+ need it to determine whether to relocate sections. */
+ if (update_shdrstrndx (new_elf, shstrndx) != 0)
+ {
+ error (0, 0, "error updating shdrstrndx: %s", elf_errmsg (-1));
+ return 1;
+ }
+
+ /* Adjust the relocation sections. */
+ remove_debug_relocations (ebl, new_elf, ehdr, fname, shstrndx);
+
+ /* Adjust the offsets of the non-allocated sections, so they come after
+ the allocated sections. */
+ scn = NULL;
+ while ((scn = elf_nextscn (new_elf, scn)) != NULL)
+ {
+ /* Get the header. */
+ GElf_Shdr shdr;
+ if (gelf_getshdr (scn, &shdr) == NULL)
+ {
+ error (0, 0, "couldn't get shdr: %s", elf_errmsg (-1));
+ return 1;
+ }
+
+ /* Adjust non-allocated section offsets to be after any allocated. */
+ if ((shdr.sh_flags & SHF_ALLOC) == 0)
+ {
+ shdr.sh_offset = ((lastoffset + shdr.sh_addralign - 1)
+ & ~((GElf_Off) (shdr.sh_addralign - 1)));
+ if (gelf_update_shdr (scn, &shdr) == 0)
+ {
+ error (0, 0, "couldn't update shdr: %s", elf_errmsg (-1));
+ return 1;
+ }
+
+ GElf_Off filesz = (shdr.sh_type != SHT_NOBITS
+ ? shdr.sh_size : 0);
+ lastoffset = shdr.sh_offset + filesz;
+ *last_offset = shdr.sh_offset;
+ *last_size = filesz;
+ }
+ }
+
+ return 0;
+}
/* Maximum size of array allocated on stack. */
#define MAX_STACK_ALLOC (400 * 1024)
@@ -460,6 +925,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
tmp_debug_fname = NULL;
int result = 0;
size_t shdridx = 0;
+ GElf_Off lastsec_offset = 0;
+ Elf64_Xword lastsec_size = 0;
size_t shstrndx;
struct shdr_info
{
@@ -518,7 +985,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
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 || reloc_debug)
+ if (remove_debug || reloc_debug || reloc_debug_only)
{
ebl = ebl_openbackend (elf);
if (ebl == NULL)
@@ -580,49 +1047,75 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
else
newelf = elf_clone (elf, ELF_C_EMPTY);
- if (unlikely (gelf_newehdr (newelf, gelf_getclass (elf)) == 0)
- || (ehdr->e_type != ET_REL
- && unlikely (gelf_newphdr (newelf, phnum) == 0)))
+ if (unlikely (gelf_newehdr (newelf, gelf_getclass (elf)) == 0))
{
- error (0, 0, gettext ("cannot create new file '%s': %s"),
+ error (0, 0, gettext ("cannot create new ehdr for file '%s': %s"),
output_fname ?: fname, elf_errmsg (-1));
goto fail;
}
/* Copy over the old program header if needed. */
- if (ehdr->e_type != ET_REL)
- for (cnt = 0; cnt < phnum; ++cnt)
- {
- GElf_Phdr phdr_mem;
- GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem);
- if (phdr == NULL
- || unlikely (gelf_update_phdr (newelf, cnt, phdr) == 0))
- INTERNAL_ERROR (fname);
- }
+ if (phnum > 0)
+ {
+ if (unlikely (gelf_newphdr (newelf, phnum) == 0))
+ {
+ error (0, 0, gettext ("cannot create new phdr for file '%s': %s"),
+ output_fname ?: fname, elf_errmsg (-1));
+ goto fail;
+ }
+
+ for (cnt = 0; cnt < phnum; ++cnt)
+ {
+ GElf_Phdr phdr_mem;
+ GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem);
+ if (phdr == NULL
+ || unlikely (gelf_update_phdr (newelf, cnt, phdr) == 0))
+ INTERNAL_ERROR (fname);
+ }
+ }
+
+ if (reloc_debug_only)
+ {
+ if (handle_debug_relocs (elf, ebl, newelf, ehdr, fname, shstrndx,
+ &lastsec_offset, &lastsec_size) != 0)
+ {
+ result = 1;
+ goto fail_close;
+ }
+ idx = shstrndx;
+ goto done; /* Skip all actual stripping operations. */
+ }
if (debug_fname != NULL)
{
/* Also create an ELF descriptor for the debug file */
debugelf = elf_begin (debug_fd, ELF_C_WRITE_MMAP, NULL);
- if (unlikely (gelf_newehdr (debugelf, gelf_getclass (elf)) == 0)
- || (ehdr->e_type != ET_REL
- && unlikely (gelf_newphdr (debugelf, phnum) == 0)))
+ if (unlikely (gelf_newehdr (debugelf, gelf_getclass (elf)) == 0))
{
- error (0, 0, gettext ("cannot create new file '%s': %s"),
+ error (0, 0, gettext ("cannot create new ehdr for file '%s': %s"),
debug_fname, elf_errmsg (-1));
goto fail_close;
}
/* Copy over the old program header if needed. */
- if (ehdr->e_type != ET_REL)
- for (cnt = 0; cnt < phnum; ++cnt)
- {
- GElf_Phdr phdr_mem;
- GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem);
- if (phdr == NULL
- || unlikely (gelf_update_phdr (debugelf, cnt, phdr) == 0))
- INTERNAL_ERROR (fname);
- }
+ if (phnum > 0)
+ {
+ if (unlikely (gelf_newphdr (debugelf, phnum) == 0))
+ {
+ error (0, 0, gettext ("cannot create new phdr for file '%s': %s"),
+ debug_fname, elf_errmsg (-1));
+ goto fail_close;
+ }
+
+ for (cnt = 0; cnt < phnum; ++cnt)
+ {
+ GElf_Phdr phdr_mem;
+ GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem);
+ if (phdr == NULL
+ || unlikely (gelf_update_phdr (debugelf, cnt, phdr) == 0))
+ INTERNAL_ERROR (fname);
+ }
+ }
}
/* Number of sections. */
@@ -730,7 +1223,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
to keep the layout of all allocated sections as similar as
possible to the original file. In relocatable object files
everything can be moved. */
- if (ehdr->e_type == ET_REL
+ if (phnum == 0
|| (shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0)
shdr_info[cnt].shdr.sh_offset = 0;
@@ -784,9 +1277,13 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
if (shdr_info[shdr_info[cnt].group_idx].idx == 0)
{
- /* The section group section will be removed. */
+ /* The section group section might be removed.
+ Don't remove the SHF_GROUP flag. The section is
+ either also removed, in which case the flag doesn't matter.
+ Or it moves with the group into the debug file, then
+ it will be reconnected with the new group and should
+ still have the flag set. */
shdr_info[cnt].group_idx = 0;
- shdr_info[cnt].shdr.sh_flags &= ~SHF_GROUP;
}
}
@@ -1127,6 +1624,14 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
debugehdr->e_entry = ehdr->e_entry;
debugehdr->e_flags = ehdr->e_flags;
+ if (unlikely (gelf_update_ehdr (debugelf, debugehdr) == 0))
+ {
+ error (0, 0, gettext ("%s: error while updating ELF header: %s"),
+ debug_fname, elf_errmsg (-1));
+ result = 1;
+ goto fail_close;
+ }
+
size_t shdrstrndx;
if (elf_getshdrstrndx (elf, &shdrstrndx) < 0)
{
@@ -1136,36 +1641,9 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
goto fail_close;
}
- if (shstrndx < SHN_LORESERVE)
- debugehdr->e_shstrndx = shdrstrndx;
- else
+ if (update_shdrstrndx (debugelf, shdrstrndx) != 0)
{
- debugehdr->e_shstrndx = SHN_XINDEX;
- Elf_Scn *scn0 = elf_getscn (debugelf, 0);
- GElf_Shdr shdr0_mem;
- GElf_Shdr *shdr0 = gelf_getshdr (scn0, &shdr0_mem);
- if (shdr0 == NULL)
- {
- error (0, 0, gettext ("%s: error getting zero section: %s"),
- debug_fname, elf_errmsg (-1));
- result = 1;
- goto fail_close;
- }
-
- shdr0->sh_link = shdrstrndx;
- if (gelf_update_shdr (scn0, shdr0) == 0)
- {
- error (0, 0, gettext ("%s: error while updating zero section: %s"),
- debug_fname, elf_errmsg (-1));
- result = 1;
- goto fail_close;
- }
-
- }
-
- if (unlikely (gelf_update_ehdr (debugelf, debugehdr) == 0))
- {
- error (0, 0, gettext ("%s: error while creating ELF header: %s"),
+ error (0, 0, gettext ("%s: error updating shdrstrndx: %s"),
debug_fname, elf_errmsg (-1));
result = 1;
goto fail_close;
@@ -1360,7 +1838,9 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
&& shdr_info[cnt].data->d_buf != NULL);
Elf32_Word *grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf;
- for (size_t inner = 0;
+ /* First word is the section group flag.
+ Followed by section indexes, that need to be renumbered. */
+ for (size_t inner = 1;
inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word);
++inner)
if (grpref[inner] < shnum)
@@ -1950,240 +2430,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
zero based between the unallocated sections. */
if (debug_fname != NULL && removing_sections
&& 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);
- if (reldata == NULL || reldata->d_buf == NULL)
- INTERNAL_ERROR (fname);
-
- /* Make sure we adjust the uncompressed debug data
- (and recompress if necessary at the end). */
- GElf_Chdr tchdr;
- int tcompress_type = 0;
- if (gelf_getchdr (tscn, &tchdr) != NULL)
- {
- tcompress_type = tchdr.ch_type;
- if (elf_compress (tscn, 0, 0) != 1)
- INTERNAL_ERROR (fname);
- }
-
- Elf_Data *tdata = elf_getdata (tscn, NULL);
- if (tdata == NULL || tdata->d_buf == NULL
- || 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;
- elf_assert (symt < shnum + 2);
- elf_assert (shdr_info[symt].symtab_idx < shnum + 2);
- 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,
- bool is_rela, 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);
- Elf32_Word sec = (sym->st_shndx == SHN_XINDEX
- ? xndx : sym->st_shndx);
- if (sec >= shnum + 2)
- INTERNAL_ERROR (fname);
-
- if (ebl_debugscn_p (ebl, shdr_info[sec].name))
- {
- size_t size;
-
-#define DO_TYPE(NAME, Name) GElf_##Name Name;
- union { TYPES; } tmpbuf;
-#undef DO_TYPE
-
- switch (type)
- {
-#define DO_TYPE(NAME, Name) \
- case ELF_T_##NAME: \
- size = sizeof (GElf_##Name); \
- tmpbuf.Name = 0; \
- break;
- TYPES;
-#undef DO_TYPE
- default:
- return false;
- }
-
- if (offset > tdata->d_size
- || tdata->d_size - offset < size)
- {
- cleanup_debug ();
- error (EXIT_FAILURE, 0, gettext ("bad relocation"));
- }
-
- /* When the symbol value is zero then for SHT_REL
- sections this is all that needs to be checked.
- The addend is contained in the original data at
- the offset already. So if the (section) symbol
- address is zero and the given addend is zero
- just remove the relocation, it isn't needed
- anymore. */
- if (addend == 0 && sym->st_value == 0)
- return true;
-
- 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,
- };
-
- GElf_Addr value = sym->st_value;
- if (is_rela)
- {
- /* For SHT_RELA sections we just take the
- given addend and add it to the value. */
- value += addend;
- }
- else
- {
- /* For SHT_REL sections we have to peek at
- what is already in the section at the given
- offset to get the addend. */
- Elf_Data *d = gelf_xlatetom (debugelf, &tmpdata,
- &rdata,
- ehdr->e_ident[EI_DATA]);
- if (d == NULL)
- INTERNAL_ERROR (fname);
- assert (d == &tmpdata);
- }
-
- switch (type)
- {
-#define DO_TYPE(NAME, Name) \
- case ELF_T_##NAME: \
- tmpbuf.Name += (GElf_##Name) value; \
- break;
- TYPES;
-#undef DO_TYPE
- default:
- abort ();
- }
-
- /* Now finally put in the new value. */
- 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;
- }
-
- if (shdr->sh_entsize == 0)
- INTERNAL_ERROR (fname);
-
- 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, false,
- 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, true,
- 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);
-
- if (tcompress_type != 0)
- if (elf_compress (tscn, tcompress_type, ELF_CHF_FORCE) != 1)
- INTERNAL_ERROR (fname);
- }
- }
- }
+ remove_debug_relocations (ebl, debugelf, ehdr, fname, shstrndx);
/* Now that we have done all adjustments to the data,
we can actually write out the debug file. */
@@ -2247,6 +2494,10 @@ while computing checksum for debug information"));
}
}
+ lastsec_offset = shdr_info[shdridx].shdr.sh_offset;
+ lastsec_size = shdr_info[shdridx].shdr.sh_size;
+
+ done:
/* Finally finish the ELF header. Fill in the fields not handled by
libelf from the old file. */
newehdr = gelf_getehdr (newelf, &newehdr_mem);
@@ -2263,31 +2514,22 @@ while computing checksum for debug information"));
/* We need to position the section header table. */
const size_t offsize = gelf_fsize (elf, ELF_T_OFF, 1, EV_CURRENT);
- newehdr->e_shoff = ((shdr_info[shdridx].shdr.sh_offset
- + shdr_info[shdridx].shdr.sh_size + offsize - 1)
+ newehdr->e_shoff = ((lastsec_offset + lastsec_size + offsize - 1)
& ~((GElf_Off) (offsize - 1)));
newehdr->e_shentsize = gelf_fsize (elf, ELF_T_SHDR, 1, EV_CURRENT);
- /* The new section header string table index. */
- if (likely (idx < SHN_HIRESERVE) && likely (idx != SHN_XINDEX))
- newehdr->e_shstrndx = idx;
- else
+ if (gelf_update_ehdr (newelf, newehdr) == 0)
{
- /* The index does not fit in the ELF header field. */
- shdr_info[0].scn = elf_getscn (elf, 0);
-
- if (gelf_getshdr (shdr_info[0].scn, &shdr_info[0].shdr) == NULL)
- INTERNAL_ERROR (fname);
-
- shdr_info[0].shdr.sh_link = idx;
- (void) gelf_update_shdr (shdr_info[0].scn, &shdr_info[0].shdr);
-
- newehdr->e_shstrndx = SHN_XINDEX;
+ error (0, 0, gettext ("%s: error while creating ELF header: %s"),
+ output_fname ?: fname, elf_errmsg (-1));
+ cleanup_debug ();
+ return 1;
}
- if (gelf_update_ehdr (newelf, newehdr) == 0)
+ /* The new section header string table index. */
+ if (update_shdrstrndx (newelf, idx) != 0)
{
- error (0, 0, gettext ("%s: error while creating ELF header: %s"),
+ error (0, 0, gettext ("%s: error updating shdrstrndx: %s"),
output_fname ?: fname, elf_errmsg (-1));
cleanup_debug ();
return 1;
@@ -2305,7 +2547,7 @@ while computing checksum for debug information"));
/* The ELF library better follows our layout when this is not a
relocatable object file. */
elf_flagelf (newelf, ELF_C_SET,
- (ehdr->e_type != ET_REL ? ELF_F_LAYOUT : 0)
+ (phnum > 0 ? ELF_F_LAYOUT : 0)
| (permissive ? ELF_F_PERMISSIVE : 0));
/* Finally write the file. */
@@ -2334,7 +2576,7 @@ while computing checksum for debug information"));
|| (pwrite_retry (fd, zero, sizeof zero,
offsetof (Elf32_Ehdr, e_shentsize))
!= sizeof zero)
- || ftruncate (fd, shdr_info[shdridx].shdr.sh_offset) < 0)
+ || ftruncate (fd, lastsec_offset) < 0)
{
error (0, errno, gettext ("while writing '%s'"),
output_fname ?: fname);
@@ -2354,7 +2596,7 @@ while computing checksum for debug information"));
|| (pwrite_retry (fd, zero, sizeof zero,
offsetof (Elf64_Ehdr, e_shentsize))
!= sizeof zero)
- || ftruncate (fd, shdr_info[shdridx].shdr.sh_offset) < 0)
+ || ftruncate (fd, lastsec_offset) < 0)
{
error (0, errno, gettext ("while writing '%s'"),
output_fname ?: fname);
diff --git a/src/unstrip.c b/src/unstrip.c
index ae37d576..723cc746 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -245,6 +245,7 @@ copy_elf (Elf *outelf, Elf *inelf)
GElf_Ehdr ehdr_mem;
GElf_Ehdr *ehdr = gelf_getehdr (inelf, &ehdr_mem);
+ ELF_CHECK (ehdr != NULL, _("cannot get ELF header: %s"));
if (shstrndx < SHN_LORESERVE)
ehdr->e_shstrndx = shstrndx;
else
@@ -447,6 +448,9 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
switch (shdr->sh_type)
{
case SHT_REL:
+ if (shdr->sh_entsize == 0)
+ error (EXIT_FAILURE, 0, "REL section cannot have zero sh_entsize");
+
for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i)
{
GElf_Rel rel_mem;
@@ -458,6 +462,9 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
break;
case SHT_RELA:
+ if (shdr->sh_entsize == 0)
+ error (EXIT_FAILURE, 0, "RELA section cannot have zero sh_entsize");
+
for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i)
{
GElf_Rela rela_mem;
@@ -484,6 +491,10 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
case SHT_HASH:
/* We must expand the table and rejigger its contents. */
{
+ if (shdr->sh_entsize == 0)
+ error (EXIT_FAILURE, 0, "HASH section cannot have zero sh_entsize");
+ if (symshdr->sh_entsize == 0)
+ error (EXIT_FAILURE, 0, "Symbol table cannot have zero sh_entsize");
const size_t nsym = symshdr->sh_size / symshdr->sh_entsize;
const size_t onent = shdr->sh_size / shdr->sh_entsize;
assert (data->d_size == shdr->sh_size);
@@ -539,6 +550,11 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
case SHT_GNU_versym:
/* We must expand the table and move its elements around. */
{
+ if (shdr->sh_entsize == 0)
+ error (EXIT_FAILURE, 0,
+ "GNU_versym section cannot have zero sh_entsize");
+ if (symshdr->sh_entsize == 0)
+ error (EXIT_FAILURE, 0, "Symbol table cannot have zero sh_entsize");
const size_t nent = symshdr->sh_size / symshdr->sh_entsize;
const size_t onent = shdr->sh_size / shdr->sh_entsize;
assert (nent >= onent);
@@ -604,6 +620,8 @@ add_new_section_symbols (Elf_Scn *old_symscn, size_t old_shnum,
GElf_Shdr shdr_mem;
GElf_Shdr *shdr = gelf_getshdr (symscn, &shdr_mem);
ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
+ if (shdr->sh_entsize == 0)
+ error (EXIT_FAILURE, 0, "Symbol table section cannot have zero sh_entsize");
const size_t nsym = shdr->sh_size / shdr->sh_entsize;
size_t symndx_map[nsym - 1];
@@ -697,6 +715,7 @@ struct section
{
Elf_Scn *scn;
const char *name;
+ const char *sig;
Elf_Scn *outscn;
Dwelf_Strent *strent;
GElf_Shdr shdr;
@@ -721,7 +740,8 @@ compare_alloc_sections (const struct section *s1, const struct section *s2,
static int
compare_unalloc_sections (const GElf_Shdr *shdr1, const GElf_Shdr *shdr2,
- const char *name1, const char *name2)
+ const char *name1, const char *name2,
+ const char *sig1, const char *sig2)
{
/* Sort by sh_flags as an arbitrary ordering. */
if (shdr1->sh_flags < shdr2->sh_flags)
@@ -735,6 +755,10 @@ compare_unalloc_sections (const GElf_Shdr *shdr1, const GElf_Shdr *shdr2,
if (shdr1->sh_size > shdr2->sh_size)
return 1;
+ /* Are they both SHT_GROUP sections? Then compare signatures. */
+ if (sig1 != NULL && sig2 != NULL)
+ return strcmp (sig1, sig2);
+
/* Sort by name as last resort. */
return strcmp (name1, name2);
}
@@ -752,7 +776,8 @@ compare_sections (const void *a, const void *b, bool rel)
return ((s1->shdr.sh_flags & SHF_ALLOC)
? compare_alloc_sections (s1, s2, rel)
: compare_unalloc_sections (&s1->shdr, &s2->shdr,
- s1->name, s2->name));
+ s1->name, s2->name,
+ s1->sig, s2->sig));
}
static int
@@ -987,6 +1012,44 @@ get_section_name (size_t ndx, const GElf_Shdr *shdr, const Elf_Data *shstrtab)
return shstrtab->d_buf + shdr->sh_name;
}
+/* Returns the signature of a group section, or NULL if the given
+ section isn't a group. */
+static const char *
+get_group_sig (Elf *elf, GElf_Shdr *shdr)
+{
+ if (shdr->sh_type != SHT_GROUP)
+ return NULL;
+
+ Elf_Scn *symscn = elf_getscn (elf, shdr->sh_link);
+ if (symscn == NULL)
+ error (EXIT_FAILURE, 0, _("bad sh_link for group section: %s"),
+ elf_errmsg (-1));
+
+ GElf_Shdr symshdr_mem;
+ GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
+ if (symshdr == NULL)
+ error (EXIT_FAILURE, 0, _("couldn't get shdr for group section: %s"),
+ elf_errmsg (-1));
+
+ Elf_Data *symdata = elf_getdata (symscn, NULL);
+ if (symdata == NULL)
+ error (EXIT_FAILURE, 0, _("bad data for group symbol section: %s"),
+ elf_errmsg (-1));
+
+ GElf_Sym sym_mem;
+ GElf_Sym *sym = gelf_getsym (symdata, shdr->sh_info, &sym_mem);
+ if (sym == NULL)
+ error (EXIT_FAILURE, 0, _("couldn't get symbol for group section: %s"),
+ elf_errmsg (-1));
+
+ const char *sig = elf_strptr (elf, symshdr->sh_link, sym->st_name);
+ if (sig == NULL)
+ error (EXIT_FAILURE, 0, _("bad symbol name for group section: %s"),
+ elf_errmsg (-1));
+
+ return sig;
+}
+
/* Fix things up when prelink has moved some allocated sections around
and the debuginfo file's section headers no longer match up.
This fills in SECTIONS[0..NALLOC-1].outscn or exits.
@@ -1112,6 +1175,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
sec->scn = elf_getscn (main, i + 1); /* Really just for ndx. */
sec->outscn = NULL;
sec->strent = NULL;
+ sec->sig = get_group_sig (main, &sec->shdr);
++undo_nalloc;
}
}
@@ -1337,6 +1401,7 @@ more sections in stripped file than debug file -- arguments reversed?"));
sections[i].scn = scn;
sections[i].outscn = NULL;
sections[i].strent = NULL;
+ sections[i].sig = get_group_sig (stripped, shdr);
}
const struct section *stripped_symtab = NULL;
@@ -1355,7 +1420,8 @@ more sections in stripped file than debug file -- arguments reversed?"));
/* Locate a matching unallocated section in SECTIONS. */
inline struct section *find_unalloc_section (const GElf_Shdr *shdr,
- const char *name)
+ const char *name,
+ const char *sig)
{
size_t l = nalloc, u = stripped_shnum - 1;
while (l < u)
@@ -1363,7 +1429,8 @@ more sections in stripped file than debug file -- arguments reversed?"));
size_t i = (l + u) / 2;
struct section *sec = &sections[i];
int cmp = compare_unalloc_sections (shdr, &sec->shdr,
- name, sec->name);
+ name, sec->name,
+ sig, sec->sig);
if (cmp < 0)
u = i;
else if (cmp > 0)
@@ -1436,7 +1503,8 @@ more sections in stripped file than debug file -- arguments reversed?"));
else
{
/* Look for the section that matches. */
- sec = find_unalloc_section (shdr, name);
+ sec = find_unalloc_section (shdr, name,
+ get_group_sig (unstripped, shdr));
if (sec == NULL)
{
/* An additional unallocated section is fine if not SHT_NOBITS.
@@ -1622,6 +1690,9 @@ more sections in stripped file than debug file -- arguments reversed?"));
Elf_Data *shndxdata = NULL; /* XXX */
+ if (shdr_mem.sh_entsize == 0)
+ error (EXIT_FAILURE, 0,
+ "SYMTAB section cannot have zero sh_entsize");
for (size_t i = 1; i < shdr_mem.sh_size / shdr_mem.sh_entsize; ++i)
{
GElf_Sym sym_mem;
@@ -1659,6 +1730,20 @@ more sections in stripped file than debug file -- arguments reversed?"));
if (shdr_mem.sh_type == SHT_DYNSYM)
stripped_dynsym = sec;
}
+
+ if (shdr_mem.sh_type == SHT_GROUP)
+ {
+ /* We must adjust all the section indices in the group.
+ Skip the first word, which is the section group flag.
+ Everything else is a section index. */
+ Elf32_Word *shndx = (Elf32_Word *) outdata->d_buf;
+ for (size_t i = 1; i < shdr_mem.sh_size / sizeof (Elf32_Word); ++i)
+ if (shndx[i] == SHN_UNDEF || shndx[i] >= stripped_shnum)
+ error (EXIT_FAILURE, 0,
+ _("group has invalid section index [%zd]"), i);
+ else
+ shndx[i] = ndx_section[shndx[i] - 1];
+ }
}
/* We may need to update the symbol table. */
@@ -1673,11 +1758,16 @@ more sections in stripped file than debug file -- arguments reversed?"));
/* Merge the stripped file's symbol table into the unstripped one. */
const size_t stripped_nsym = (stripped_symtab == NULL ? 1
: (stripped_symtab->shdr.sh_size
- / stripped_symtab->shdr.sh_entsize));
+ / (stripped_symtab->shdr.sh_entsize == 0
+ ? 1
+ : stripped_symtab->shdr.sh_entsize)));
GElf_Shdr shdr_mem;
GElf_Shdr *shdr = gelf_getshdr (unstripped_symtab, &shdr_mem);
ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
+ if (shdr->sh_entsize == 0)
+ error (EXIT_FAILURE, 0,
+ "unstripped SYMTAB section cannot have zero sh_entsize");
const size_t unstripped_nsym = shdr->sh_size / shdr->sh_entsize;
/* First collect all the symbols from both tables. */