alexk / rpms / rpm

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