Blob Blame History Raw
From 5598e24ef8aef14727ff72eea71ec460200bc2e3 Mon Sep 17 00:00:00 2001
From: Mark Wielaard <mark@klomp.org>
Date: Fri, 17 Mar 2017 21:03:35 +0100
Subject: [PATCH] debugedit: Fix cross-endian build-id reading and updating
 section data.

debugedit doesn't read raw mmap data any longer. Which made the complex
way to read the build-id unnecessary (and it was broken for cross-endian).
Just use gelf_getnote to read the notes.

Also in some special cases when only the debug_info or build_id data
was updated, but no section changed size and we had to preserve the
allocated section headers we could hit a bug in elfutils that could
trash some section data in case there were gaps between non-dirty and
dirty sections. See https://sourceware.org/bugzilla/show_bug.cgi?id=21199
Add a workaround for that issue.

This fixes the kompose package build on fedora ppc64.
And makes it possible to replicate that issue on x86_64.

Signed-off-by: Mark Wielaard <mark@klomp.org>
(cherry picked from commit a6e767600309bdb1f8af33b44563a1187fb0dbc4)
---
 tools/debugedit.c | 63 +++++++++++++++++++++++++++----------------------------
 1 file changed, 31 insertions(+), 32 deletions(-)

diff --git a/tools/debugedit.c b/tools/debugedit.c
index 87a423fdb..0f373162d 100644
--- a/tools/debugedit.c
+++ b/tools/debugedit.c
@@ -2581,40 +2581,25 @@ main (int argc, char *argv[])
 	  break;
 	case SHT_NOTE:
 	  if (do_build_id
-	      && build_id == NULL && (dso->shdr[i].sh_flags & SHF_ALLOC))
+	      && build_id == 0 && (dso->shdr[i].sh_flags & SHF_ALLOC))
 	    {
 	      /* Look for a build-ID note here.  */
+	      size_t off = 0;
+	      GElf_Nhdr nhdr;
+	      size_t name_off;
+	      size_t desc_off;
 	      Elf_Data *data = elf_getdata (elf_getscn (dso->elf, i), NULL);
-	      Elf32_Nhdr nh;
-	      Elf_Data dst =
-		{
-		  .d_version = EV_CURRENT, .d_type = ELF_T_NHDR,
-		  .d_buf = &nh, .d_size = sizeof nh
-		};
-	      Elf_Data src = dst;
-	      src.d_buf = data->d_buf;
-	      assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
-	      while ((char *) data->d_buf + data->d_size -
-		     (char *) src.d_buf > (int) sizeof nh
-		     && elf32_xlatetom (&dst, &src, dso->ehdr.e_ident[EI_DATA]))
-		{
-		  Elf32_Word len = sizeof nh + nh.n_namesz;
-		  len = (len + 3) & ~3;
-
-		  if (nh.n_namesz == sizeof "GNU" && nh.n_type == 3
-		      && !memcmp ((char *) src.d_buf + sizeof nh, "GNU", sizeof "GNU"))
-		    {
-		      build_id = data;
-		      build_id_offset = (char *) src.d_buf + len -
-					(char *) data->d_buf;
-		      build_id_size = nh.n_descsz;
-		      break;
-		    }
-
-		  len += nh.n_descsz;
-		  len = (len + 3) & ~3;
-		  src.d_buf = (char *) src.d_buf + len;
-		}
+	      while ((off = gelf_getnote (data, off,
+					  &nhdr, &name_off, &desc_off)) > 0)
+		if (nhdr.n_type == NT_GNU_BUILD_ID
+		    && nhdr.n_namesz == sizeof "GNU"
+		    && (memcmp ((char *)data->d_buf + name_off, "GNU",
+				sizeof "GNU") == 0))
+		  {
+		    build_id = data;
+		    build_id_offset = desc_off;
+		    build_id_size = nhdr.n_descsz;
+		  }
 	    }
 	  break;
 	default:
@@ -2622,6 +2607,20 @@ main (int argc, char *argv[])
 	}
     }
 
+  /* Normally we only need to explicitly update the section headers
+     and data when any section data changed size. But because of a bug
+     in elfutils before 0.169 we will have to update and write out all
+     section data if any data has changed (when ELF_F_LAYOUT was
+     set). https://sourceware.org/bugzilla/show_bug.cgi?id=21199 */
+  bool need_update = need_strp_update || need_stmt_update;
+
+#if !_ELFUTILS_PREREQ (0, 169)
+  /* string replacements or build_id updates don't change section size. */
+  need_update = (need_update
+		 || need_string_replacement
+		 || (do_build_id && build_id != NULL));
+#endif
+
   /* We might have changed the size of some debug sections. If so make
      sure the section headers are updated and the data offsets are
      correct. We set ELF_F_LAYOUT above because we don't want libelf
@@ -2631,7 +2630,7 @@ main (int argc, char *argv[])
      anything for the phdrs allocated sections. Keep the offset of
      allocated sections so they are at the same place in the file. Add
      unallocated ones after the allocated ones. */
-  if (dso->phnum != 0 && (need_strp_update || need_stmt_update))
+  if (dso->phnum != 0 && need_update)
     {
       Elf *elf = dso->elf;
       GElf_Off last_offset;