dcavalca / rpms / rpm

Forked from rpms/rpm 2 years ago
Clone
672c60
From ce6e8556a8f93327d6de0446f21ac5e549861d82 Mon Sep 17 00:00:00 2001
672c60
Message-Id: <ce6e8556a8f93327d6de0446f21ac5e549861d82.1573552234.git.pmatilai@redhat.com>
672c60
From: Mark Wielaard <mark@klomp.org>
672c60
Date: Mon, 17 Jun 2019 11:23:24 +0200
672c60
Subject: [PATCH 1/3] debugedit: Refactor reading/writing of relocated values.
672c60
672c60
This refactors the reading and writing of relocated values into seperate
672c60
helper functions (setup_relbuf and update_rela_data). It will be easier
672c60
to reuse this code in case we want to read/write relocated values in other
672c60
sections than DEBUG_INFO. The only functional change is that we explicitly
672c60
track whether the relocation data is updated, and only explicitly update
672c60
and write out the relocation data if so. In the case there were no strp
672c60
or stmt updates, there will also not be any relocation updates, even if
672c60
there is relocation data available.
672c60
672c60
All new debugedit testcases pass before and after this refactoring.
672c60
---
672c60
 tools/debugedit.c | 395 +++++++++++++++++++++++++---------------------
672c60
 1 file changed, 216 insertions(+), 179 deletions(-)
672c60
672c60
diff --git a/tools/debugedit.c b/tools/debugedit.c
672c60
index 4be85b979..cf9cc3ca9 100644
672c60
--- a/tools/debugedit.c
672c60
+++ b/tools/debugedit.c
672c60
@@ -401,13 +401,18 @@ dwarf2_write_be32 (unsigned char *p, uint32_t v)
672c60
    relend). Might just update the addend. So relocations need to be
672c60
    updated at the end.  */
672c60
 
672c60
+static bool rel_updated;
672c60
+
672c60
 #define do_write_32_relocated(ptr,val) ({ \
672c60
   if (relptr && relptr < relend && relptr->ptr == ptr)	\
672c60
     {							\
672c60
       if (reltype == SHT_REL)				\
672c60
 	do_write_32 (ptr, val - relptr->addend);	\
672c60
       else						\
672c60
-	relptr->addend = val;				\
672c60
+	{						\
672c60
+	  relptr->addend = val;				\
672c60
+	  rel_updated = true;				\
672c60
+	}						\
672c60
     }							\
672c60
   else							\
672c60
     do_write_32 (ptr,val);				\
672c60
@@ -418,14 +423,18 @@ dwarf2_write_be32 (unsigned char *p, uint32_t v)
672c60
   ptr += 4;			       \
672c60
 })
672c60
 
672c60
-static struct
672c60
+typedef struct debug_section
672c60
   {
672c60
     const char *name;
672c60
     unsigned char *data;
672c60
     Elf_Data *elf_data;
672c60
     size_t size;
672c60
     int sec, relsec;
672c60
-  } debug_sections[] =
672c60
+    REL *relbuf;
672c60
+    REL *relend;
672c60
+  } debug_section;
672c60
+
672c60
+static debug_section debug_sections[] =
672c60
   {
672c60
 #define DEBUG_INFO	0
672c60
 #define DEBUG_ABBREV	1
672c60
@@ -458,6 +467,201 @@ static struct
672c60
     { NULL, NULL, NULL, 0, 0, 0 }
672c60
   };
672c60
 
672c60
+static int
672c60
+rel_cmp (const void *a, const void *b)
672c60
+{
672c60
+  REL *rela = (REL *) a, *relb = (REL *) b;
672c60
+
672c60
+  if (rela->ptr < relb->ptr)
672c60
+    return -1;
672c60
+
672c60
+  if (rela->ptr > relb->ptr)
672c60
+    return 1;
672c60
+
672c60
+  return 0;
672c60
+}
672c60
+
672c60
+/* Returns a malloced REL array, or NULL when there are no relocations
672c60
+   for this section.  When there are relocations, will setup relend,
672c60
+   as the last REL, and reltype, as SHT_REL or SHT_RELA.  */
672c60
+static void
672c60
+setup_relbuf (DSO *dso, debug_section *sec, int *reltype)
672c60
+{
672c60
+  int ndx, maxndx;
672c60
+  GElf_Rel rel;
672c60
+  GElf_Rela rela;
672c60
+  GElf_Sym sym;
672c60
+  GElf_Addr base = dso->shdr[sec->sec].sh_addr;
672c60
+  Elf_Data *symdata = NULL;
672c60
+  int rtype;
672c60
+  REL *relbuf;
672c60
+  Elf_Scn *scn;
672c60
+  Elf_Data *data;
672c60
+  int i = sec->relsec;
672c60
+
672c60
+  /* No relocations, or did we do this already? */
672c60
+  if (i == 0 || sec->relbuf != NULL)
672c60
+    {
672c60
+      relptr = sec->relbuf;
672c60
+      relend = sec->relend;
672c60
+      return;
672c60
+    }
672c60
+
672c60
+  scn = dso->scn[i];
672c60
+  data = elf_getdata (scn, NULL);
672c60
+  assert (data != NULL && data->d_buf != NULL);
672c60
+  assert (elf_getdata (scn, data) == NULL);
672c60
+  assert (data->d_off == 0);
672c60
+  assert (data->d_size == dso->shdr[i].sh_size);
672c60
+  maxndx = dso->shdr[i].sh_size / dso->shdr[i].sh_entsize;
672c60
+  relbuf = malloc (maxndx * sizeof (REL));
672c60
+  *reltype = dso->shdr[i].sh_type;
672c60
+  if (relbuf == NULL)
672c60
+    error (1, errno, "%s: Could not allocate memory", dso->filename);
672c60
+
672c60
+  symdata = elf_getdata (dso->scn[dso->shdr[i].sh_link], NULL);
672c60
+  assert (symdata != NULL && symdata->d_buf != NULL);
672c60
+  assert (elf_getdata (dso->scn[dso->shdr[i].sh_link], symdata) == NULL);
672c60
+  assert (symdata->d_off == 0);
672c60
+  assert (symdata->d_size == dso->shdr[dso->shdr[i].sh_link].sh_size);
672c60
+
672c60
+  for (ndx = 0, relend = relbuf; ndx < maxndx; ++ndx)
672c60
+    {
672c60
+      if (dso->shdr[i].sh_type == SHT_REL)
672c60
+	{
672c60
+	  gelf_getrel (data, ndx, &rel;;
672c60
+	  rela.r_offset = rel.r_offset;
672c60
+	  rela.r_info = rel.r_info;
672c60
+	  rela.r_addend = 0;
672c60
+	}
672c60
+      else
672c60
+	gelf_getrela (data, ndx, &rela);
672c60
+      gelf_getsym (symdata, ELF64_R_SYM (rela.r_info), &sym);
672c60
+      /* Relocations against section symbols are uninteresting in REL.  */
672c60
+      if (dso->shdr[i].sh_type == SHT_REL && sym.st_value == 0)
672c60
+	continue;
672c60
+      /* Only consider relocations against .debug_str, .debug_line
672c60
+	 and .debug_abbrev.  */
672c60
+      if (sym.st_shndx != debug_sections[DEBUG_STR].sec
672c60
+	  && sym.st_shndx != debug_sections[DEBUG_LINE].sec
672c60
+	  && sym.st_shndx != debug_sections[DEBUG_ABBREV].sec)
672c60
+	continue;
672c60
+      rela.r_addend += sym.st_value;
672c60
+      rtype = ELF64_R_TYPE (rela.r_info);
672c60
+      switch (dso->ehdr.e_machine)
672c60
+	{
672c60
+	case EM_SPARC:
672c60
+	case EM_SPARC32PLUS:
672c60
+	case EM_SPARCV9:
672c60
+	  if (rtype != R_SPARC_32 && rtype != R_SPARC_UA32)
672c60
+	    goto fail;
672c60
+	  break;
672c60
+	case EM_386:
672c60
+	  if (rtype != R_386_32)
672c60
+	    goto fail;
672c60
+	  break;
672c60
+	case EM_PPC:
672c60
+	case EM_PPC64:
672c60
+	  if (rtype != R_PPC_ADDR32 && rtype != R_PPC_UADDR32)
672c60
+	    goto fail;
672c60
+	  break;
672c60
+	case EM_S390:
672c60
+	  if (rtype != R_390_32)
672c60
+	    goto fail;
672c60
+	  break;
672c60
+	case EM_IA_64:
672c60
+	  if (rtype != R_IA64_SECREL32LSB)
672c60
+	    goto fail;
672c60
+	  break;
672c60
+	case EM_X86_64:
672c60
+	  if (rtype != R_X86_64_32)
672c60
+	    goto fail;
672c60
+	  break;
672c60
+	case EM_ALPHA:
672c60
+	  if (rtype != R_ALPHA_REFLONG)
672c60
+	    goto fail;
672c60
+	  break;
672c60
+#if defined(EM_AARCH64) && defined(R_AARCH64_ABS32)
672c60
+	case EM_AARCH64:
672c60
+	  if (rtype != R_AARCH64_ABS32)
672c60
+	    goto fail;
672c60
+	  break;
672c60
+#endif
672c60
+	case EM_68K:
672c60
+	  if (rtype != R_68K_32)
672c60
+	    goto fail;
672c60
+	  break;
672c60
+#if defined(EM_RISCV) && defined(R_RISCV_32)
672c60
+	case EM_RISCV:
672c60
+	  if (rtype != R_RISCV_32)
672c60
+	    goto fail;
672c60
+	  break;
672c60
+#endif
672c60
+	default:
672c60
+	fail:
672c60
+	  error (1, 0, "%s: Unhandled relocation %d in %s section",
672c60
+		 dso->filename, rtype, sec->name);
672c60
+	}
672c60
+      relend->ptr = sec->data
672c60
+	+ (rela.r_offset - base);
672c60
+      relend->addend = rela.r_addend;
672c60
+      relend->ndx = ndx;
672c60
+      ++(relend);
672c60
+    }
672c60
+  if (relbuf == relend)
672c60
+    {
672c60
+      free (relbuf);
672c60
+      relbuf = NULL;
672c60
+      relend = NULL;
672c60
+    }
672c60
+  else
672c60
+    qsort (relbuf, relend - relbuf, sizeof (REL), rel_cmp);
672c60
+
672c60
+  sec->relbuf = relbuf;
672c60
+  sec->relend = relend;
672c60
+  relptr = relbuf;
672c60
+}
672c60
+
672c60
+/* Updates SHT_RELA section associated with the given section based on
672c60
+   the relbuf data. The relbuf data is freed at the end.  */
672c60
+static void
672c60
+update_rela_data (DSO *dso, struct debug_section *sec)
672c60
+{
672c60
+  Elf_Data *symdata;
672c60
+  int relsec_ndx = sec->relsec;
672c60
+  Elf_Data *data = elf_getdata (dso->scn[relsec_ndx], NULL);
672c60
+  symdata = elf_getdata (dso->scn[dso->shdr[relsec_ndx].sh_link],
672c60
+			 NULL);
672c60
+
672c60
+  relptr = sec->relbuf;
672c60
+  relend = sec->relend;
672c60
+  while (relptr < relend)
672c60
+    {
672c60
+      GElf_Sym sym;
672c60
+      GElf_Rela rela;
672c60
+      int ndx = relptr->ndx;
672c60
+
672c60
+      if (gelf_getrela (data, ndx, &rela) == NULL)
672c60
+	error (1, 0, "Couldn't get relocation: %s",
672c60
+	       elf_errmsg (-1));
672c60
+
672c60
+      if (gelf_getsym (symdata, GELF_R_SYM (rela.r_info),
672c60
+		       &sym) == NULL)
672c60
+	error (1, 0, "Couldn't get symbol: %s", elf_errmsg (-1));
672c60
+
672c60
+      rela.r_addend = relptr->addend - sym.st_value;
672c60
+
672c60
+      if (gelf_update_rela (data, ndx, &rela) == 0)
672c60
+	error (1, 0, "Couldn't update relocations: %s",
672c60
+	       elf_errmsg (-1));
672c60
+
672c60
+      ++relptr;
672c60
+    }
672c60
+  elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY);
672c60
+
672c60
+  free (sec->relbuf);
672c60
+}
672c60
+
672c60
 struct abbrev_attr
672c60
   {
672c60
     unsigned int attr;
672c60
@@ -1743,20 +1947,6 @@ edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase)
672c60
   return ptr;
672c60
 }
672c60
 
672c60
-static int
672c60
-rel_cmp (const void *a, const void *b)
672c60
-{
672c60
-  REL *rela = (REL *) a, *relb = (REL *) b;
672c60
-
672c60
-  if (rela->ptr < relb->ptr)
672c60
-    return -1;
672c60
-
672c60
-  if (rela->ptr > relb->ptr)
672c60
-    return 1;
672c60
-
672c60
-  return 0;
672c60
-}
672c60
-
672c60
 static int
672c60
 line_rel_cmp (const void *a, const void *b)
672c60
 {
672c60
@@ -1871,132 +2061,7 @@ edit_dwarf2 (DSO *dso)
672c60
       htab_t abbrev;
672c60
       struct abbrev_tag tag, *t;
672c60
       int phase;
672c60
-      REL *relbuf = NULL;
672c60
-
672c60
-      if (debug_sections[DEBUG_INFO].relsec)
672c60
-	{
672c60
-	  int ndx, maxndx;
672c60
-	  GElf_Rel rel;
672c60
-	  GElf_Rela rela;
672c60
-	  GElf_Sym sym;
672c60
-	  GElf_Addr base = dso->shdr[debug_sections[DEBUG_INFO].sec].sh_addr;
672c60
-	  Elf_Data *symdata = NULL;
672c60
-	  int rtype;
672c60
-
672c60
-	  i = debug_sections[DEBUG_INFO].relsec;
672c60
-	  scn = dso->scn[i];
672c60
-	  data = elf_getdata (scn, NULL);
672c60
-	  assert (data != NULL && data->d_buf != NULL);
672c60
-	  assert (elf_getdata (scn, data) == NULL);
672c60
-	  assert (data->d_off == 0);
672c60
-	  assert (data->d_size == dso->shdr[i].sh_size);
672c60
-	  maxndx = dso->shdr[i].sh_size / dso->shdr[i].sh_entsize;
672c60
-	  relbuf = malloc (maxndx * sizeof (REL));
672c60
-	  reltype = dso->shdr[i].sh_type;
672c60
-	  if (relbuf == NULL)
672c60
-	    error (1, errno, "%s: Could not allocate memory", dso->filename);
672c60
-
672c60
-	  symdata = elf_getdata (dso->scn[dso->shdr[i].sh_link], NULL);
672c60
-	  assert (symdata != NULL && symdata->d_buf != NULL);
672c60
-	  assert (elf_getdata (dso->scn[dso->shdr[i].sh_link], symdata)
672c60
-		  == NULL);
672c60
-	  assert (symdata->d_off == 0);
672c60
-	  assert (symdata->d_size
672c60
-		  == dso->shdr[dso->shdr[i].sh_link].sh_size);
672c60
-
672c60
-	  for (ndx = 0, relend = relbuf; ndx < maxndx; ++ndx)
672c60
-	    {
672c60
-	      if (dso->shdr[i].sh_type == SHT_REL)
672c60
-		{
672c60
-		  gelf_getrel (data, ndx, &rel;;
672c60
-		  rela.r_offset = rel.r_offset;
672c60
-		  rela.r_info = rel.r_info;
672c60
-		  rela.r_addend = 0;
672c60
-		}
672c60
-	      else
672c60
-		gelf_getrela (data, ndx, &rela);
672c60
-	      gelf_getsym (symdata, ELF64_R_SYM (rela.r_info), &sym);
672c60
-	      /* Relocations against section symbols are uninteresting
672c60
-		 in REL.  */
672c60
-	      if (dso->shdr[i].sh_type == SHT_REL && sym.st_value == 0)
672c60
-		continue;
672c60
-	      /* Only consider relocations against .debug_str, .debug_line
672c60
-		 and .debug_abbrev.  */
672c60
-	      if (sym.st_shndx != debug_sections[DEBUG_STR].sec
672c60
-		  && sym.st_shndx != debug_sections[DEBUG_LINE].sec
672c60
-		  && sym.st_shndx != debug_sections[DEBUG_ABBREV].sec)
672c60
-		continue;
672c60
-	      rela.r_addend += sym.st_value;
672c60
-	      rtype = ELF64_R_TYPE (rela.r_info);
672c60
-	      switch (dso->ehdr.e_machine)
672c60
-		{
672c60
-		case EM_SPARC:
672c60
-		case EM_SPARC32PLUS:
672c60
-		case EM_SPARCV9:
672c60
-		  if (rtype != R_SPARC_32 && rtype != R_SPARC_UA32)
672c60
-		    goto fail;
672c60
-		  break;
672c60
-		case EM_386:
672c60
-		  if (rtype != R_386_32)
672c60
-		    goto fail;
672c60
-		  break;
672c60
-		case EM_PPC:
672c60
-		case EM_PPC64:
672c60
-		  if (rtype != R_PPC_ADDR32 && rtype != R_PPC_UADDR32)
672c60
-		    goto fail;
672c60
-		  break;
672c60
-		case EM_S390:
672c60
-		  if (rtype != R_390_32)
672c60
-		    goto fail;
672c60
-		  break;
672c60
-		case EM_IA_64:
672c60
-		  if (rtype != R_IA64_SECREL32LSB)
672c60
-		    goto fail;
672c60
-		  break;
672c60
-		case EM_X86_64:
672c60
-		  if (rtype != R_X86_64_32)
672c60
-		    goto fail;
672c60
-		  break;
672c60
-		case EM_ALPHA:
672c60
-		  if (rtype != R_ALPHA_REFLONG)
672c60
-		    goto fail;
672c60
-		  break;
672c60
-#if defined(EM_AARCH64) && defined(R_AARCH64_ABS32)
672c60
-		case EM_AARCH64:
672c60
-		  if (rtype != R_AARCH64_ABS32)
672c60
-		    goto fail;
672c60
-		  break;
672c60
-#endif
672c60
-		case EM_68K:
672c60
-		  if (rtype != R_68K_32)
672c60
-		    goto fail;
672c60
-		  break;
672c60
-#if defined(EM_RISCV) && defined(R_RISCV_32)
672c60
-		case EM_RISCV:
672c60
-		  if (rtype != R_RISCV_32)
672c60
-		    goto fail;
672c60
-		  break;
672c60
-#endif
672c60
-		default:
672c60
-		fail:
672c60
-		  error (1, 0, "%s: Unhandled relocation %d in .debug_info section",
672c60
-			 dso->filename, rtype);
672c60
-		}
672c60
-	      relend->ptr = debug_sections[DEBUG_INFO].data
672c60
-			    + (rela.r_offset - base);
672c60
-	      relend->addend = rela.r_addend;
672c60
-	      relend->ndx = ndx;
672c60
-	      ++relend;
672c60
-	    }
672c60
-	  if (relbuf == relend)
672c60
-	    {
672c60
-	      free (relbuf);
672c60
-	      relbuf = NULL;
672c60
-	      relend = NULL;
672c60
-	    }
672c60
-	  else
672c60
-	    qsort (relbuf, relend - relbuf, sizeof (REL), rel_cmp);
672c60
-	}
672c60
+      bool info_rel_updated = false;
672c60
 
672c60
       for (phase = 0; phase < 2; phase++)
672c60
 	{
672c60
@@ -2008,7 +2073,8 @@ edit_dwarf2 (DSO *dso)
672c60
 	    break;
672c60
 
672c60
 	  ptr = debug_sections[DEBUG_INFO].data;
672c60
-	  relptr = relbuf;
672c60
+	  setup_relbuf(dso, &debug_sections[DEBUG_INFO], &reltype);
672c60
+	  rel_updated = false;
672c60
 	  endsec = ptr + debug_sections[DEBUG_INFO].size;
672c60
 	  while (ptr < endsec)
672c60
 	    {
672c60
@@ -2096,6 +2162,10 @@ edit_dwarf2 (DSO *dso)
672c60
 	      htab_delete (abbrev);
672c60
 	    }
672c60
 
672c60
+	  /* Remember whether any .debug_info relocations might need
672c60
+	     to be updated. */
672c60
+	  info_rel_updated = rel_updated;
672c60
+
672c60
 	  /* We might have to recalculate/rewrite the debug_line
672c60
 	     section.  We need to do that before going into phase one
672c60
 	     so we have all new offsets.  We do this separately from
672c60
@@ -2240,41 +2310,8 @@ edit_dwarf2 (DSO *dso)
672c60
 	dirty_section (DEBUG_INFO);
672c60
 
672c60
       /* Update any debug_info relocations addends we might have touched. */
672c60
-      if (relbuf != NULL && reltype == SHT_RELA)
672c60
-	{
672c60
-	  Elf_Data *symdata;
672c60
-          int relsec_ndx = debug_sections[DEBUG_INFO].relsec;
672c60
-          data = elf_getdata (dso->scn[relsec_ndx], NULL);
672c60
-	  symdata = elf_getdata (dso->scn[dso->shdr[relsec_ndx].sh_link],
672c60
-				 NULL);
672c60
-
672c60
-	  relptr = relbuf;
672c60
-	  while (relptr < relend)
672c60
-	    {
672c60
-	      GElf_Sym sym;
672c60
-	      GElf_Rela rela;
672c60
-	      int ndx = relptr->ndx;
672c60
-
672c60
-	      if (gelf_getrela (data, ndx, &rela) == NULL)
672c60
-		error (1, 0, "Couldn't get relocation: %s",
672c60
-		       elf_errmsg (-1));
672c60
-
672c60
-	      if (gelf_getsym (symdata, GELF_R_SYM (rela.r_info),
672c60
-			       &sym) == NULL)
672c60
-		error (1, 0, "Couldn't get symbol: %s", elf_errmsg (-1));
672c60
-
672c60
-	      rela.r_addend = relptr->addend - sym.st_value;
672c60
-
672c60
-	      if (gelf_update_rela (data, ndx, &rela) == 0)
672c60
-		error (1, 0, "Couldn't update relocations: %s",
672c60
-		       elf_errmsg (-1));
672c60
-
672c60
-	      ++relptr;
672c60
-	    }
672c60
-	  elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY);
672c60
-	}
672c60
-
672c60
-      free (relbuf);
672c60
+      if (info_rel_updated)
672c60
+	update_rela_data (dso, &debug_sections[DEBUG_INFO]);
672c60
     }
672c60
 
672c60
   return 0;
672c60
-- 
672c60
2.23.0
672c60