Hi Di, Thanks for working on this.
On Tue, Sep 3, 2024 at 7:48 AM Di Chen <dic...@redhat.com> wrote: > > 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); libdwelf.h mentions the following re. naming: Functions starting with dwelf_elf will take a (libelf) Elf object as first argument and might set elf_errno on error. Functions starting with dwelf_dwarf will take a (libdw) Dwarf object as first argument and might set dwarf_errno on error. The new function takes an Elf object, its name should start with dwelf_elf. And since the original eu-strip function is called remove_debug_relocations I would name the new function dwelf_elf_remove_debug_relocations. > 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)) Since this is a library function we don't want to exit the program when there is an error. It's better to instead set elf_errno and return early. > + > +typedef uint8_t GElf_Byte; This typedef is unused. > +static int debug_fd = -1; > +static char *tmp_debug_fname = NULL; This was copied over from eu-strip. It's needed there because eu-strip writes to files, but this function only acts on an Elf object. It should not write to any files. > + > + > +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; > + } > +} cleanup_debug can be removed since this function doesn't need to clean up any files. > + > + > +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")); As with INTERNAL_ERROR, error_exit should be replaced with setting elf_errno and an early return. > + } > + > + /* 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); Asserts should be removed too. assert.h does not need to be included either. > + } > + } > + 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) Since we won't call INTERNAL_ERROR or manipulate any files, the fname parameter isn't needed. > +{ > + 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); This function should return something to communicate whether or not it was successful. I suggest using an int value where -1 means failure and 0 means success. Using an int instead of a bool lets us represent additional outcomes in the future (if needed) without breaking the API. > + > #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 This name should be changed to reflect the new function name. Also we'll need a copyright statement (which can be copied from another test file). > @@ -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> err.h, stdio.h and unistd.h aren't used. > + > +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 run-remove-debug-relocs.sh is a more suitable name. > @@ -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 This could use a brief comment explaining what's going on. Such as "Before debug relocations are removed some indices into string tables are set to a default of 0. This causes incorrect file and function names to be displayed." > + > +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