[v2] libdwelf: add dwelf_elf_remove_debug_relocs

Message ID 20241018061057.1634905-1-amerey@redhat.com
State New
Headers
Series [v2] libdwelf: add dwelf_elf_remove_debug_relocs |

Commit Message

Aaron Merey Oct. 18, 2024, 6:10 a.m. UTC
  From: Di Chen <dichen@redhat.com>

Provide a public function for removing debug section relocations.

eu-strip previously contained the code to remove debug section
relocations.  This patch moves that code into
dwelf_elf_remove_debug_relocs.

https://sourceware.org/bugzilla/show_bug.cgi?id=31447

Signed-off-by: Di Chen <dichen@redhat.com>
Signed-off-by: Aaron Merey <amerey@redhat.com>
---

I'd like to be able to call __libelf_seterrno from 
dwelf_elf_remove_debug_relocations.c, but I keep getting the following
linker error:

> /usr/local/bin/ld: ../libdwelf/libdwelf_pic.a(dwelf_elf_remove_debug_relocations.os): in function `relocate':
> /home/amerey/elfutils/libdwelf/dwelf_elf_remove_debug_relocations.c:113:(.text+0x28e): undefined reference to `__libelf_seterrno'

I tried to modifying libdwelf/Makefile.am but wasn't able to solve this.
__libdw_seterrno works without this issue and I'm not sure what's
missing from the libelf linking.

I've left the calls to __libelf_seterrno commented out for now.

v1: https://sourceware.org/pipermail/elfutils-devel/2024q3/007388.html

v2 changes:
Renamed dwelf_relocation_debug_sections to
dwelf_elf_remove_debug_relocations. Renamed various files to match this
new function name.

Removed all asserts and error exits from
dwelf_elf_remove_debug_relocations.c

 libdw/libdw.map                               |   1 +
 libdwelf/Makefile.am                          |   5 +-
 libdwelf/dwelf_elf_remove_debug_relocations.c | 400 ++++++++++++++++++
 libdwelf/libdwelf.h                           |   4 +
 src/strip.c                                   | 354 +---------------
 tests/Makefile.am                             |   5 +-
 tests/remove-relocs.c                         |  38 ++
 tests/run-remove-relocs.sh                    |  54 +++
 tests/testfile-remove-relocs.bz2              | Bin 0 -> 1088 bytes
 9 files changed, 513 insertions(+), 348 deletions(-)
 create mode 100644 libdwelf/dwelf_elf_remove_debug_relocations.c
 create mode 100644 tests/remove-relocs.c
 create mode 100755 tests/run-remove-relocs.sh
 create mode 100644 tests/testfile-remove-relocs.bz2
  

Patch

diff --git a/libdw/libdw.map b/libdw/libdw.map
index bc53385f..b282e886 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -384,4 +384,5 @@  ELFUTILS_0.192 {
     dwfl_set_sysroot;
     dwfl_frame_unwound_source;
     dwfl_unwound_source_str;
+    dwelf_elf_remove_debug_relocations;
 } ELFUTILS_0.191;
diff --git a/libdwelf/Makefile.am b/libdwelf/Makefile.am
index a35a2873..6090fd64 100644
--- a/libdwelf/Makefile.am
+++ b/libdwelf/Makefile.am
@@ -42,13 +42,14 @@  noinst_HEADERS = libdwelfP.h
 libdwelf_a_SOURCES = dwelf_elf_gnu_debuglink.c dwelf_dwarf_gnu_debugaltlink.c \
 		     dwelf_elf_gnu_build_id.c dwelf_scn_gnu_compressed_size.c \
 		     dwelf_strtab.c dwelf_elf_begin.c \
-		     dwelf_elf_e_machine_string.c
+		     dwelf_elf_e_machine_string.c \
+		     dwelf_elf_remove_debug_relocations.c
 
 libdwelf = $(libdw)
 
 libdw = ../libdw/libdw.so
 libelf = ../libelf/libelf.so
-libebl = ../libebl/libebl.a
+libebl = ../libebl/libebl.a ../backends/libebl_backends.a
 libeu = ../lib/libeu.a
 
 libdwelf_pic_a_SOURCES =
diff --git a/libdwelf/dwelf_elf_remove_debug_relocations.c b/libdwelf/dwelf_elf_remove_debug_relocations.c
new file mode 100644
index 00000000..cbb25fb4
--- /dev/null
+++ b/libdwelf/dwelf_elf_remove_debug_relocations.c
@@ -0,0 +1,400 @@ 
+/* Remove relocations from debug sections.
+   Copyright (C) 2014 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwelfP.h"
+#include "libelfP.h"
+#include "libebl.h"
+
+typedef uint8_t GElf_Byte;
+
+const char *
+secndx_name (Elf *elf, size_t ndx)
+{
+  size_t shstrndx;
+  GElf_Shdr mem;
+  Elf_Scn *sec = elf_getscn (elf, ndx);
+  GElf_Shdr *shdr = gelf_getshdr (sec, &mem);
+  if (shdr == NULL || elf_getshdrstrndx (elf, &shstrndx) < 0)
+    return "???";
+  return elf_strptr (elf, shstrndx, shdr->sh_name) ?: "???";
+}
+
+
+Elf_Data *
+get_xndxdata (Elf *elf, Elf_Scn *symscn)
+{
+  Elf_Data *xndxdata = NULL;
+  GElf_Shdr shdr_mem;
+  GElf_Shdr *shdr = gelf_getshdr (symscn, &shdr_mem);
+  if (shdr != NULL && shdr->sh_type == SHT_SYMTAB)
+    {
+      size_t scnndx = elf_ndxscn (symscn);
+      Elf_Scn *xndxscn = NULL;
+      while ((xndxscn = elf_nextscn (elf, xndxscn)) != NULL)
+	{
+	  GElf_Shdr xndxshdr_mem;
+	  GElf_Shdr *xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
+
+	  if (xndxshdr != NULL
+	      && xndxshdr->sh_type == SHT_SYMTAB_SHNDX
+	      && xndxshdr->sh_link == scnndx)
+	    {
+	      xndxdata = elf_getdata (xndxscn, NULL);
+	      break;
+	    }
+	}
+    }
+
+  return xndxdata;
+}
+
+
+bool
+relocate (Elf *elf, GElf_Addr offset, const GElf_Sxword addend,
+	  Elf_Data *tdata, unsigned int ei_data, bool is_rela,
+	  GElf_Sym *sym, int addsub, Elf_Type type)
+{
+  /* These are the types we can relocate.  */
+#define TYPES   DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half);		\
+      DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword);		\
+      DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
+
+  size_t size;
+
+#define DO_TYPE(NAME, Name) GElf_##Name Name;
+  union { TYPES; } tmpbuf;
+#undef DO_TYPE
+
+  switch (type)
+    {
+#define DO_TYPE(NAME, Name)				\
+      case ELF_T_##NAME:			\
+	size = sizeof (GElf_##Name);	\
+	tmpbuf.Name = 0;			\
+	break;
+      TYPES;
+#undef DO_TYPE
+    default:
+      return false;
+    }
+
+  if (offset > tdata->d_size
+      || tdata->d_size - offset < size)
+    {
+      //__libelf_seterrno (ELF_E_INVALID_OFFSET);
+      return false;
+    }
+
+  /* When the symbol value is zero then for SHT_REL
+     sections this is all that needs to be checked.
+     The addend is contained in the original data at
+     the offset already.  So if the (section) symbol
+     address is zero and the given addend is zero
+     just remove the relocation, it isn't needed
+     anymore.  */
+  if (addend == 0 && sym->st_value == 0)
+    return true;
+
+  Elf_Data tmpdata =
+    {
+      .d_type = type,
+      .d_buf = &tmpbuf,
+      .d_size = size,
+      .d_version = EV_CURRENT,
+    };
+  Elf_Data rdata =
+    {
+      .d_type = type,
+      .d_buf = tdata->d_buf + offset,
+      .d_size = size,
+      .d_version = EV_CURRENT,
+    };
+
+  GElf_Addr value = sym->st_value;
+  if (is_rela)
+    {
+      /* For SHT_RELA sections we just take the
+	 given addend and add it to the value.  */
+      value += addend;
+      /* For ADD/SUB relocations we need to fetch the
+	 current section contents.  */
+      if (addsub != 0)
+	{
+	  Elf_Data *d = gelf_xlatetom (elf, &tmpdata,
+				       &rdata,
+				       ei_data);
+	  if (d == NULL || d != &tmpdata)
+	    {
+	      //__libelf_seterrno (ELF_E_INVALID_HANDLE);
+	      return false;
+	    }
+	}
+    }
+  else
+    {
+      /* For SHT_REL sections we have to peek at
+	 what is already in the section at the given
+	 offset to get the addend.  */
+      Elf_Data *d = gelf_xlatetom (elf, &tmpdata,
+				   &rdata,
+				   ei_data);
+      if (d == NULL || d != &tmpdata)
+	{
+	  //__libelf_seterrno (ELF_E_INVALID_HANDLE);
+	  return false;
+	}
+    }
+
+  switch (type)
+    {
+#define DO_TYPE(NAME, Name)					 \
+      case ELF_T_##NAME:				 \
+	if (addsub < 0)				 \
+	  tmpbuf.Name -= (GElf_##Name) value;	 \
+	else					 \
+	  tmpbuf.Name += (GElf_##Name) value;	 \
+	break;
+      TYPES;
+#undef DO_TYPE
+    default:
+      //__libelf_seterrno (ELF_E_UNKNOWN_TYPE);
+      return false;
+    }
+
+  /* Now finally put in the new value.  */
+  Elf_Data *s = gelf_xlatetof (elf, &rdata,
+			       &tmpdata,
+			       ei_data);
+  if (s == NULL || s != &rdata)
+    {
+      //__libelf_seterrno (ELF_E_INVALID_HANDLE);
+      return false;
+    }
+
+  return true;
+}
+
+
+int dwelf_elf_remove_debug_relocations (Elf *elf)
+{
+  size_t shstrndx;
+  if (elf_getshdrstrndx (elf, &shstrndx) < 0)
+    return -1;
+
+  GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
+  if (ehdr == NULL)
+    return -1;
+
+  const unsigned int ei_data = ehdr->e_ident[EI_DATA];
+
+  Ebl *ebl = ebl_openbackend (elf);
+  if (ebl == NULL)
+    return -1;
+
+  int res = -1;
+  Elf_Scn *scn = NULL;
+  while ((scn = elf_nextscn (elf, scn)) != NULL)
+  {
+    /* We need the actual section and header from the elf
+	not just the cached original in shdr_info because we
+	might want to change the size.  */
+	GElf_Shdr shdr_mem;
+	GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+
+    if (shdr != NULL
+	&& (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
+      {
+	/* Make sure that this relocation section points to a
+	   section to relocate with contents, that isn't
+	   allocated and that is a debug section.  */
+	Elf_Scn *tscn = elf_getscn (elf, shdr->sh_info);
+	GElf_Shdr tshdr_mem;
+	GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
+	if (tshdr == NULL
+	    || tshdr->sh_type == SHT_NOBITS
+	    || tshdr->sh_size == 0
+	    || (tshdr->sh_flags & SHF_ALLOC) != 0)
+	  continue;
+
+	const char *tname =  elf_strptr (elf, shstrndx,
+					 tshdr->sh_name);
+	if (! tname || ! ebl_debugscn_p (ebl, tname))
+	  continue;
+
+	/* OK, lets relocate all trivial cross debug section
+	   relocations. */
+	Elf_Data *reldata = elf_getdata (scn, NULL);
+	if (reldata == NULL || reldata->d_buf == NULL)
+	  goto exit;
+
+	/* Make sure we adjust the uncompressed debug data
+	   (and recompress if necessary at the end).  */
+	GElf_Chdr tchdr;
+	int tcompress_type = 0;
+	bool is_gnu_compressed = false;
+	if (startswith (tname, ".zdebug"))
+	  {
+	    is_gnu_compressed = true;
+	    if (elf_compress_gnu (tscn, 0, 0) != 1)
+	      goto exit;
+	  }
+	else
+	  {
+	    if (gelf_getchdr (tscn, &tchdr) != NULL)
+	      {
+		tcompress_type = tchdr.ch_type;
+		if (elf_compress (tscn, 0, 0) != 1)
+		  goto exit;
+	      }
+	  }
+
+	Elf_Data *tdata = elf_getdata (tscn, NULL);
+	if (tdata == NULL || tdata->d_buf == NULL
+	    || tdata->d_type != ELF_T_BYTE)
+	  goto exit;
+
+	/* Pick up the symbol table and shndx table to
+	   resolve relocation symbol indexes.  */
+	Elf64_Word symt = shdr->sh_link;
+	Elf_Data *symdata, *xndxdata;
+	Elf_Scn * symscn = elf_getscn (elf, symt);
+	symdata = elf_getdata (symscn, NULL);
+	xndxdata = get_xndxdata (elf, symscn);
+	if (symdata == NULL)
+	  goto exit;
+
+	if (shdr->sh_entsize == 0)
+	  goto exit;
+
+	size_t nrels = shdr->sh_size / shdr->sh_entsize;
+	size_t next = 0;
+	const bool is_rela = (shdr->sh_type == SHT_RELA);
+
+	for (size_t relidx = 0; relidx < nrels; ++relidx)
+	  {
+	    int rtype, symndx, offset, addend;
+	    union { GElf_Rela rela; GElf_Rel rel; } mem;
+	    void *rel_p; /* Pointer to either rela or rel above */
+
+	    if (is_rela)
+	      {
+		GElf_Rela *r = gelf_getrela (reldata, relidx, &mem.rela);
+		if (r == NULL)
+		  goto exit;
+		offset = r->r_offset;
+		addend = r->r_addend;
+		rtype = GELF_R_TYPE (r->r_info);
+		symndx = GELF_R_SYM (r->r_info);
+		rel_p = r;
+	      }
+	    else
+	      {
+		GElf_Rel *r = gelf_getrel (reldata, relidx, &mem.rel);
+		if (r == NULL)
+		  goto exit;
+		offset = r->r_offset;
+		addend = 0;
+		rtype = GELF_R_TYPE (r->r_info);
+		symndx = GELF_R_SYM (r->r_info);
+		rel_p = r;
+	      }
+
+	    /* R_*_NONE relocs can always just be removed.  */
+	    if (rtype == 0)
+	      continue;
+
+	    /* We only do simple absolute relocations.  */
+	    int addsub = 0;
+	    Elf_Type type = ebl_reloc_simple_type (ebl, rtype, &addsub);
+	    if (type == ELF_T_NUM)
+	      goto relocate_failed;
+
+	    /* And only for relocations against other debug sections.  */
+	    GElf_Sym sym_mem;
+	    Elf32_Word xndx;
+	    GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
+					      symndx, &sym_mem,
+					      &xndx);
+	    if (sym == NULL)
+	      goto exit;
+	    Elf32_Word sec = (sym->st_shndx == SHN_XINDEX
+				? xndx : sym->st_shndx);
+
+	    bool dbg_scn = ebl_debugscn_p (ebl, secndx_name (elf, sec));
+
+	    if (!dbg_scn)
+	      goto relocate_failed;
+
+	    if (! relocate (elf, offset, addend, tdata, ei_data, is_rela,
+			    sym, addsub, type))
+	    goto relocate_failed;
+
+	    continue; /* Next */
+
+relocate_failed:
+	    if (relidx != next)
+	      {
+		int updated;
+		if (is_rela)
+		  updated = gelf_update_rela (reldata, next, rel_p);
+		else
+		  updated = gelf_update_rel (reldata, next, rel_p);
+		if (updated == 0)
+		  goto exit;
+	      }
+	    ++next;
+	  }
+
+	nrels = next;
+	shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize;
+	if (gelf_update_shdr (scn, shdr) == 0)
+	  goto exit;
+
+	if (is_gnu_compressed)
+	  {
+	    if (elf_compress_gnu (tscn, 1, ELF_CHF_FORCE) != 1)
+	      goto exit;
+	  }
+	else if (tcompress_type != 0)
+	  {
+	    if (elf_compress (tscn, tcompress_type, ELF_CHF_FORCE) != 1)
+	      goto exit;
+	  }
+      }
+  }
+
+  res = 0;
+
+exit:
+  ebl_closebackend (ebl);
+  return res;
+}
diff --git a/libdwelf/libdwelf.h b/libdwelf/libdwelf.h
index 263ca60e..734aa9c3 100644
--- a/libdwelf/libdwelf.h
+++ b/libdwelf/libdwelf.h
@@ -140,6 +140,10 @@  extern Elf *dwelf_elf_begin (int fd);
    value, or NULL if the given number isn't currently known.  */
 extern const char *dwelf_elf_e_machine_string (int machine);
 
+/* Remove relocations for debug sections.  Returns 0 on success.
+   Returns -1 on failure and sets elf_errno.  */
+extern int dwelf_elf_remove_debug_relocations (Elf *elf);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/strip.c b/src/strip.c
index 403e0f6f..a431ebbe 100644
--- a/src/strip.c
+++ b/src/strip.c
@@ -367,46 +367,6 @@  parse_opt (int key, char *arg, struct argp_state *state)
   return 0;
 }
 
-static const char *
-secndx_name (Elf *elf, size_t ndx)
-{
-  size_t shstrndx;
-  GElf_Shdr mem;
-  Elf_Scn *sec = elf_getscn (elf, ndx);
-  GElf_Shdr *shdr = gelf_getshdr (sec, &mem);
-  if (shdr == NULL || elf_getshdrstrndx (elf, &shstrndx) < 0)
-    return "???";
-  return elf_strptr (elf, shstrndx, shdr->sh_name) ?: "???";
-}
-
-/* Get the extended section index table data for a symbol table section.  */
-static Elf_Data *
-get_xndxdata (Elf *elf, Elf_Scn *symscn)
-{
-  Elf_Data *xndxdata = NULL;
-  GElf_Shdr shdr_mem;
-  GElf_Shdr *shdr = gelf_getshdr (symscn, &shdr_mem);
-  if (shdr != NULL && shdr->sh_type == SHT_SYMTAB)
-    {
-      size_t scnndx = elf_ndxscn (symscn);
-      Elf_Scn *xndxscn = NULL;
-      while ((xndxscn = elf_nextscn (elf, xndxscn)) != NULL)
-	{
-	  GElf_Shdr xndxshdr_mem;
-	  GElf_Shdr *xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
-
-	  if (xndxshdr != NULL
-	      && xndxshdr->sh_type == SHT_SYMTAB_SHNDX
-	      && xndxshdr->sh_link == scnndx)
-	    {
-	      xndxdata = elf_getdata (xndxscn, NULL);
-	      break;
-	    }
-	}
-    }
-
-  return xndxdata;
-}
 
 /* Updates the shdrstrndx for the given Elf by updating the Ehdr and
    possibly the section zero extension field.  Returns zero on success.  */
@@ -440,306 +400,6 @@  update_shdrstrndx (Elf *elf, size_t shdrstrndx)
 }
 
 
-/* Apply one relocation.  Returns true when trivial
-   relocation actually done.  */
-static bool
-relocate (Elf *elf, GElf_Addr offset, const GElf_Sxword addend,
-	  Elf_Data *tdata, unsigned int ei_data, const char *fname,
-	  bool is_rela, GElf_Sym *sym, int addsub, Elf_Type type)
-{
-  /* These are the types we can relocate.  */
-#define TYPES   DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half);		\
-      DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword);		\
-      DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
-
-  size_t size;
-
-#define DO_TYPE(NAME, Name) GElf_##Name Name;
-  union { TYPES; } tmpbuf;
-#undef DO_TYPE
-
-  switch (type)
-    {
-#define DO_TYPE(NAME, Name)				\
-      case ELF_T_##NAME:			\
-	size = sizeof (GElf_##Name);	\
-	tmpbuf.Name = 0;			\
-	break;
-      TYPES;
-#undef DO_TYPE
-    default:
-      return false;
-    }
-
-  if (offset > tdata->d_size
-      || tdata->d_size - offset < size)
-    {
-      cleanup_debug ();
-      error_exit (0, _("bad relocation"));
-    }
-
-  /* When the symbol value is zero then for SHT_REL
-     sections this is all that needs to be checked.
-     The addend is contained in the original data at
-     the offset already.  So if the (section) symbol
-     address is zero and the given addend is zero
-     just remove the relocation, it isn't needed
-     anymore.  */
-  if (addend == 0 && sym->st_value == 0)
-    return true;
-
-  Elf_Data tmpdata =
-    {
-      .d_type = type,
-      .d_buf = &tmpbuf,
-      .d_size = size,
-      .d_version = EV_CURRENT,
-    };
-  Elf_Data rdata =
-    {
-      .d_type = type,
-      .d_buf = tdata->d_buf + offset,
-      .d_size = size,
-      .d_version = EV_CURRENT,
-    };
-
-  GElf_Addr value = sym->st_value;
-  if (is_rela)
-    {
-      /* For SHT_RELA sections we just take the
-	 given addend and add it to the value.  */
-      value += addend;
-      /* For ADD/SUB relocations we need to fetch the
-	 current section contents.  */
-      if (addsub != 0)
-	{
-	  Elf_Data *d = gelf_xlatetom (elf, &tmpdata,
-				       &rdata,
-				       ei_data);
-	  if (d == NULL)
-	    INTERNAL_ERROR (fname);
-	  assert (d == &tmpdata);
-	}
-    }
-  else
-    {
-      /* For SHT_REL sections we have to peek at
-	 what is already in the section at the given
-	 offset to get the addend.  */
-      Elf_Data *d = gelf_xlatetom (elf, &tmpdata,
-				   &rdata,
-				   ei_data);
-      if (d == NULL)
-	INTERNAL_ERROR (fname);
-      assert (d == &tmpdata);
-    }
-
-  switch (type)
-    {
-#define DO_TYPE(NAME, Name)					 \
-      case ELF_T_##NAME:				 \
-	if (addsub < 0)				 \
-	  tmpbuf.Name -= (GElf_##Name) value;	 \
-	else					 \
-	  tmpbuf.Name += (GElf_##Name) value;	 \
-	break;
-      TYPES;
-#undef DO_TYPE
-    default:
-      abort ();
-    }
-
-  /* Now finally put in the new value.  */
-  Elf_Data *s = gelf_xlatetof (elf, &rdata,
-			       &tmpdata,
-			       ei_data);
-  if (s == NULL)
-    INTERNAL_ERROR (fname);
-  assert (s == &rdata);
-
-  return true;
-}
-
-/* Remove any relocations between debug sections in ET_REL
-   for the debug file when requested.  These relocations are always
-   zero based between the unallocated sections.  */
-static void
-remove_debug_relocations (Ebl *ebl, Elf *elf, GElf_Ehdr *ehdr,
-			  const char *fname, size_t shstrndx)
-{
-  Elf_Scn *scn = NULL;
-  while ((scn = elf_nextscn (elf, scn)) != NULL)
-    {
-      /* We need the actual section and header from the elf
-	 not just the cached original in shdr_info because we
-	 might want to change the size.  */
-      GElf_Shdr shdr_mem;
-      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
-      if (shdr != NULL
-	  && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
-	{
-	  /* Make sure that this relocation section points to a
-	     section to relocate with contents, that isn't
-	     allocated and that is a debug section.  */
-	  Elf_Scn *tscn = elf_getscn (elf, shdr->sh_info);
-	  GElf_Shdr tshdr_mem;
-	  GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
-	  if (tshdr == NULL
-	      || tshdr->sh_type == SHT_NOBITS
-	      || tshdr->sh_size == 0
-	      || (tshdr->sh_flags & SHF_ALLOC) != 0)
-	    continue;
-
-	  const char *tname =  elf_strptr (elf, shstrndx,
-					   tshdr->sh_name);
-	  if (! tname || ! ebl_debugscn_p (ebl, tname))
-	    continue;
-
-	  /* OK, lets relocate all trivial cross debug section
-	     relocations. */
-	  Elf_Data *reldata = elf_getdata (scn, NULL);
-	  if (reldata == NULL || reldata->d_buf == NULL)
-	    INTERNAL_ERROR (fname);
-
-	  /* Make sure we adjust the uncompressed debug data
-	     (and recompress if necessary at the end).  */
-	  GElf_Chdr tchdr;
-	  int tcompress_type = 0;
-	  bool is_gnu_compressed = false;
-	  if (startswith (tname, ".zdebug"))
-	    {
-	      is_gnu_compressed = true;
-	      if (elf_compress_gnu (tscn, 0, 0) != 1)
-		INTERNAL_ERROR (fname);
-	    }
-	  else
-	    {
-	      if (gelf_getchdr (tscn, &tchdr) != NULL)
-		{
-		  tcompress_type = tchdr.ch_type;
-		  if (elf_compress (tscn, 0, 0) != 1)
-		    INTERNAL_ERROR (fname);
-		}
-	    }
-
-	  Elf_Data *tdata = elf_getdata (tscn, NULL);
-	  if (tdata == NULL || tdata->d_buf == NULL
-	      || tdata->d_type != ELF_T_BYTE)
-	    INTERNAL_ERROR (fname);
-
-	  /* Pick up the symbol table and shndx table to
-	     resolve relocation symbol indexes.  */
-	  Elf64_Word symt = shdr->sh_link;
-	  Elf_Data *symdata, *xndxdata;
-	  Elf_Scn * symscn = elf_getscn (elf, symt);
-	  symdata = elf_getdata (symscn, NULL);
-	  xndxdata = get_xndxdata (elf, symscn);
-	  if (symdata == NULL)
-	    INTERNAL_ERROR (fname);
-
-	  if (shdr->sh_entsize == 0)
-	    INTERNAL_ERROR (fname);
-
-	  size_t nrels = shdr->sh_size / shdr->sh_entsize;
-	  size_t next = 0;
-	  const bool is_rela = (shdr->sh_type == SHT_RELA);
-	  const unsigned int ei_data = ehdr->e_ident[EI_DATA];
-
-	  for (size_t relidx = 0; relidx < nrels; ++relidx)
-	    {
-	      int rtype, symndx, offset, addend;
-	      union { GElf_Rela rela; GElf_Rel rel; } mem;
-	      void *rel_p; /* Pointer to either rela or rel above */
-
-	      if (is_rela)
-		{
-		  GElf_Rela *r = gelf_getrela (reldata, relidx, &mem.rela);
-		  if (r == NULL)
-		    INTERNAL_ERROR (fname);
-		  offset = r->r_offset;
-		  addend = r->r_addend;
-		  rtype = GELF_R_TYPE (r->r_info);
-		  symndx = GELF_R_SYM (r->r_info);
-		  rel_p = r;
-		}
-	      else
-		{
-		  GElf_Rel *r = gelf_getrel (reldata, relidx, &mem.rel);
-		  if (r == NULL)
-		    INTERNAL_ERROR (fname);
-		  offset = r->r_offset;
-		  addend = 0;
-		  rtype = GELF_R_TYPE (r->r_info);
-		  symndx = GELF_R_SYM (r->r_info);
-		  rel_p = r;
-		}
-
-	      /* R_*_NONE relocs can always just be removed.  */
-	      if (rtype == 0)
-		continue;
-
-	      /* We only do simple absolute relocations.  */
-	      int addsub = 0;
-	      Elf_Type type = ebl_reloc_simple_type (ebl, rtype, &addsub);
-	      if (type == ELF_T_NUM)
-		goto relocate_failed;
-
-	      /* And only for relocations against other debug sections.  */
-	      GElf_Sym sym_mem;
-	      Elf32_Word xndx;
-	      GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
-						symndx, &sym_mem,
-						  &xndx);
-	      if (sym == NULL)
-		INTERNAL_ERROR (fname);
-	      Elf32_Word sec = (sym->st_shndx == SHN_XINDEX
-				? xndx : sym->st_shndx);
-
-	      bool dbg_scn = ebl_debugscn_p (ebl, secndx_name (elf, sec));
-
-	      if (!dbg_scn)
-		goto relocate_failed;
-
-	      if (! relocate (elf, offset, addend,
-			    tdata, ei_data, fname, is_rela,
-			    sym, addsub, type))
-	      goto relocate_failed;
-
-	      continue; /* Next */
-
-relocate_failed:
-	      if (relidx != next)
-		{
-		  int updated;
-		  if (is_rela)
-		    updated = gelf_update_rela (reldata, next, rel_p);
-		  else
-		    updated = gelf_update_rel (reldata, next, rel_p);
-		  if (updated == 0)
-		    INTERNAL_ERROR (fname);
-		}
-	      ++next;
-	    }
-
-	  nrels = next;
-	  shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize;
-	  if (gelf_update_shdr (scn, shdr) == 0)
-	    INTERNAL_ERROR (fname);
-
-	  if (is_gnu_compressed)
-	    {
-	      if (elf_compress_gnu (tscn, 1, ELF_CHF_FORCE) != 1)
-		INTERNAL_ERROR (fname);
-	    }
-	  else if (tcompress_type != 0)
-	    {
-	      if (elf_compress (tscn, tcompress_type, ELF_CHF_FORCE) != 1)
-		INTERNAL_ERROR (fname);
-	    }
-	}
-    }
-}
-
 static int
 process_file (const char *fname)
 {
@@ -839,7 +499,7 @@  process_file (const char *fname)
 
 /* Processing for --reloc-debug-sections-only.  */
 static int
-handle_debug_relocs (Elf *elf, Ebl *ebl, Elf *new_elf,
+handle_debug_relocs (Elf *elf, Elf *new_elf,
 		     GElf_Ehdr *ehdr, const char *fname, size_t shstrndx,
 		     GElf_Off *last_offset, GElf_Xword *last_size)
 {
@@ -910,8 +570,9 @@  handle_debug_relocs (Elf *elf, Ebl *ebl, Elf *new_elf,
       return 1;
     }
 
-  /* Adjust the relocation sections.  */
-  remove_debug_relocations (ebl, new_elf, ehdr, fname, shstrndx);
+  /* Remove debug section relocations.  */
+  if (dwelf_elf_remove_debug_relocations (new_elf) == -1)
+    INTERNAL_ERROR (fname);
 
   /* Adjust the offsets of the non-allocated sections, so they come after
      the allocated sections.  */
@@ -1139,7 +800,7 @@  handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 
   if (reloc_debug_only)
     {
-      if (handle_debug_relocs (elf, ebl, newelf, ehdr, fname, shstrndx,
+      if (handle_debug_relocs (elf, newelf, ehdr, fname, shstrndx,
 			       &lastsec_offset, &lastsec_size) != 0)
 	{
 	  result = 1;
@@ -2457,7 +2118,10 @@  handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
      zero based between the unallocated sections.  */
   if (debug_fname != NULL && removing_sections
       && reloc_debug && ehdr->e_type == ET_REL)
-    remove_debug_relocations (ebl, debugelf, ehdr, fname, shstrndx);
+    {
+      if (dwelf_elf_remove_debug_relocations (debugelf) == -1)
+	INTERNAL_ERROR (fname);
+    }
 
   /* Now that we have done all adjustments to the data,
      we can actually write out the debug file.  */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index ffccb0cd..a3c4a745 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -59,7 +59,7 @@  check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
 		  get-units-invalid get-units-split attr-integrate-skel \
 		  all-dwarf-ranges unit-info next_cfi \
 		  elfcopy addsections xlate_notes elfrdwrnop \
-		  dwelf_elf_e_machine_string \
+		  dwelf_elf_e_machine_string remove-relocs \
 		  getphdrnum leb128 read_unaligned \
 		  msg_tst system-elf-libelf-test system-elf-gelf-test \
 		  nvidia_extended_linemap_libdw elf-print-reloc-syms \
@@ -204,6 +204,7 @@  TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \
 	run-strip-version.sh run-xlate-note.sh \
 	run-readelf-discr.sh \
 	run-dwelf_elf_e_machine_string.sh \
+	run-remove-relocs.sh \
 	run-elfclassify.sh run-elfclassify-self.sh \
 	run-disasm-riscv64.sh \
 	run-pt_gnu_prop-tests.sh \
@@ -576,6 +577,7 @@  EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
 	     run-readelf-discr.sh \
 	     testfile-rng.debug.bz2 testfile-urng.debug.bz2 \
 	     run-dwelf_elf_e_machine_string.sh \
+	     run-remove-relocs.sh testfile-remove-relocs.bz2 \
 	     run-elfclassify.sh run-elfclassify-self.sh \
 	     run-disasm-riscv64.sh \
 	     testfile-riscv64-dis1.o.bz2 testfile-riscv64-dis1.expect.bz2 \
@@ -856,6 +858,7 @@  debuginfod_build_id_find_LDADD = $(libelf) $(libdw)
 xlate_notes_LDADD = $(libelf)
 elfrdwrnop_LDADD = $(libelf)
 dwelf_elf_e_machine_string_LDADD = $(libelf) $(libdw)
+remove_relocs_LDADD = $(libelf) $(libdw)
 getphdrnum_LDADD = $(libelf) $(libdw)
 leb128_LDADD = $(libelf) $(libdw)
 read_unaligned_LDADD = $(libelf) $(libdw)
diff --git a/tests/remove-relocs.c b/tests/remove-relocs.c
new file mode 100644
index 00000000..9a678f59
--- /dev/null
+++ b/tests/remove-relocs.c
@@ -0,0 +1,38 @@ 
+/* Test program for dwelf_elf_remove_debug_relocs
+   Copyright (C) 2024 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <fcntl.h>
+#include ELFUTILS_HEADER(dw)
+#include ELFUTILS_HEADER(dwelf)
+
+int main(int argc __attribute__ ((unused)), char **argv) {
+  Elf *elf;
+  elf_version (EV_CURRENT);
+  int fd = open (argv[1], O_RDWR);
+
+  elf = elf_begin (fd, ELF_C_RDWR, NULL);
+
+  dwelf_elf_remove_debug_relocations (elf);
+  elf_update (elf, ELF_C_WRITE);
+
+  elf_end (elf);
+  return 0;
+}
diff --git a/tests/run-remove-relocs.sh b/tests/run-remove-relocs.sh
new file mode 100755
index 00000000..3a49a5ab
--- /dev/null
+++ b/tests/run-remove-relocs.sh
@@ -0,0 +1,54 @@ 
+#! /usr/bin/env bash
+# Test dwelf_elf_remove_debug_relocations
+# Copyright (C) 2024 Red Hat, Inc.
+# This file is part of elfutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# elfutils is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. $srcdir/test-subr.sh
+
+# = qq.c =
+# int add (int a, int b)
+# {
+#   return a+b;
+# }
+#
+# int main()
+# {
+#   return 0;
+# }
+
+# Using gcc (GCC) 14.2.1 20240801 (Red Hat 14.2.1-1)
+# gcc -g -c qq.c -o testfile-remove-relocs
+
+testfiles testfile-remove-relocs
+
+# Before debug relocations are removed some indices into string tables are
+# set to a default value of 0.  This causes incorrect file and function
+# names to be displayed.
+testrun_compare ${abs_builddir}/allfcts testfile-remove-relocs <<\EOF
+qq.c/qq.c:6:GNU C17 14.2.1 20240801 (Red Hat 14.2.1-1) -mtune=generic -march=x86-64 -g
+qq.c/qq.c:1:add
+EOF
+
+# Remove debug relocations and write the changes to the testfile.
+testrun ${abs_builddir}/remove-relocs testfile-remove-relocs
+
+# Correct file and function names should now be displayed.
+testrun_compare ${abs_builddir}/allfcts testfile-remove-relocs <<\EOF
+/home/dichen/elfutils/tests/qq.c:6:main
+/home/dichen/elfutils/tests/qq.c:1:add
+EOF
+
+exit 0
diff --git a/tests/testfile-remove-relocs.bz2 b/tests/testfile-remove-relocs.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..2f7ca9b63adb5afc4e7b454c2531f328041de010
GIT binary patch
literal 1088
zcmV-G1i$-2T4*^jL0KkKS)er3J^%yRfB*mg|Ni#(_5b_r(_;Vc|9gvQWE8{z0K`cE
zL_h*SU`)^hde?`qYcFQ@bAv@sQ&Ue-r>W{R^)pjVs2MQ;dTIaw01W|=pa1{>01W^&
zPfB_a%6e%(RMF`@G(Z3V02%-QXaE2J0ib9A05vd(6*r|D)X>l-(V*1Yn3`d!ko5*Y
z1`q*>gu-ahVh=<E)L=46O#{>hgHKQZX`sOxGynhwMu5;^0B8n)00070Q8Xq%Ddieu
z&@|8h^#e^b4F-ly02%;jXf$Zh8hU{B4^RmDELD`%=HnQFAq_A<j3g?~{TX(abYl{y
zO1yNEP?>*eHhohwHb?H%Q<GBlQVcCwZG(34Ly~gTMjxcY0w>?Jj5JcDh-nnrqZ0yV
zp?K}+M)t}&0TYBpCP4s>M`X-{9QKu}rm8^2{8G<rmvHntQK<$=uMS6i4`?@B-P_J<
z%m!V7IR&vcZUI6DR_)ea<^VH83TxYzrje;jiJ{to6lub^sHS+$i&s%SY>a9WfHFg1
z%;3?B4tGyKDx*gDKoITZ&l#gxiGagE0gi!*lLY8tvr_{Eh+xb?RW?#K>6!S>Hd-eY
zQF{5F4VH#rf@T<?h7U>{fCstIN<a=`5<-yfAS6g2&9~iHnZ%LgUyV;z;g8HZ7c4Bf
z6+13wG88W}oqsN~g*I*74l7Z<Xx#H=k_-p4KoS<UF}-<gg#_Y22#AQ8MV!P`q$WA9
zes-3rNEqL7i(ls}{fU_12fV0In@H)@l&M67dV~Z}Z>WYCAw-%-swAQUOoJIk)esR%
zCJPzH23@a#<pRjM1&>oMT86mdtp1}Z5NdFSDY9*X0TDQ5V3Fdk<T=hvnT!<l_G5=h
z%-*yfQ^-(!LIQ#VQ*WgDK6iW1?t!0L8u2hnt`Wc`UC17D1D^odErw%u#uEsk(jZ~o
zny^7bvOi*&jG>ri;1Lt4OhI(Qj!q8Sh~h>FOk`gNj!!JRhh&3AoRYz1W~`%uZbp(j
z`(a=?vs?t-7D9WEx*D>ns)3S3WRU}!zs#gkDn)mEW1m45Leqi7Mw0L+D9ZR7S?`rB
ztJuvHH;@uvof^{^)#`vM17&EEEvlNnxSo7Nkuo7}BkPlc)_^q~`oeSqs;6gRG$Vkg
z-0Y}YDo>PhS|Rb12AXW=fMvL^DBUv1JMdvp-3NODpvW%Fh(5%mW8x6j$@g_f4kR1I
zM>t4XEXyu)<|I_1Udd|=Z1_|C;@CxF5}ksfWMDpR<BP5mOf(?`J>U%%`P2@<N|A|K
zKxa)zY%>9&F2mTMKM_fwv*4f+A45<Y5g0ZUQUgKK6$XD|OQeV;B!LV&m=rP2elX5G
zSf?Gd(`-4Rwhvs*S^eOy;ozPTHEBaYHTZ&o0T@m2<x)DJ)3?L0dxM|D#4hBDaG@bU
GX{dalrP>4l

literal 0
HcmV?d00001

-- 
2.46.2