[Rpm-maint] [PATCH 4/5] debugedit: Implement DWARF-5 .debug_types (in .debug_info).

Jan Kratochvil jan.kratochvil at redhat.com
Tue Aug 18 20:13:15 UTC 2020


diff --git a/tests/debugedit.at b/tests/debugedit.at
index 49721a342..bcd86ac67 100644
--- a/tests/debugedit.at
+++ b/tests/debugedit.at
@@ -253,9 +253,8 @@ AT_CLEANUP
 # ===
 # Make sure -fdebug-types-section has updated strings in objects.
 # ===
-AT_SETUP([debugedit .debug_types objects])
-AT_KEYWORDS([debugtypes] [debugedit])
-RPM_DEBUGEDIT_SETUP([-fdebug-types-section])
+m4_define([RPM_DEBUGEDIT_DEBUG_TYPES_OBJECTS],[
+RPM_DEBUGEDIT_SETUP($1)
 
 AT_DATA([expout],
 [st1
@@ -283,15 +282,13 @@ for i in ./foo.o ./subdir_bar/bar.o ./baz.o;do \
           | sort;
 done
 ]],[0],[expout])
-
-AT_CLEANUP
+])
 
 # ===
 # Make sure -fdebug-types-section has updated strings in partial linked object.
 # ===
-AT_SETUP([debugedit .debug_types partial])
-AT_KEYWORDS([debugtypes] [debugedit])
-RPM_DEBUGEDIT_SETUP([-fdebug-types-section])
+m4_define([RPM_DEBUGEDIT_DEBUG_TYPES_PARTIAL],[
+RPM_DEBUGEDIT_SETUP($1)
 
 AT_DATA([expout],
 [st1
@@ -311,15 +308,13 @@ readelf --debug-dump=info ./foobarbaz.part.o \
         | sed -n 's/^.*> *DW_AT_name *:.* \(stringp[^ ]*\|st.\)$/\1/p' \
         | sort
 ]],[0],[expout])
-
-AT_CLEANUP
+])
 
 # ===
 # Make sure -fdebug-types-section has updated strings in executable.
 # ===
-AT_SETUP([debugedit .debug_types exe])
-AT_KEYWORDS([debugtypes] [debugedit])
-RPM_DEBUGEDIT_SETUP([-fdebug-types-section])
+m4_define([RPM_DEBUGEDIT_DEBUG_TYPES_EXE],[
+RPM_DEBUGEDIT_SETUP($1)
 
 AT_DATA([expout],
 [st1
@@ -339,7 +334,36 @@ readelf --debug-dump=info ./foobarbaz.exe \
         | sed -n 's/^.*> *DW_AT_name *:.* \(stringp[^ ]*\|st.\)$/\1/p' \
         | sort
 ]],[0],[expout])
+])
+
+AT_SETUP([debugedit DWARF-4 .debug_types objects])
+AT_KEYWORDS([debugtypes] [debugedit])
+RPM_DEBUGEDIT_DEBUG_TYPES_OBJECTS([-gdwarf-4 -fdebug-types-section])
+AT_CLEANUP
 
+AT_SETUP([debugedit DWARF-4 .debug_types partial])
+AT_KEYWORDS([debugtypes] [debugedit])
+RPM_DEBUGEDIT_DEBUG_TYPES_PARTIAL([-gdwarf-4 -fdebug-types-section])
+AT_CLEANUP
+
+AT_SETUP([debugedit DWARF-4 .debug_types exe])
+AT_KEYWORDS([debugtypes] [debugedit])
+RPM_DEBUGEDIT_DEBUG_TYPES_EXE([-gdwarf-4 -fdebug-types-section])
+AT_CLEANUP
+
+AT_SETUP([debugedit DWARF-5 .debug_types objects])
+AT_KEYWORDS([debugtypes] [debugedit])
+RPM_DEBUGEDIT_DEBUG_TYPES_OBJECTS([-gdwarf-5 -fdebug-types-section])
+AT_CLEANUP
+
+AT_SETUP([debugedit DWARF-5 .debug_types partial])
+AT_KEYWORDS([debugtypes] [debugedit])
+RPM_DEBUGEDIT_DEBUG_TYPES_PARTIAL([-gdwarf-5 -fdebug-types-section])
+AT_CLEANUP
+
+AT_SETUP([debugedit DWARF-5 .debug_types exe])
+AT_KEYWORDS([debugtypes] [debugedit])
+RPM_DEBUGEDIT_DEBUG_TYPES_EXE([-gdwarf-5 -fdebug-types-section])
 AT_CLEANUP
 
 # foo.o and bar.o are build with relative paths and so will use the
diff --git a/tools/debugedit.c b/tools/debugedit.c
index 9f1dc2d3f..19f69e263 100644
--- a/tools/debugedit.c
+++ b/tools/debugedit.c
@@ -433,7 +433,8 @@ typedef struct debug_section
     int sec, relsec;
     REL *relbuf;
     REL *relend;
-    /* Only happens for COMDAT .debug_macro and .debug_types.  */
+    /* Only happens for COMDAT .debug_macro, .debug_types and DWARF-5
+       .debug_info.  */
     struct debug_section *next;
   } debug_section;
 
@@ -755,12 +756,19 @@ no_memory:
 	    }
 	  form = read_uleb128 (ptr);
 	  if (form == 2
-	      || (form > DW_FORM_flag_present && form != DW_FORM_ref_sig8))
+	      || (form > DW_FORM_flag_present && form != DW_FORM_ref_sig8
+		  && form != DW_FORM_implicit_const))
 	    {
-	      error (0, 0, "%s: Unknown DWARF DW_FORM_%d", dso->filename, form);
+	      error (0, 0, "%s: Unknown DWARF abbrev DW_FORM_0x%x",
+	             dso->filename, form);
 	      htab_delete (h);
 	      return NULL;
 	    }
+	  if (form == DW_FORM_implicit_const)
+	    {
+	      /* It is SLEB128 but the value is dropped anyway.  */
+	      read_uleb128 (ptr);
+	    }
 
 	  t->attr[t->nattr].attr = attr;
 	  t->attr[t->nattr++].form = form;
@@ -1505,6 +1513,7 @@ skip_form (DSO *dso, uint32_t *formp, unsigned char **ptrp)
 	*ptrp += 4;
       break;
     case DW_FORM_flag_present:
+    case DW_FORM_implicit_const:
       break;
     case DW_FORM_addr:
       *ptrp += ptr_size;
@@ -2018,7 +2027,7 @@ line_rel_cmp (const void *a, const void *b)
 }
 
 static int
-edit_info (DSO *dso, int phase, struct debug_section *sec)
+edit_info (DSO *dso, int phase, struct debug_section *sec, bool is_types)
 {
   unsigned char *ptr, *endcu, *endsec;
   uint32_t value;
@@ -2033,7 +2042,9 @@ edit_info (DSO *dso, int phase, struct debug_section *sec)
   endsec = ptr + sec->size;
   while (ptr < endsec)
     {
-      if (ptr + (sec == &debug_sections[DEBUG_INFO] ? 11 : 23) > endsec)
+      unsigned char *sec_start = ptr;
+
+      if (ptr + 4 + 2 + 1 + 1 > endsec)
 	{
 	  error (0, 0, "%s: %s CU header too small",
 		 dso->filename, sec->name);
@@ -2055,13 +2066,48 @@ edit_info (DSO *dso, int phase, struct debug_section *sec)
 	}
 
       cu_version = read_16 (ptr);
-      if (cu_version != 2 && cu_version != 3 && cu_version != 4)
+      if (cu_version != 2 && cu_version != 3 && cu_version != 4
+	  && cu_version != 5)
 	{
 	  error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
 		 cu_version);
 	  return 1;
 	}
 
+      int cu_ptr_size;
+      bool cu_is_types;
+
+      if (cu_version >= 5)
+	{
+	  if (is_types)
+	    {
+	      error (0, 0, "%s: .debug_types are invalid for DWARF 5+",
+		     dso->filename);
+	      return 1;
+	    }
+
+	  uint8_t unit_type = read_8 (ptr);
+	  if (unit_type != DW_UT_compile && unit_type != DW_UT_type)
+	    {
+	      error (0, 0, "%s: Unit type %u unhandled", dso->filename,
+		     unit_type);
+	      return 1;
+	    }
+	  cu_is_types = unit_type == DW_UT_type;
+
+	  cu_ptr_size = read_8 (ptr);
+	}
+      else
+	cu_is_types = is_types;
+
+      unsigned char *header_end = (sec_start + (!cu_is_types ? 11 : 23)
+				   + (cu_version < 5 ? 0 : 1));
+      if (header_end > endsec)
+	{
+	  error (0, 0, "%s: %s CU header too small", dso->filename, sec->name);
+	  return 1;
+	}
+
       value = read_32_relocated (ptr);
       if (value >= debug_sections[DEBUG_ABBREV].size)
 	{
@@ -2073,9 +2119,12 @@ edit_info (DSO *dso, int phase, struct debug_section *sec)
 	  return 1;
 	}
 
+      if (cu_version < 5)
+	cu_ptr_size = read_8 (ptr);
+
       if (ptr_size == 0)
 	{
-	  ptr_size = read_8 (ptr);
+	  ptr_size = cu_ptr_size;
 	  if (ptr_size != 4 && ptr_size != 8)
 	    {
 	      error (0, 0, "%s: Invalid DWARF pointer size %d",
@@ -2083,14 +2132,14 @@ edit_info (DSO *dso, int phase, struct debug_section *sec)
 	      return 1;
 	    }
 	}
-      else if (read_8 (ptr) != ptr_size)
+      else if (cu_ptr_size != ptr_size)
 	{
 	  error (0, 0, "%s: DWARF pointer size differs between CUs",
 		 dso->filename);
 	  return 1;
 	}
 
-      if (sec != &debug_sections[DEBUG_INFO])
+      if (cu_is_types)
 	ptr += 12; /* Skip type_signature and type_offset.  */
 
       abbrev = read_abbrev (dso,
@@ -2179,7 +2228,8 @@ edit_dwarf2 (DSO *dso)
 		  struct debug_section *debug_sec = &debug_sections[j];
 		  if (debug_sections[j].data)
 		    {
-		      if (j != DEBUG_MACRO && j != DEBUG_TYPES)
+		      if (j != DEBUG_MACRO && j != DEBUG_TYPES
+			  && j != DEBUG_INFO)
 			{
 			  error (0, 0, "%s: Found two copies of %s section",
 				 dso->filename, name);
@@ -2187,8 +2237,9 @@ edit_dwarf2 (DSO *dso)
 			}
 		      else
 			{
-			  /* In relocatable files .debug_macro and .debug_types
-			     might appear multiple times as COMDAT section.  */
+			  /* In relocatable files .debug_macro, .debug_types
+			     and DWARF-5 .debug_info might appear multiple
+			     times as COMDAT section.  */
 			  struct debug_section *sec;
 			  sec = calloc (sizeof (struct debug_section), 1);
 			  if (sec == NULL)
@@ -2238,7 +2289,7 @@ edit_dwarf2 (DSO *dso)
 			  + (dso->shdr[i].sh_type == SHT_RELA),
 			  debug_sections[j].name) == 0)
 	 	{
-		  if (j == DEBUG_MACRO || j == DEBUG_TYPES)
+		  if (j == DEBUG_MACRO || j == DEBUG_TYPES || j == DEBUG_INFO)
 		    {
 		      /* Pick the correct one.  */
 		      int rel_target = dso->shdr[i].sh_info;
@@ -2302,8 +2353,13 @@ edit_dwarf2 (DSO *dso)
 	break;
 
       rel_updated = false;
-      if (edit_info (dso, phase, &debug_sections[DEBUG_INFO]))
-	return 1;
+      struct debug_section *info_sec = &debug_sections[DEBUG_INFO];
+      while (info_sec != NULL)
+	{
+	  if (edit_info (dso, phase, info_sec, false /* is_types */))
+	    return 1;
+	  info_sec = info_sec->next;
+	}
 
       /* Remember whether any .debug_info relocations might need
 	 to be updated. */
@@ -2313,7 +2369,7 @@ edit_dwarf2 (DSO *dso)
       struct debug_section *types_sec = &debug_sections[DEBUG_TYPES];
       while (types_sec != NULL)
 	{
-	  if (edit_info (dso, phase, types_sec))
+	  if (edit_info (dso, phase, types_sec, true /* is_types */))
 	    return 1;
 	  types_sec = types_sec->next;
 	}
@@ -2564,7 +2620,14 @@ edit_dwarf2 (DSO *dso)
 
   /* Update any relocations addends we might have touched. */
   if (info_rel_updated)
-    update_rela_data (dso, &debug_sections[DEBUG_INFO]);
+    {
+      struct debug_section *info_sec = &debug_sections[DEBUG_INFO];
+      while (info_sec != NULL)
+	{
+	  update_rela_data (dso, info_sec);
+	  info_sec = info_sec->next;
+	}
+    }
   if (types_rel_updated)
     {
       struct debug_section *types_sec = &debug_sections[DEBUG_TYPES];
@@ -2914,6 +2977,7 @@ main (int argc, char *argv[])
   if (dso == NULL)
     exit (1);
 
+  bool have_info = false;
   for (i = 1; i < dso->ehdr.e_shnum; i++)
     {
       const char *name;
@@ -2929,7 +2993,7 @@ main (int argc, char *argv[])
 	      break;
 	    }
 	  if (strcmp (name, ".debug_info") == 0)
-	    edit_dwarf2 (dso);
+	    have_info = true;
 
 	  break;
 	case SHT_NOTE:
@@ -2960,6 +3024,9 @@ main (int argc, char *argv[])
 	}
     }
 
+  if (have_info)
+    edit_dwarf2 (dso);
+
   /* Normally we only need to explicitly update the section headers
      and data when any section data changed size. But because of a bug
      in elfutils before 0.169 we will have to update and write out all
@@ -3136,6 +3203,17 @@ main (int argc, char *argv[])
       types_sec = next;
     }
 
+  /* In case there were multiple (COMDAT) DWARF-5 .debug_info sections,
+     free them.  */
+  struct debug_section *info_sec = &debug_sections[DEBUG_INFO];
+  info_sec = info_sec->next;
+  while (info_sec != NULL)
+    {
+      struct debug_section *next = info_sec->next;
+      free (info_sec);
+      info_sec = next;
+    }
+
   poptFreeContext (optCon);
 
   return 0;



More information about the Rpm-maint mailing list