Igor Gnatenko 082d5d
From 5598e24ef8aef14727ff72eea71ec460200bc2e3 Mon Sep 17 00:00:00 2001
Igor Gnatenko 082d5d
From: Mark Wielaard <mark@klomp.org>
Igor Gnatenko 082d5d
Date: Fri, 17 Mar 2017 21:03:35 +0100
Mark Wielaard 284dc3
Subject: [PATCH] debugedit: Fix cross-endian build-id reading and updating
Mark Wielaard 284dc3
 section data.
Igor Gnatenko 082d5d
Igor Gnatenko 082d5d
debugedit doesn't read raw mmap data any longer. Which made the complex
Igor Gnatenko 082d5d
way to read the build-id unnecessary (and it was broken for cross-endian).
Igor Gnatenko 082d5d
Just use gelf_getnote to read the notes.
Igor Gnatenko 082d5d
Igor Gnatenko 082d5d
Also in some special cases when only the debug_info or build_id data
Igor Gnatenko 082d5d
was updated, but no section changed size and we had to preserve the
Igor Gnatenko 082d5d
allocated section headers we could hit a bug in elfutils that could
Igor Gnatenko 082d5d
trash some section data in case there were gaps between non-dirty and
Igor Gnatenko 082d5d
dirty sections. See https://sourceware.org/bugzilla/show_bug.cgi?id=21199
Igor Gnatenko 082d5d
Add a workaround for that issue.
Igor Gnatenko 082d5d
Igor Gnatenko 082d5d
This fixes the kompose package build on fedora ppc64.
Igor Gnatenko 082d5d
And makes it possible to replicate that issue on x86_64.
Igor Gnatenko 082d5d
Igor Gnatenko 082d5d
Signed-off-by: Mark Wielaard <mark@klomp.org>
Igor Gnatenko 082d5d
(cherry picked from commit a6e767600309bdb1f8af33b44563a1187fb0dbc4)
Igor Gnatenko 082d5d
---
Igor Gnatenko 082d5d
 tools/debugedit.c | 63 +++++++++++++++++++++++++++----------------------------
Igor Gnatenko 082d5d
 1 file changed, 31 insertions(+), 32 deletions(-)
Igor Gnatenko 082d5d
Mark Wielaard c6952c
diff --git a/tools/debugedit.c b/tools/debugedit.c
Igor Gnatenko 082d5d
index 87a423fdb..0f373162d 100644
Mark Wielaard c6952c
--- a/tools/debugedit.c
Mark Wielaard c6952c
+++ b/tools/debugedit.c
Mark Wielaard c6952c
@@ -2581,40 +2581,25 @@ main (int argc, char *argv[])
Mark Wielaard c6952c
 	  break;
Mark Wielaard c6952c
 	case SHT_NOTE:
Mark Wielaard c6952c
 	  if (do_build_id
Mark Wielaard c6952c
-	      && build_id == NULL && (dso->shdr[i].sh_flags & SHF_ALLOC))
Mark Wielaard c6952c
+	      && build_id == 0 && (dso->shdr[i].sh_flags & SHF_ALLOC))
Mark Wielaard c6952c
 	    {
Mark Wielaard c6952c
 	      /* Look for a build-ID note here.  */
Mark Wielaard c6952c
+	      size_t off = 0;
Mark Wielaard c6952c
+	      GElf_Nhdr nhdr;
Mark Wielaard c6952c
+	      size_t name_off;
Mark Wielaard c6952c
+	      size_t desc_off;
Mark Wielaard c6952c
 	      Elf_Data *data = elf_getdata (elf_getscn (dso->elf, i), NULL);
Mark Wielaard c6952c
-	      Elf32_Nhdr nh;
Mark Wielaard c6952c
-	      Elf_Data dst =
Mark Wielaard c6952c
-		{
Mark Wielaard c6952c
-		  .d_version = EV_CURRENT, .d_type = ELF_T_NHDR,
Mark Wielaard c6952c
-		  .d_buf = &nh, .d_size = sizeof nh
Mark Wielaard c6952c
-		};
Mark Wielaard c6952c
-	      Elf_Data src = dst;
Mark Wielaard c6952c
-	      src.d_buf = data->d_buf;
Mark Wielaard c6952c
-	      assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
Mark Wielaard c6952c
-	      while ((char *) data->d_buf + data->d_size -
Mark Wielaard c6952c
-		     (char *) src.d_buf > (int) sizeof nh
Mark Wielaard c6952c
-		     && elf32_xlatetom (&dst, &src, dso->ehdr.e_ident[EI_DATA]))
Mark Wielaard c6952c
-		{
Mark Wielaard c6952c
-		  Elf32_Word len = sizeof nh + nh.n_namesz;
Mark Wielaard c6952c
-		  len = (len + 3) & ~3;
Mark Wielaard c6952c
-
Mark Wielaard c6952c
-		  if (nh.n_namesz == sizeof "GNU" && nh.n_type == 3
Mark Wielaard c6952c
-		      && !memcmp ((char *) src.d_buf + sizeof nh, "GNU", sizeof "GNU"))
Mark Wielaard c6952c
-		    {
Mark Wielaard c6952c
-		      build_id = data;
Mark Wielaard c6952c
-		      build_id_offset = (char *) src.d_buf + len -
Mark Wielaard c6952c
-					(char *) data->d_buf;
Mark Wielaard c6952c
-		      build_id_size = nh.n_descsz;
Mark Wielaard c6952c
-		      break;
Mark Wielaard c6952c
-		    }
Mark Wielaard c6952c
-
Mark Wielaard c6952c
-		  len += nh.n_descsz;
Mark Wielaard c6952c
-		  len = (len + 3) & ~3;
Mark Wielaard c6952c
-		  src.d_buf = (char *) src.d_buf + len;
Mark Wielaard c6952c
-		}
Mark Wielaard c6952c
+	      while ((off = gelf_getnote (data, off,
Mark Wielaard c6952c
+					  &nhdr, &name_off, &desc_off)) > 0)
Mark Wielaard c6952c
+		if (nhdr.n_type == NT_GNU_BUILD_ID
Mark Wielaard c6952c
+		    && nhdr.n_namesz == sizeof "GNU"
Mark Wielaard c6952c
+		    && (memcmp ((char *)data->d_buf + name_off, "GNU",
Mark Wielaard c6952c
+				sizeof "GNU") == 0))
Mark Wielaard c6952c
+		  {
Mark Wielaard c6952c
+		    build_id = data;
Mark Wielaard c6952c
+		    build_id_offset = desc_off;
Mark Wielaard c6952c
+		    build_id_size = nhdr.n_descsz;
Mark Wielaard c6952c
+		  }
Mark Wielaard c6952c
 	    }
Mark Wielaard c6952c
 	  break;
Mark Wielaard c6952c
 	default:
Mark Wielaard c6952c
@@ -2622,6 +2607,20 @@ main (int argc, char *argv[])
Mark Wielaard c6952c
 	}
Mark Wielaard c6952c
     }
Mark Wielaard c6952c
 
Mark Wielaard c6952c
+  /* Normally we only need to explicitly update the section headers
Mark Wielaard c6952c
+     and data when any section data changed size. But because of a bug
Mark Wielaard c6952c
+     in elfutils before 0.169 we will have to update and write out all
Mark Wielaard c6952c
+     section data if any data has changed (when ELF_F_LAYOUT was
Mark Wielaard c6952c
+     set). https://sourceware.org/bugzilla/show_bug.cgi?id=21199 */
Mark Wielaard c6952c
+  bool need_update = need_strp_update || need_stmt_update;
Mark Wielaard c6952c
+
Mark Wielaard c6952c
+#if !_ELFUTILS_PREREQ (0, 169)
Mark Wielaard c6952c
+  /* string replacements or build_id updates don't change section size. */
Mark Wielaard c6952c
+  need_update = (need_update
Mark Wielaard c6952c
+		 || need_string_replacement
Mark Wielaard c6952c
+		 || (do_build_id && build_id != NULL));
Mark Wielaard c6952c
+#endif
Mark Wielaard c6952c
+
Mark Wielaard c6952c
   /* We might have changed the size of some debug sections. If so make
Mark Wielaard c6952c
      sure the section headers are updated and the data offsets are
Mark Wielaard c6952c
      correct. We set ELF_F_LAYOUT above because we don't want libelf
Mark Wielaard c6952c
@@ -2631,7 +2630,7 @@ main (int argc, char *argv[])
Mark Wielaard c6952c
      anything for the phdrs allocated sections. Keep the offset of
Mark Wielaard c6952c
      allocated sections so they are at the same place in the file. Add
Mark Wielaard c6952c
      unallocated ones after the allocated ones. */
Mark Wielaard c6952c
-  if (dso->phnum != 0 && (need_strp_update || need_stmt_update))
Mark Wielaard c6952c
+  if (dso->phnum != 0 && need_update)
Mark Wielaard c6952c
     {
Mark Wielaard c6952c
       Elf *elf = dso->elf;
Mark Wielaard c6952c
       GElf_Off last_offset;