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