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