michal-grzedzicki / rpms / rpm

Forked from rpms/rpm 5 months ago
Clone
ed184b
From 201a71ce18734b1cebc337225f345fd754a6414f Mon Sep 17 00:00:00 2001
ed184b
Message-Id: <201a71ce18734b1cebc337225f345fd754a6414f.1573552234.git.pmatilai@redhat.com>
ed184b
In-Reply-To: <ce6e8556a8f93327d6de0446f21ac5e549861d82.1573552234.git.pmatilai@redhat.com>
ed184b
References: <ce6e8556a8f93327d6de0446f21ac5e549861d82.1573552234.git.pmatilai@redhat.com>
ed184b
From: Mark Wielaard <mark@klomp.org>
ed184b
Date: Mon, 17 Jun 2019 11:23:25 +0200
ed184b
Subject: [PATCH 2/3] Handle .debug_macro in debugedit.
ed184b
ed184b
When compiling with -g3 gcc will generate a .debug_macro section
ed184b
which has pointers to the .debug_str section. Since we might rewrite
ed184b
the .debug_str section, we also need to update any .debug_macro
ed184b
pointers.
ed184b
ed184b
Updated the debugedit.at testcase by building everything with -g
ed184b
and add various checks to see the .debug_macro section looks OK
ed184b
after running debugedit. Added a new rpmbuild.at testcase to check
ed184b
handing of .debug_macro in the whole rpmbuild debuginfo pipeline
ed184b
to double check the separate .debug file also contains the macros.
ed184b
ed184b
Original patch by Michael Schroeder <mls@suse.de>. Extended by
ed184b
Mark Wielaard <mark@klomp.org> to deal with relocations and possible
ed184b
multiple COMDAT .debug_macro sections.
ed184b
---
ed184b
 tests/Makefile.am              |   1 +
ed184b
 tests/data/SPECS/hello-g3.spec |  60 ++++++++++
ed184b
 tests/debugedit.at             |  79 ++++++++++++-
ed184b
 tests/rpmbuild.at              |  33 ++++++
ed184b
 tools/debugedit.c              | 196 +++++++++++++++++++++++++++++++--
ed184b
 5 files changed, 356 insertions(+), 13 deletions(-)
ed184b
 create mode 100644 tests/data/SPECS/hello-g3.spec
ed184b
ed184b
[ test-suite part edited out, too painful to backport ]
ed184b
ed184b
diff --git a/tools/debugedit.c b/tools/debugedit.c
ed184b
index cf9cc3ca9..84483ef5e 100644
ed184b
--- a/tools/debugedit.c
ed184b
+++ b/tools/debugedit.c
ed184b
@@ -41,6 +41,7 @@
ed184b
 #include <gelf.h>
ed184b
 #include <dwarf.h>
ed184b
 
ed184b
+
ed184b
 /* Unfortunately strtab manipulation functions were only officially added
ed184b
    to elfutils libdw in 0.167.  Before that there were internal unsupported
ed184b
    ebl variants.  While libebl.h isn't supported we'll try to use it anyway
ed184b
@@ -432,6 +433,7 @@ typedef struct debug_section
ed184b
     int sec, relsec;
ed184b
     REL *relbuf;
ed184b
     REL *relend;
ed184b
+    struct debug_section *next; /* Only happens for COMDAT .debug_macro.  */
ed184b
   } debug_section;
ed184b
 
ed184b
 static debug_section debug_sections[] =
ed184b
@@ -1989,11 +1991,35 @@ edit_dwarf2 (DSO *dso)
ed184b
 	    for (j = 0; debug_sections[j].name; ++j)
ed184b
 	      if (strcmp (name, debug_sections[j].name) == 0)
ed184b
 	 	{
ed184b
+		  struct debug_section *debug_sec = &debug_sections[j];
ed184b
 		  if (debug_sections[j].data)
ed184b
 		    {
ed184b
-		      error (0, 0, "%s: Found two copies of %s section",
ed184b
-			     dso->filename, name);
ed184b
-		      return 1;
ed184b
+		      if (j != DEBUG_MACRO)
ed184b
+			{
ed184b
+			  error (0, 0, "%s: Found two copies of %s section",
ed184b
+				 dso->filename, name);
ed184b
+			  return 1;
ed184b
+			}
ed184b
+		      else
ed184b
+			{
ed184b
+			  /* In relocatable files .debug_macro might
ed184b
+			     appear multiple times as COMDAT
ed184b
+			     section.  */
ed184b
+			  struct debug_section *sec;
ed184b
+			  sec = calloc (sizeof (struct debug_section), 1);
ed184b
+			  if (sec == NULL)
ed184b
+			    error (1, errno,
ed184b
+				   "%s: Could not allocate more macro sections",
ed184b
+				   dso->filename);
ed184b
+			  sec->name = ".debug_macro";
ed184b
+
ed184b
+			  struct debug_section *macro_sec = debug_sec;
ed184b
+			  while (macro_sec->next != NULL)
ed184b
+			    macro_sec = macro_sec->next;
ed184b
+
ed184b
+			  macro_sec->next = sec;
ed184b
+			  debug_sec = sec;
ed184b
+			}
ed184b
 		    }
ed184b
 
ed184b
 		  scn = dso->scn[i];
ed184b
@@ -2002,10 +2028,10 @@ edit_dwarf2 (DSO *dso)
ed184b
 		  assert (elf_getdata (scn, data) == NULL);
ed184b
 		  assert (data->d_off == 0);
ed184b
 		  assert (data->d_size == dso->shdr[i].sh_size);
ed184b
-		  debug_sections[j].data = data->d_buf;
ed184b
-		  debug_sections[j].elf_data = data;
ed184b
-		  debug_sections[j].size = data->d_size;
ed184b
-		  debug_sections[j].sec = i;
ed184b
+		  debug_sec->data = data->d_buf;
ed184b
+		  debug_sec->elf_data = data;
ed184b
+		  debug_sec->size = data->d_size;
ed184b
+		  debug_sec->sec = i;
ed184b
 		  break;
ed184b
 		}
ed184b
 
ed184b
@@ -2028,7 +2054,26 @@ edit_dwarf2 (DSO *dso)
ed184b
 			  + (dso->shdr[i].sh_type == SHT_RELA),
ed184b
 			  debug_sections[j].name) == 0)
ed184b
 	 	{
ed184b
-		  debug_sections[j].relsec = i;
ed184b
+		  if (j == DEBUG_MACRO)
ed184b
+		    {
ed184b
+		      /* Pick the correct one.  */
ed184b
+		      int rel_target = dso->shdr[i].sh_info;
ed184b
+		      struct debug_section *macro_sec = &debug_sections[j];
ed184b
+		      while (macro_sec != NULL)
ed184b
+			{
ed184b
+			  if (macro_sec->sec == rel_target)
ed184b
+			    {
ed184b
+			      macro_sec->relsec = i;
ed184b
+			      break;
ed184b
+			    }
ed184b
+			  macro_sec = macro_sec->next;
ed184b
+			}
ed184b
+		      if (macro_sec == NULL)
ed184b
+			error (0, 1, "No .debug_macro reloc section: %s",
ed184b
+			       dso->filename);
ed184b
+		    }
ed184b
+		  else
ed184b
+		    debug_sections[j].relsec = i;
ed184b
 		  break;
ed184b
 		}
ed184b
 	  }
ed184b
@@ -2062,6 +2107,7 @@ edit_dwarf2 (DSO *dso)
ed184b
       struct abbrev_tag tag, *t;
ed184b
       int phase;
ed184b
       bool info_rel_updated = false;
ed184b
+      bool macro_rel_updated = false;
ed184b
 
ed184b
       for (phase = 0; phase < 2; phase++)
ed184b
 	{
ed184b
@@ -2279,6 +2325,113 @@ edit_dwarf2 (DSO *dso)
ed184b
 		}
ed184b
 	    }
ed184b
 
ed184b
+	  /* The .debug_macro section also contains offsets into the
ed184b
+	     .debug_str section and references to the .debug_line
ed184b
+	     tables, so we need to update those as well if we update
ed184b
+	     the strings or the stmts.  */
ed184b
+	  if ((need_strp_update || need_stmt_update)
ed184b
+	      && debug_sections[DEBUG_MACRO].data)
ed184b
+	    {
ed184b
+	      /* There might be multiple (COMDAT) .debug_macro sections.  */
ed184b
+	      struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO];
ed184b
+	      while (macro_sec != NULL)
ed184b
+		{
ed184b
+		  setup_relbuf(dso, macro_sec, &reltype);
ed184b
+		  rel_updated = false;
ed184b
+
ed184b
+		  ptr = macro_sec->data;
ed184b
+		  endsec = ptr + macro_sec->size;
ed184b
+		  int op = 0, macro_version, macro_flags;
ed184b
+		  int offset_len = 4, line_offset = 0;
ed184b
+
ed184b
+		  while (ptr < endsec)
ed184b
+		    {
ed184b
+		      if (!op)
ed184b
+			{
ed184b
+			  macro_version = read_16 (ptr);
ed184b
+			  macro_flags = read_8 (ptr);
ed184b
+			  if (macro_version < 4 || macro_version > 5)
ed184b
+			    error (1, 0, "unhandled .debug_macro version: %d",
ed184b
+				   macro_version);
ed184b
+			  if ((macro_flags & ~2) != 0)
ed184b
+			    error (1, 0, "unhandled .debug_macro flags: 0x%x",
ed184b
+				   macro_flags);
ed184b
+
ed184b
+			  offset_len = (macro_flags & 0x01) ? 8 : 4;
ed184b
+			  line_offset = (macro_flags & 0x02) ? 1 : 0;
ed184b
+
ed184b
+			  if (offset_len != 4)
ed184b
+			    error (0, 1,
ed184b
+				   "Cannot handle 8 byte macro offsets: %s",
ed184b
+				   dso->filename);
ed184b
+
ed184b
+			  /* Update the line_offset if it is there.  */
ed184b
+			  if (line_offset)
ed184b
+			    {
ed184b
+			      if (phase == 0)
ed184b
+				ptr += offset_len;
ed184b
+			      else
ed184b
+				{
ed184b
+				  size_t idx, new_idx;
ed184b
+				  idx = do_read_32_relocated (ptr);
ed184b
+				  new_idx = find_new_list_offs (&dso->lines,
ed184b
+								idx);
ed184b
+				  write_32_relocated (ptr, new_idx);
ed184b
+				}
ed184b
+			    }
ed184b
+			}
ed184b
+
ed184b
+		      op = read_8 (ptr);
ed184b
+		      if (!op)
ed184b
+			continue;
ed184b
+		      switch(op)
ed184b
+			{
ed184b
+			case DW_MACRO_GNU_define:
ed184b
+			case DW_MACRO_GNU_undef:
ed184b
+			  read_uleb128 (ptr);
ed184b
+			  ptr = ((unsigned char *) strchr ((char *) ptr, '\0')
ed184b
+				 + 1);
ed184b
+			  break;
ed184b
+			case DW_MACRO_GNU_start_file:
ed184b
+			  read_uleb128 (ptr);
ed184b
+			  read_uleb128 (ptr);
ed184b
+			  break;
ed184b
+			case DW_MACRO_GNU_end_file:
ed184b
+			  break;
ed184b
+			case DW_MACRO_GNU_define_indirect:
ed184b
+			case DW_MACRO_GNU_undef_indirect:
ed184b
+			  read_uleb128 (ptr);
ed184b
+			  if (phase == 0)
ed184b
+			    {
ed184b
+			      size_t idx = read_32_relocated (ptr);
ed184b
+			      record_existing_string_entry_idx (&dso->strings,
ed184b
+								idx);
ed184b
+			    }
ed184b
+			  else
ed184b
+			    {
ed184b
+			      struct stridxentry *entry;
ed184b
+			      size_t idx, new_idx;
ed184b
+			      idx = do_read_32_relocated (ptr);
ed184b
+			      entry = string_find_entry (&dso->strings, idx);
ed184b
+			      new_idx = strent_offset (entry->entry);
ed184b
+			      write_32_relocated (ptr, new_idx);
ed184b
+			    }
ed184b
+			  break;
ed184b
+			case DW_MACRO_GNU_transparent_include:
ed184b
+			  ptr += offset_len;
ed184b
+			  break;
ed184b
+			default:
ed184b
+			  error (1, 0, "Unhandled DW_MACRO op 0x%x", op);
ed184b
+			  break;
ed184b
+			}
ed184b
+		    }
ed184b
+
ed184b
+		  if (rel_updated)
ed184b
+		    macro_rel_updated = true;
ed184b
+		  macro_sec = macro_sec->next;
ed184b
+		}
ed184b
+	    }
ed184b
+
ed184b
 	  /* Same for the debug_str section. Make sure everything is
ed184b
 	     in place for phase 1 updating of debug_info
ed184b
 	     references. */
ed184b
@@ -2308,10 +2461,24 @@ edit_dwarf2 (DSO *dso)
ed184b
 	 new strp, strings and/or linep offsets.  */
ed184b
       if (need_strp_update || need_string_replacement || need_stmt_update)
ed184b
 	dirty_section (DEBUG_INFO);
ed184b
+      if (need_strp_update || need_stmt_update)
ed184b
+	dirty_section (DEBUG_MACRO);
ed184b
+      if (need_stmt_update)
ed184b
+	dirty_section (DEBUG_LINE);
ed184b
 
ed184b
-      /* Update any debug_info relocations addends we might have touched. */
ed184b
+      /* Update any relocations addends we might have touched. */
ed184b
       if (info_rel_updated)
ed184b
 	update_rela_data (dso, &debug_sections[DEBUG_INFO]);
ed184b
+
ed184b
+      if (macro_rel_updated)
ed184b
+	{
ed184b
+	  struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO];
ed184b
+	  while (macro_sec != NULL)
ed184b
+	    {
ed184b
+	      update_rela_data (dso, macro_sec);
ed184b
+	      macro_sec = macro_sec->next;
ed184b
+	    }
ed184b
+	}
ed184b
     }
ed184b
 
ed184b
   return 0;
ed184b
@@ -2843,6 +3010,17 @@ main (int argc, char *argv[])
ed184b
   destroy_lines (&dso->lines);
ed184b
   free (dso);
ed184b
 
ed184b
+  /* In case there were multiple (COMDAT) .debug_macro sections,
ed184b
+     free them.  */
ed184b
+  struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO];
ed184b
+  macro_sec = macro_sec->next;
ed184b
+  while (macro_sec != NULL)
ed184b
+    {
ed184b
+      struct debug_section *next = macro_sec->next;
ed184b
+      free (macro_sec);
ed184b
+      macro_sec = next;
ed184b
+    }
ed184b
+
ed184b
   poptFreeContext (optCon);
ed184b
 
ed184b
   return 0;
ed184b
-- 
ed184b
2.23.0
ed184b