Hey team elfutils, This patch is for https://sourceware.org/bugzilla/show_bug.cgi?id=31447, and it is ready for code review now 😀
Regards, Di
From 5326db4241c15a4b2760d12bcc6b58aec86eda98 Mon Sep 17 00:00:00 2001 From: Di Chen <dic...@redhat.com> Date: Sun, 7 Jul 2024 14:57:30 +0800 Subject: [PATCH] libdwelf: provide a public debug section relocation function When opening an ET_REL file through libdwfl, we do resolve all cross-debug-section relocations using __libdwfl_relocate(). This commit provide a public function for the above feature, so users can make sure that ET_REL files can be handled by libdw. Here is an example: int main(int argc, char **argv) { const char *fname = argv[1]; Elf *elf; elf_version(EV_CURRENT); int fd = open(argv[1], O_RDWR); elf = elf_begin(fd, ELF_C_RDWR, NULL); dwelf_relocation_debug_sections(elf, fname); elf_update(elf, ELF_C_WRITE); return 0; } https://sourceware.org/bugzilla/show_bug.cgi?id=31447 Signed-off-by: Di Chen <dic...@redhat.com> --- libdw/libdw.map | 5 + libdwelf/Makefile.am | 5 +- libdwelf/dwelf_relocation_debug_sections.c | 389 +++++++++++++++++++++ libdwelf/libdwelf.h | 3 + src/strip.c | 348 +----------------- tests/Makefile.am | 5 +- tests/dwelf_reloc_dbg_scn.c | 25 ++ tests/run-dwelf-reloc-dbg-scn.sh | 48 +++ tests/testfile-dwelf-reloc-dbg-scn.o.bz2 | Bin 0 -> 1088 bytes 9 files changed, 481 insertions(+), 347 deletions(-) create mode 100644 libdwelf/dwelf_relocation_debug_sections.c create mode 100644 tests/dwelf_reloc_dbg_scn.c create mode 100755 tests/run-dwelf-reloc-dbg-scn.sh create mode 100644 tests/testfile-dwelf-reloc-dbg-scn.o.bz2 diff --git a/libdw/libdw.map b/libdw/libdw.map index 552588a9..529036f8 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -383,3 +383,8 @@ ELFUTILS_0.192 { global: dwfl_set_sysroot; } ELFUTILS_0.191; + +ELFUTILS_0.193 { + global: + dwelf_relocation_debug_sections; +} ELFUTILS_0.192; diff --git a/libdwelf/Makefile.am b/libdwelf/Makefile.am index a35a2873..a3d9cdd4 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_relocation_debug_sections.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_relocation_debug_sections.c b/libdwelf/dwelf_relocation_debug_sections.c new file mode 100644 index 00000000..b2949124 --- /dev/null +++ b/libdwelf/dwelf_relocation_debug_sections.c @@ -0,0 +1,389 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include "libdwP.h" +#include "libebl.h" + +#define INTERNAL_ERROR(fname) \ + error_exit(0, _("%s: INTERNAL ERROR %d (%s): %s"), fname, __LINE__, \ + PACKAGE_VERSION, elf_errmsg(-1)) + +typedef uint8_t GElf_Byte; +static int debug_fd = -1; +static char *tmp_debug_fname = NULL; + + +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; +} + + +void +cleanup_debug (void) +{ + if (debug_fd >= 0) + { + if (tmp_debug_fname != NULL) + { + unlink (tmp_debug_fname); + free (tmp_debug_fname); + tmp_debug_fname = NULL; + } + close (debug_fd); + debug_fd = -1; + } +} + + +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; +} + + +void dwelf_relocation_debug_sections (Elf *elf, const char *fname) +{ + size_t shstrndx; + if (elf_getshdrstrndx (elf, &shstrndx) < 0) + INTERNAL_ERROR (fname); + + GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + { + // __libdwfl_seterrno (DWFL_E_LIBELF); + INTERNAL_ERROR (fname); + } + const unsigned int ei_data = ehdr->e_ident[EI_DATA]; + + Ebl *ebl = ebl_openbackend (elf); + if (ebl == NULL) + { + // __libdwfl_seterrno (DWFL_E_LIBEBL); + INTERNAL_ERROR (fname); + } + + 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); + + 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); + } + } + } + +} diff --git a/libdwelf/libdwelf.h b/libdwelf/libdwelf.h index 263ca60e..89936bf8 100644 --- a/libdwelf/libdwelf.h +++ b/libdwelf/libdwelf.h @@ -140,6 +140,9 @@ 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); +/* Provide a public debug section relocation function. */ +extern void dwelf_relocation_debug_sections (Elf *elf, const char *fname); + #ifdef __cplusplus } #endif diff --git a/src/strip.c b/src/strip.c index 403e0f6f..b46966e6 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) { @@ -911,7 +571,7 @@ handle_debug_relocs (Elf *elf, Ebl *ebl, Elf *new_elf, } /* Adjust the relocation sections. */ - remove_debug_relocations (ebl, new_elf, ehdr, fname, shstrndx); + dwelf_relocation_debug_sections (new_elf, fname); /* Adjust the offsets of the non-allocated sections, so they come after the allocated sections. */ @@ -1139,7 +799,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 +2117,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) - remove_debug_relocations (ebl, debugelf, ehdr, fname, shstrndx); + dwelf_relocation_debug_sections (debugelf, 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 cdb2d405..69cfc1ba 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 dwelf_reloc_dbg_scn\ getphdrnum leb128 read_unaligned \ msg_tst system-elf-libelf-test system-elf-gelf-test \ nvidia_extended_linemap_libdw elf-print-reloc-syms \ @@ -205,6 +205,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-dwelf-reloc-dbg-scn.sh \ run-elfclassify.sh run-elfclassify-self.sh \ run-disasm-riscv64.sh \ run-pt_gnu_prop-tests.sh \ @@ -575,6 +576,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-dwelf-reloc-dbg-scn.sh testfile-dwelf-reloc-dbg-scn.o.bz2 \ run-elfclassify.sh run-elfclassify-self.sh \ run-disasm-riscv64.sh \ testfile-riscv64-dis1.o.bz2 testfile-riscv64-dis1.expect.bz2 \ @@ -851,6 +853,7 @@ debuginfod_build_id_find_LDADD = $(libelf) $(libdw) xlate_notes_LDADD = $(libelf) elfrdwrnop_LDADD = $(libelf) dwelf_elf_e_machine_string_LDADD = $(libelf) $(libdw) +dwelf_reloc_dbg_scn_LDADD = $(libelf) $(libdw) getphdrnum_LDADD = $(libelf) $(libdw) leb128_LDADD = $(libelf) $(libdw) read_unaligned_LDADD = $(libelf) $(libdw) diff --git a/tests/dwelf_reloc_dbg_scn.c b/tests/dwelf_reloc_dbg_scn.c new file mode 100644 index 00000000..bef58c01 --- /dev/null +++ b/tests/dwelf_reloc_dbg_scn.c @@ -0,0 +1,25 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <err.h> +#include <fcntl.h> +#include ELFUTILS_HEADER(dw) +#include ELFUTILS_HEADER(dwelf) +#include <stdio.h> +#include <unistd.h> + +int main(int /*argc*/, char **argv) { + const char *fname = argv[1]; + + Elf *elf; + elf_version(EV_CURRENT); + int fd = open(argv[1], O_RDWR); + + elf = elf_begin(fd, ELF_C_RDWR, NULL); + + dwelf_relocation_debug_sections(elf, fname); + elf_update(elf, ELF_C_WRITE); + + return 0; +} diff --git a/tests/run-dwelf-reloc-dbg-scn.sh b/tests/run-dwelf-reloc-dbg-scn.sh new file mode 100755 index 00000000..537a46f6 --- /dev/null +++ b/tests/run-dwelf-reloc-dbg-scn.sh @@ -0,0 +1,48 @@ +#! /usr/bin/env bash +# 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 + +testfiles testfile-dwelf-reloc-dbg-scn.o + +testrun_compare ${abs_builddir}/allfcts testfile-dwelf-reloc-dbg-scn.o <<\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 + +testrun ${abs_builddir}/dwelf_reloc_dbg_scn testfile-dwelf-reloc-dbg-scn.o + +testrun_compare ${abs_builddir}/allfcts testfile-dwelf-reloc-dbg-scn.o <<\EOF +/home/dichen/elfutils/tests/qq.c:6:main +/home/dichen/elfutils/tests/qq.c:1:add +EOF + +# = 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-dwelf-reloc-dbg-scn.o + +exit 0 diff --git a/tests/testfile-dwelf-reloc-dbg-scn.o.bz2 b/tests/testfile-dwelf-reloc-dbg-scn.o.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.45.2