[PATCH] libdwelf: provide a public debug section relocation function
Aaron Merey
amerey@redhat.com
Tue Sep 10 15:10:21 GMT 2024
Hi Di,
Thanks for working on this.
On Tue, Sep 3, 2024 at 7:48 AM Di Chen <dichen@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 <dichen@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
More information about the Elfutils-devel
mailing list