From: Di Chen <dic...@redhat.com> Provide a public function for removing debug section relocations.
eu-strip previously contained the code to remove debug section relocations. This patch moves that code into dwelf_elf_remove_debug_relocs. https://sourceware.org/bugzilla/show_bug.cgi?id=31447 Signed-off-by: Di Chen <dic...@redhat.com> Signed-off-by: Aaron Merey <ame...@redhat.com> --- I'd like to be able to call __libelf_seterrno from dwelf_elf_remove_debug_relocations.c, but I keep getting the following linker error: > /usr/local/bin/ld: > ../libdwelf/libdwelf_pic.a(dwelf_elf_remove_debug_relocations.os): in > function `relocate': > /home/amerey/elfutils/libdwelf/dwelf_elf_remove_debug_relocations.c:113:(.text+0x28e): > undefined reference to `__libelf_seterrno' I tried to modifying libdwelf/Makefile.am but wasn't able to solve this. __libdw_seterrno works without this issue and I'm not sure what's missing from the libelf linking. I've left the calls to __libelf_seterrno commented out for now. v1: https://sourceware.org/pipermail/elfutils-devel/2024q3/007388.html v2 changes: Renamed dwelf_relocation_debug_sections to dwelf_elf_remove_debug_relocations. Renamed various files to match this new function name. Removed all asserts and error exits from dwelf_elf_remove_debug_relocations.c libdw/libdw.map | 1 + libdwelf/Makefile.am | 5 +- libdwelf/dwelf_elf_remove_debug_relocations.c | 400 ++++++++++++++++++ libdwelf/libdwelf.h | 4 + src/strip.c | 354 +--------------- tests/Makefile.am | 5 +- tests/remove-relocs.c | 38 ++ tests/run-remove-relocs.sh | 54 +++ tests/testfile-remove-relocs.bz2 | Bin 0 -> 1088 bytes 9 files changed, 513 insertions(+), 348 deletions(-) create mode 100644 libdwelf/dwelf_elf_remove_debug_relocations.c create mode 100644 tests/remove-relocs.c create mode 100755 tests/run-remove-relocs.sh create mode 100644 tests/testfile-remove-relocs.bz2 diff --git a/libdw/libdw.map b/libdw/libdw.map index bc53385f..b282e886 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -384,4 +384,5 @@ ELFUTILS_0.192 { dwfl_set_sysroot; dwfl_frame_unwound_source; dwfl_unwound_source_str; + dwelf_elf_remove_debug_relocations; } ELFUTILS_0.191; diff --git a/libdwelf/Makefile.am b/libdwelf/Makefile.am index a35a2873..6090fd64 100644 --- a/libdwelf/Makefile.am +++ b/libdwelf/Makefile.am @@ -42,13 +42,14 @@ noinst_HEADERS = libdwelfP.h libdwelf_a_SOURCES = dwelf_elf_gnu_debuglink.c dwelf_dwarf_gnu_debugaltlink.c \ dwelf_elf_gnu_build_id.c dwelf_scn_gnu_compressed_size.c \ dwelf_strtab.c dwelf_elf_begin.c \ - dwelf_elf_e_machine_string.c + dwelf_elf_e_machine_string.c \ + dwelf_elf_remove_debug_relocations.c libdwelf = $(libdw) libdw = ../libdw/libdw.so libelf = ../libelf/libelf.so -libebl = ../libebl/libebl.a +libebl = ../libebl/libebl.a ../backends/libebl_backends.a libeu = ../lib/libeu.a libdwelf_pic_a_SOURCES = diff --git a/libdwelf/dwelf_elf_remove_debug_relocations.c b/libdwelf/dwelf_elf_remove_debug_relocations.c new file mode 100644 index 00000000..cbb25fb4 --- /dev/null +++ b/libdwelf/dwelf_elf_remove_debug_relocations.c @@ -0,0 +1,400 @@ +/* Remove relocations from debug sections. + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwelfP.h" +#include "libelfP.h" +#include "libebl.h" + +typedef uint8_t GElf_Byte; + +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) ?: "???"; +} + + +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; +} + + +bool +relocate (Elf *elf, GElf_Addr offset, const GElf_Sxword addend, + Elf_Data *tdata, unsigned int ei_data, bool is_rela, + GElf_Sym *sym, int addsub, Elf_Type type) +{ + /* 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) + + 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) + { + //__libelf_seterrno (ELF_E_INVALID_OFFSET); + return false; + } + + /* 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, + ei_data); + if (d == NULL || d != &tmpdata) + { + //__libelf_seterrno (ELF_E_INVALID_HANDLE); + return false; + } + } + } + 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, + ei_data); + if (d == NULL || d != &tmpdata) + { + //__libelf_seterrno (ELF_E_INVALID_HANDLE); + return false; + } + } + + 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: + //__libelf_seterrno (ELF_E_UNKNOWN_TYPE); + return false; + } + + /* Now finally put in the new value. */ + Elf_Data *s = gelf_xlatetof (elf, &rdata, + &tmpdata, + ei_data); + if (s == NULL || s != &rdata) + { + //__libelf_seterrno (ELF_E_INVALID_HANDLE); + return false; + } + + return true; +} + + +int dwelf_elf_remove_debug_relocations (Elf *elf) +{ + size_t shstrndx; + if (elf_getshdrstrndx (elf, &shstrndx) < 0) + return -1; + + GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + return -1; + + const unsigned int ei_data = ehdr->e_ident[EI_DATA]; + + Ebl *ebl = ebl_openbackend (elf); + if (ebl == NULL) + return -1; + + int res = -1; + 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 != NULL + && (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 == NULL + || 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) + goto exit; + + /* 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 (startswith (tname, ".zdebug")) + { + is_gnu_compressed = true; + if (elf_compress_gnu (tscn, 0, 0) != 1) + goto exit; + } + else + { + if (gelf_getchdr (tscn, &tchdr) != NULL) + { + tcompress_type = tchdr.ch_type; + if (elf_compress (tscn, 0, 0) != 1) + goto exit; + } + } + + Elf_Data *tdata = elf_getdata (tscn, NULL); + if (tdata == NULL || tdata->d_buf == NULL + || tdata->d_type != ELF_T_BYTE) + goto exit; + + /* 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) + goto exit; + + if (shdr->sh_entsize == 0) + goto exit; + + size_t nrels = shdr->sh_size / shdr->sh_entsize; + size_t next = 0; + const bool is_rela = (shdr->sh_type == SHT_RELA); + + for (size_t relidx = 0; relidx < nrels; ++relidx) + { + int rtype, symndx, offset, addend; + union { GElf_Rela rela; GElf_Rel rel; } mem; + void *rel_p; /* Pointer to either rela or rel above */ + + if (is_rela) + { + GElf_Rela *r = gelf_getrela (reldata, relidx, &mem.rela); + if (r == NULL) + goto exit; + offset = r->r_offset; + addend = r->r_addend; + rtype = GELF_R_TYPE (r->r_info); + symndx = GELF_R_SYM (r->r_info); + rel_p = r; + } + else + { + GElf_Rel *r = gelf_getrel (reldata, relidx, &mem.rel); + if (r == NULL) + goto exit; + offset = r->r_offset; + addend = 0; + rtype = GELF_R_TYPE (r->r_info); + symndx = GELF_R_SYM (r->r_info); + rel_p = r; + } + + /* R_*_NONE relocs can always just be removed. */ + if (rtype == 0) + continue; + + /* We only do simple absolute relocations. */ + int addsub = 0; + Elf_Type type = ebl_reloc_simple_type (ebl, rtype, &addsub); + if (type == ELF_T_NUM) + goto relocate_failed; + + /* 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 (sym == NULL) + goto exit; + Elf32_Word sec = (sym->st_shndx == SHN_XINDEX + ? xndx : sym->st_shndx); + + bool dbg_scn = ebl_debugscn_p (ebl, secndx_name (elf, sec)); + + if (!dbg_scn) + goto relocate_failed; + + if (! relocate (elf, offset, addend, tdata, ei_data, is_rela, + sym, addsub, type)) + goto relocate_failed; + + continue; /* Next */ + +relocate_failed: + if (relidx != next) + { + int updated; + if (is_rela) + updated = gelf_update_rela (reldata, next, rel_p); + else + updated = gelf_update_rel (reldata, next, rel_p); + if (updated == 0) + goto exit; + } + ++next; + } + + nrels = next; + shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize; + if (gelf_update_shdr (scn, shdr) == 0) + goto exit; + + if (is_gnu_compressed) + { + if (elf_compress_gnu (tscn, 1, ELF_CHF_FORCE) != 1) + goto exit; + } + else if (tcompress_type != 0) + { + if (elf_compress (tscn, tcompress_type, ELF_CHF_FORCE) != 1) + goto exit; + } + } + } + + res = 0; + +exit: + ebl_closebackend (ebl); + return res; +} diff --git a/libdwelf/libdwelf.h b/libdwelf/libdwelf.h index 263ca60e..734aa9c3 100644 --- a/libdwelf/libdwelf.h +++ b/libdwelf/libdwelf.h @@ -140,6 +140,10 @@ extern Elf *dwelf_elf_begin (int fd); value, or NULL if the given number isn't currently known. */ extern const char *dwelf_elf_e_machine_string (int machine); +/* Remove relocations for debug sections. Returns 0 on success. + Returns -1 on failure and sets elf_errno. */ +extern int dwelf_elf_remove_debug_relocations (Elf *elf); + #ifdef __cplusplus } #endif diff --git a/src/strip.c b/src/strip.c index 403e0f6f..a431ebbe 100644 --- a/src/strip.c +++ b/src/strip.c @@ -367,46 +367,6 @@ 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. */ @@ -440,306 +400,6 @@ update_shdrstrndx (Elf *elf, size_t shdrstrndx) } -/* Apply one relocation. Returns true when trivial - relocation actually done. */ -static bool -relocate (Elf *elf, GElf_Addr offset, const GElf_Sxword addend, - Elf_Data *tdata, unsigned int ei_data, const char *fname, - bool is_rela, GElf_Sym *sym, int addsub, Elf_Type type) -{ - /* 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) - - 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 (0, _("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, - 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, - 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, - ei_data); - if (s == NULL) - INTERNAL_ERROR (fname); - assert (s == &rdata); - - return true; -} - -/* 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 != NULL - && (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 == NULL - || 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 (startswith (tname, ".zdebug")) - { - 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); - - if (shdr->sh_entsize == 0) - INTERNAL_ERROR (fname); - - size_t nrels = shdr->sh_size / shdr->sh_entsize; - size_t next = 0; - const bool is_rela = (shdr->sh_type == SHT_RELA); - const unsigned int ei_data = ehdr->e_ident[EI_DATA]; - - for (size_t relidx = 0; relidx < nrels; ++relidx) - { - int rtype, symndx, offset, addend; - union { GElf_Rela rela; GElf_Rel rel; } mem; - void *rel_p; /* Pointer to either rela or rel above */ - - if (is_rela) - { - GElf_Rela *r = gelf_getrela (reldata, relidx, &mem.rela); - if (r == NULL) - INTERNAL_ERROR (fname); - offset = r->r_offset; - addend = r->r_addend; - rtype = GELF_R_TYPE (r->r_info); - symndx = GELF_R_SYM (r->r_info); - rel_p = r; - } - else - { - GElf_Rel *r = gelf_getrel (reldata, relidx, &mem.rel); - if (r == NULL) - INTERNAL_ERROR (fname); - offset = r->r_offset; - addend = 0; - rtype = GELF_R_TYPE (r->r_info); - symndx = GELF_R_SYM (r->r_info); - rel_p = r; - } - - /* R_*_NONE relocs can always just be removed. */ - if (rtype == 0) - continue; - - /* We only do simple absolute relocations. */ - int addsub = 0; - Elf_Type type = ebl_reloc_simple_type (ebl, rtype, &addsub); - if (type == ELF_T_NUM) - goto relocate_failed; - - /* 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 (sym == NULL) - INTERNAL_ERROR (fname); - Elf32_Word sec = (sym->st_shndx == SHN_XINDEX - ? xndx : sym->st_shndx); - - bool dbg_scn = ebl_debugscn_p (ebl, secndx_name (elf, sec)); - - if (!dbg_scn) - goto relocate_failed; - - if (! relocate (elf, offset, addend, - tdata, ei_data, fname, is_rela, - sym, addsub, type)) - goto relocate_failed; - - continue; /* Next */ - -relocate_failed: - if (relidx != next) - { - int updated; - if (is_rela) - updated = gelf_update_rela (reldata, next, rel_p); - else - updated = gelf_update_rel (reldata, next, rel_p); - if (updated == 0) - INTERNAL_ERROR (fname); - } - ++next; - } - - nrels = next; - shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize; - if (gelf_update_shdr (scn, shdr) == 0) - INTERNAL_ERROR (fname); - - 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) { @@ -839,7 +499,7 @@ process_file (const char *fname) /* Processing for --reloc-debug-sections-only. */ static int -handle_debug_relocs (Elf *elf, Ebl *ebl, Elf *new_elf, +handle_debug_relocs (Elf *elf, Elf *new_elf, GElf_Ehdr *ehdr, const char *fname, size_t shstrndx, GElf_Off *last_offset, GElf_Xword *last_size) { @@ -910,8 +570,9 @@ handle_debug_relocs (Elf *elf, Ebl *ebl, Elf *new_elf, return 1; } - /* Adjust the relocation sections. */ - remove_debug_relocations (ebl, new_elf, ehdr, fname, shstrndx); + /* Remove debug section relocations. */ + if (dwelf_elf_remove_debug_relocations (new_elf) == -1) + INTERNAL_ERROR (fname); /* Adjust the offsets of the non-allocated sections, so they come after the allocated sections. */ @@ -1139,7 +800,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, if (reloc_debug_only) { - if (handle_debug_relocs (elf, ebl, newelf, ehdr, fname, shstrndx, + if (handle_debug_relocs (elf, newelf, ehdr, fname, shstrndx, &lastsec_offset, &lastsec_size) != 0) { result = 1; @@ -2457,7 +2118,10 @@ 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) - remove_debug_relocations (ebl, debugelf, ehdr, fname, shstrndx); + { + if (dwelf_elf_remove_debug_relocations (debugelf) == -1) + INTERNAL_ERROR (fname); + } /* Now that we have done all adjustments to the data, we can actually write out the debug file. */ diff --git a/tests/Makefile.am b/tests/Makefile.am index ffccb0cd..a3c4a745 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -59,7 +59,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \ get-units-invalid get-units-split attr-integrate-skel \ all-dwarf-ranges unit-info next_cfi \ elfcopy addsections xlate_notes elfrdwrnop \ - dwelf_elf_e_machine_string \ + dwelf_elf_e_machine_string remove-relocs \ getphdrnum leb128 read_unaligned \ msg_tst system-elf-libelf-test system-elf-gelf-test \ nvidia_extended_linemap_libdw elf-print-reloc-syms \ @@ -204,6 +204,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \ run-strip-version.sh run-xlate-note.sh \ run-readelf-discr.sh \ run-dwelf_elf_e_machine_string.sh \ + run-remove-relocs.sh \ run-elfclassify.sh run-elfclassify-self.sh \ run-disasm-riscv64.sh \ run-pt_gnu_prop-tests.sh \ @@ -576,6 +577,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \ run-readelf-discr.sh \ testfile-rng.debug.bz2 testfile-urng.debug.bz2 \ run-dwelf_elf_e_machine_string.sh \ + run-remove-relocs.sh testfile-remove-relocs.bz2 \ run-elfclassify.sh run-elfclassify-self.sh \ run-disasm-riscv64.sh \ testfile-riscv64-dis1.o.bz2 testfile-riscv64-dis1.expect.bz2 \ @@ -856,6 +858,7 @@ debuginfod_build_id_find_LDADD = $(libelf) $(libdw) xlate_notes_LDADD = $(libelf) elfrdwrnop_LDADD = $(libelf) dwelf_elf_e_machine_string_LDADD = $(libelf) $(libdw) +remove_relocs_LDADD = $(libelf) $(libdw) getphdrnum_LDADD = $(libelf) $(libdw) leb128_LDADD = $(libelf) $(libdw) read_unaligned_LDADD = $(libelf) $(libdw) diff --git a/tests/remove-relocs.c b/tests/remove-relocs.c new file mode 100644 index 00000000..9a678f59 --- /dev/null +++ b/tests/remove-relocs.c @@ -0,0 +1,38 @@ +/* Test program for dwelf_elf_remove_debug_relocs + Copyright (C) 2024 Red Hat, Inc. + This file is part of elfutils. + + This file 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; either version 3 of the License, or + (at your option) any later version. + + 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 this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <fcntl.h> +#include ELFUTILS_HEADER(dw) +#include ELFUTILS_HEADER(dwelf) + +int main(int argc __attribute__ ((unused)), char **argv) { + Elf *elf; + elf_version (EV_CURRENT); + int fd = open (argv[1], O_RDWR); + + elf = elf_begin (fd, ELF_C_RDWR, NULL); + + dwelf_elf_remove_debug_relocations (elf); + elf_update (elf, ELF_C_WRITE); + + elf_end (elf); + return 0; +} diff --git a/tests/run-remove-relocs.sh b/tests/run-remove-relocs.sh new file mode 100755 index 00000000..3a49a5ab --- /dev/null +++ b/tests/run-remove-relocs.sh @@ -0,0 +1,54 @@ +#! /usr/bin/env bash +# Test dwelf_elf_remove_debug_relocations +# Copyright (C) 2024 Red Hat, Inc. +# This file is part of elfutils. +# +# This file 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; either version 3 of the License, or +# (at your option) any later version. +# +# 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 this program. If not, see <http://www.gnu.org/licenses/>. + +. $srcdir/test-subr.sh + +# = qq.c = +# int add (int a, int b) +# { +# return a+b; +# } +# +# int main() +# { +# return 0; +# } + +# Using gcc (GCC) 14.2.1 20240801 (Red Hat 14.2.1-1) +# gcc -g -c qq.c -o testfile-remove-relocs + +testfiles testfile-remove-relocs + +# Before debug relocations are removed some indices into string tables are +# set to a default value of 0. This causes incorrect file and function +# names to be displayed. +testrun_compare ${abs_builddir}/allfcts testfile-remove-relocs <<\EOF +qq.c/qq.c:6:GNU C17 14.2.1 20240801 (Red Hat 14.2.1-1) -mtune=generic -march=x86-64 -g +qq.c/qq.c:1:add +EOF + +# Remove debug relocations and write the changes to the testfile. +testrun ${abs_builddir}/remove-relocs testfile-remove-relocs + +# Correct file and function names should now be displayed. +testrun_compare ${abs_builddir}/allfcts testfile-remove-relocs <<\EOF +/home/dichen/elfutils/tests/qq.c:6:main +/home/dichen/elfutils/tests/qq.c:1:add +EOF + +exit 0 diff --git a/tests/testfile-remove-relocs.bz2 b/tests/testfile-remove-relocs.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..2f7ca9b63adb5afc4e7b454c2531f328041de010 GIT binary patch literal 1088 zcmV-G1i$-2T4*^jL0KkKS)er3J^%yRfB*mg|Ni#(_5b_r(_;Vc|9gvQWE8{z0K`cE zL_h*SU`)^hde?`qYcFQ@bAv@sQ&Ue-r>W{R^)pjVs2MQ;dTIaw01W|=pa1{>01W^& zPfB_a%6e%(RMF`@G(Z3V02%-QXaE2J0ib9A05vd(6*r|D)X>l-(V*1Yn3`d!ko5*Y z1`q*>gu-ahVh=<E)L=46O#{>hgHKQZX`sOxGynhwMu5;^0B8n)00070Q8Xq%Ddieu z&@|8h^#e^b4F-ly02%;jXf$Zh8hU{B4^RmDELD`%=HnQFAq_A<j3g?~{TX(abYl{y zO1yNEP?>*eHhohwHb?H%Q<GBlQVcCwZG(34Ly~gTMjxcY0w>?Jj5JcDh-nnrqZ0yV zp?K}+M)t}&0TYBpCP4s>M`X-{9QKu}rm8^2{8G<rmvHntQK<$=uMS6i4`?@B-P_J< z%m!V7IR&vcZUI6DR_)ea<^VH83TxYzrje;jiJ{to6lub^sHS+$i&s%SY>a9WfHFg1 z%;3?B4tGyKDx*gDKoITZ&l#gxiGagE0gi!*lLY8tvr_{Eh+xb?RW?#K>6!S>Hd-eY zQF{5F4VH#rf@T<?h7U>{fCstIN<a=`5<-yfAS6g2&9~iHnZ%LgUyV;z;g8HZ7c4Bf z6+13wG88W}oqsN~g*I*74l7Z<Xx#H=k_-p4KoS<UF}-<gg#_Y22#AQ8MV!P`q$WA9 zes-3rNEqL7i(ls}{fU_12fV0In@H)@l&M67dV~Z}Z>WYCAw-%-swAQUOoJIk)esR% zCJPzH23@a#<pRjM1&>oMT86mdtp1}Z5NdFSDY9*X0TDQ5V3Fdk<T=hvnT!<l_G5=h z%-*yfQ^-(!LIQ#VQ*WgDK6iW1?t!0L8u2hnt`Wc`UC17D1D^odErw%u#uEsk(jZ~o zny^7bvOi*&jG>ri;1Lt4OhI(Qj!q8Sh~h>FOk`gNj!!JRhh&3AoRYz1W~`%uZbp(j z`(a=?vs?t-7D9WEx*D>ns)3S3WRU}!zs#gkDn)mEW1m45Leqi7Mw0L+D9ZR7S?`rB ztJuvHH;@uvof^{^)#`vM17&EEEvlNnxSo7Nkuo7}BkPlc)_^q~`oeSqs;6gRG$Vkg z-0Y}YDo>PhS|Rb12AXW=fMvL^DBUv1JMdvp-3NODpvW%Fh(5%mW8x6j$@g_f4kR1I zM>t4XEXyu)<|I_1Udd|=Z1_|C;@CxF5}ksfWMDpR<BP5mOf(?`J>U%%`P2@<N|A|K zKxa)zY%>9&F2mTMKM_fwv*4f+A45<Y5g0ZUQUgKK6$XD|OQeV;B!LV&m=rP2elX5G zSf?Gd(`-4Rwhvs*S^eOy;ozPTHEBaYHTZ&o0T@m2<x)DJ)3?L0dxM|D#4hBDaG@bU GX{dalrP>4l literal 0 HcmV?d00001 -- 2.46.2