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

Reply via email to