debugedit: Fix missing relocation of .debug_types section.
authorJan Kratochvil <jan.kratochvil@redhat.com>
Sat, 1 Aug 2020 08:45:47 +0000 (10:45 +0200)
committerPanu Matilainen <pmatilai@redhat.com>
Wed, 12 Aug 2020 08:21:13 +0000 (11:21 +0300)
tests/data/SOURCES/bar.c
tests/data/SOURCES/baz.c
tests/data/SOURCES/foo.c
tests/data/SOURCES/foobar.h
tests/debugedit.at
tools/debugedit.c

index 6d67469873d67eb099d8b8ca2d73c06161b4937d..20c6bd858e786eeb67057280bd2e820c99af8761 100644 (file)
@@ -1,5 +1,16 @@
 #include "foobar.h"
 
+struct debug_types_section1 var_bar1;
+
+/* Use different DW_AT_stmt_list in .debug_types having it outside foobar.h.
+   Also use two types in .debug_types for multiple COMDAT sections in object
+   files.  */
+struct debug_types_section_bar
+{
+  int stringp_bar, stb;
+};
+struct debug_types_section_bar var_bar;
+
 int number = NUMBER;
 
 int
index 4723022c2a9982ba881dcb7fe648e40cd7641341..ceab9f1c7376f9f314bf868e7881a7c4d35c909a 100644 (file)
@@ -1,5 +1,16 @@
 #include "foobar.h"
 
+struct debug_types_section1 var_baz1;
+
+/* Use different DW_AT_stmt_list in .debug_types having it outside foobar.h.
+   Also use two types in .debug_types for multiple COMDAT sections in object
+   files.  */
+struct debug_types_section_baz
+{
+  int stringp_baz, stz;
+};
+struct debug_types_section_baz var_baz;
+
 int
 main ()
 {
index 57906a2c5ebb7a4bdac867594a146966708859a6..76783d52166c569e35d3da2331dae8dffdef669b 100644 (file)
@@ -1,5 +1,16 @@
 #include "foobar.h"
 
+struct debug_types_section1 var_foo1;
+
+/* Use different DW_AT_stmt_list in .debug_types having it outside foobar.h.
+   Also use two types in .debug_types for multiple COMDAT sections in object
+   files.  */
+struct debug_types_section_foo
+{
+  int stringp_foo, stf;
+};
+struct debug_types_section_foo var_foo;
+
 int
 foo ()
 {
index 6db49a8cc589c9e4c4f3c47581e8baadd50429c2..fa493f55eceb190fa7af1509214a6584bff7d190 100644 (file)
@@ -4,3 +4,9 @@ extern int number;
 
 extern int foo (void);
 extern int bar (int);
+
+struct debug_types_section1
+{
+  /* Test both DW_FORM_strp and DW_FORM_string.  */
+  int stringp1, st1;
+};
index cae3f4384266f59f7cc2de297f64fba7f3de0327..49721a34271ab21fa2b06bec16a183cafe8e1a32 100644 (file)
@@ -22,6 +22,7 @@ AT_BANNER([RPM debugedit])
 AT_TESTED([debugedit])
 
 # Helper to create some test binaries.
+# Optional parameter can specify additional gcc parameters.
 m4_define([RPM_DEBUGEDIT_SETUP],[[
 # Create some test binaries. Create and build them in different subdirs
 # to make sure they produce different relative/absolute paths.
@@ -36,11 +37,11 @@ cp "${abs_srcdir}"/data/SOURCES/foobar.h subdir_headers
 cp "${abs_srcdir}"/data/SOURCES/baz.c .
 
 # First three object files (foo.o subdir_bar/bar.o and baz.o)
-gcc -g3 -Isubdir_headers -c subdir_foo/foo.c
+gcc -g3 -Isubdir_headers $1 -c subdir_foo/foo.c
 cd subdir_bar
-gcc -g3 -I../subdir_headers -c bar.c
+gcc -g3 -I../subdir_headers $1 -c bar.c
 cd ..
-gcc -g3 -I$(pwd)/subdir_headers -c $(pwd)/baz.c
+gcc -g3 -I$(pwd)/subdir_headers $1 -c $(pwd)/baz.c
 
 # Then a partially linked object file (somewhat like a kernel module).
 # This will still have relocations between the debug sections.
@@ -249,6 +250,98 @@ readelf --debug-dump=info ./foobarbaz.exe | grep -E 'DW_AT_(name|comp_dir)' \
 
 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])
+
+AT_DATA([expout],
+[st1
+stf
+stringp1
+stringp_foo
+st1
+stb
+stringp1
+stringp_bar
+st1
+stringp1
+stringp_baz
+stz
+])
+
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./foo.o]])
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./subdir_bar/bar.o]])
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./baz.o]])
+AT_CHECK([[
+for i in ./foo.o ./subdir_bar/bar.o ./baz.o;do \
+  readelf --debug-dump=info $i \
+          | awk '/Abbrev Number:.*DW_TAG_type_unit/{p=1}{if(p)print}/^$/{p=0}' \
+          | sed -n 's/^.*> *DW_AT_name *:.* \(stringp[^ ]*\|st.\)$/\1/p' \
+          | 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])
+
+AT_DATA([expout],
+[st1
+stb
+stf
+stringp1
+stringp_bar
+stringp_baz
+stringp_foo
+stz
+])
+
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./foobarbaz.part.o]])
+AT_CHECK([[
+readelf --debug-dump=info ./foobarbaz.part.o \
+        | awk '/Abbrev Number:.*DW_TAG_type_unit/{p=1}{if(p)print}/^$/{p=0}' \
+        | 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])
+
+AT_DATA([expout],
+[st1
+stb
+stf
+stringp1
+stringp_bar
+stringp_baz
+stringp_foo
+stz
+])
+
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./foobarbaz.exe]])
+AT_CHECK([[
+readelf --debug-dump=info ./foobarbaz.exe \
+        | awk '/Abbrev Number:.*DW_TAG_type_unit/{p=1}{if(p)print}/^$/{p=0}' \
+        | sed -n 's/^.*> *DW_AT_name *:.* \(stringp[^ ]*\|st.\)$/\1/p' \
+        | sort
+]],[0],[expout])
+
+AT_CLEANUP
+
 # foo.o and bar.o are build with relative paths and so will use the
 # comp_dir (from .debug_info). But bar.o is build from sources with
 # an absolute path, so the .debug_line Directory Table should contain
index ceae7b211d95d113e3ee42dff6890e68f610c719..c2884933c2e4e9dd7040a41e82c1e47f23094043 100644 (file)
@@ -433,7 +433,8 @@ typedef struct debug_section
     int sec, relsec;
     REL *relbuf;
     REL *relend;
-    struct debug_section *next; /* Only happens for COMDAT .debug_macro.  */
+    /* Only happens for COMDAT .debug_macro and .debug_types.  */
+    struct debug_section *next;
   } debug_section;
 
 static debug_section debug_sections[] =
@@ -1269,7 +1270,9 @@ static int dirty_elf;
 static void
 dirty_section (unsigned int sec)
 {
-  elf_flagdata (debug_sections[sec].elf_data, ELF_C_SET, ELF_F_DIRTY);
+  for (struct debug_section *secp = &debug_sections[sec]; secp != NULL;
+       secp = secp->next)
+    elf_flagdata (secp->elf_data, ELF_C_SET, ELF_F_DIRTY);
   dirty_elf = 1;
 }
 
@@ -1469,12 +1472,7 @@ read_dwarf2_line (DSO *dso, uint32_t off, char *comp_dir)
 
   if (get_line_table (dso, off, &table) == false
       || table == NULL)
-    {
-      if (table != NULL)
-       error (0, 0, ".debug_line offset 0x%x referenced multiple times",
-              off);
-      return false;
-    }
+    return false;
 
   /* Skip to the directory table. The rest of the header has already
      been read and checked by get_line_table. */
@@ -1965,22 +1963,25 @@ line_rel_cmp (const void *a, const void *b)
 }
 
 static int
-edit_info (DSO *dso, int phase)
+edit_info (DSO *dso, int phase, struct debug_section *sec)
 {
   unsigned char *ptr, *endcu, *endsec;
   uint32_t value;
   htab_t abbrev;
   struct abbrev_tag tag, *t;
 
-  ptr = debug_sections[DEBUG_INFO].data;
-  setup_relbuf(dso, &debug_sections[DEBUG_INFO], &reltype);
-  endsec = ptr + debug_sections[DEBUG_INFO].size;
+  ptr = sec->data;
+  if (ptr == NULL)
+    return 0;
+
+  setup_relbuf(dso, sec, &reltype);
+  endsec = ptr + sec->size;
   while (ptr < endsec)
     {
-      if (ptr + 11 > endsec)
+      if (ptr + (sec == &debug_sections[DEBUG_INFO] ? 11 : 23) > endsec)
        {
-         error (0, 0, "%s: .debug_info CU header too small",
-                dso->filename);
+         error (0, 0, "%s: %s CU header too small",
+                dso->filename, sec->name);
          return 1;
        }
 
@@ -1994,7 +1995,7 @@ edit_info (DSO *dso, int phase)
 
       if (endcu > endsec)
        {
-         error (0, 0, "%s: .debug_info too small", dso->filename);
+         error (0, 0, "%s: %s too small", dso->filename, sec->name);
          return 1;
        }
 
@@ -2034,6 +2035,9 @@ edit_info (DSO *dso, int phase)
          return 1;
        }
 
+      if (sec != &debug_sections[DEBUG_INFO])
+       ptr += 12; /* Skip type_signature and type_offset.  */
+
       abbrev = read_abbrev (dso,
                            debug_sections[DEBUG_ABBREV].data + value);
       if (abbrev == NULL)
@@ -2095,7 +2099,7 @@ edit_dwarf2 (DSO *dso)
                  struct debug_section *debug_sec = &debug_sections[j];
                  if (debug_sections[j].data)
                    {
-                     if (j != DEBUG_MACRO)
+                     if (j != DEBUG_MACRO && j != DEBUG_TYPES)
                        {
                          error (0, 0, "%s: Found two copies of %s section",
                                 dso->filename, name);
@@ -2103,22 +2107,21 @@ edit_dwarf2 (DSO *dso)
                        }
                      else
                        {
-                         /* In relocatable files .debug_macro might
-                            appear multiple times as COMDAT
-                            section.  */
+                         /* In relocatable files .debug_macro and .debug_types
+                            might appear multiple times as COMDAT section.  */
                          struct debug_section *sec;
                          sec = calloc (sizeof (struct debug_section), 1);
                          if (sec == NULL)
                            error (1, errno,
-                                  "%s: Could not allocate more macro sections",
-                                  dso->filename);
-                         sec->name = ".debug_macro";
+                                  "%s: Could not allocate more %s sections",
+                                  dso->filename, name);
+                         sec->name = name;
 
-                         struct debug_section *macro_sec = debug_sec;
-                         while (macro_sec->next != NULL)
-                           macro_sec = macro_sec->next;
+                         struct debug_section *multi_sec = debug_sec;
+                         while (multi_sec->next != NULL)
+                           multi_sec = multi_sec->next;
 
-                         macro_sec->next = sec;
+                         multi_sec->next = sec;
                          debug_sec = sec;
                        }
                    }
@@ -2155,23 +2158,23 @@ edit_dwarf2 (DSO *dso)
                          + (dso->shdr[i].sh_type == SHT_RELA),
                          debug_sections[j].name) == 0)
                {
-                 if (j == DEBUG_MACRO)
+                 if (j == DEBUG_MACRO || j == DEBUG_TYPES)
                    {
                      /* Pick the correct one.  */
                      int rel_target = dso->shdr[i].sh_info;
-                     struct debug_section *macro_sec = &debug_sections[j];
-                     while (macro_sec != NULL)
+                     struct debug_section *multi_sec = &debug_sections[j];
+                     while (multi_sec != NULL)
                        {
-                         if (macro_sec->sec == rel_target)
+                         if (multi_sec->sec == rel_target)
                            {
-                             macro_sec->relsec = i;
+                             multi_sec->relsec = i;
                              break;
                            }
-                         macro_sec = macro_sec->next;
+                         multi_sec = multi_sec->next;
                        }
-                     if (macro_sec == NULL)
-                       error (0, 1, "No .debug_macro reloc section: %s",
-                              dso->filename);
+                     if (multi_sec == NULL)
+                       error (0, 1, "No %s reloc section: %s",
+                              debug_sections[j].name, dso->filename);
                    }
                  else
                    debug_sections[j].relsec = i;
@@ -2203,12 +2206,10 @@ edit_dwarf2 (DSO *dso)
   if (debug_sections[DEBUG_INFO].data == NULL)
     return 0;
 
-  unsigned char *ptr, *endcu, *endsec;
-  uint32_t value;
-  htab_t abbrev;
-  struct abbrev_tag tag, *t;
+  unsigned char *ptr, *endsec;
   int phase;
   bool info_rel_updated = false;
+  bool types_rel_updated = false;
   bool macro_rel_updated = false;
 
   for (phase = 0; phase < 2; phase++)
@@ -2221,13 +2222,26 @@ edit_dwarf2 (DSO *dso)
        break;
 
       rel_updated = false;
-      if (edit_info (dso, phase))
-       return 1;
+      if (edit_info (dso, phase, &debug_sections[DEBUG_INFO]))
+       return 1;
 
       /* Remember whether any .debug_info relocations might need
         to be updated. */
       info_rel_updated = rel_updated;
 
+      rel_updated = false;
+      struct debug_section *types_sec = &debug_sections[DEBUG_TYPES];
+      while (types_sec != NULL)
+       {
+         if (edit_info (dso, phase, types_sec))
+           return 1;
+         types_sec = types_sec->next;
+       }
+
+      /* Remember whether any .debug_types relocations might need
+        to be updated. */
+      types_rel_updated = rel_updated;
+
       /* We might have to recalculate/rewrite the debug_line
         section.  We need to do that before going into phase one
         so we have all new offsets.  We do this separately from
@@ -2475,8 +2489,11 @@ edit_dwarf2 (DSO *dso)
 
   /* After phase 1 we might have rewritten the debug_info with
      new strp, strings and/or linep offsets.  */
-  if (need_strp_update || need_string_replacement || need_stmt_update)
+  if (need_strp_update || need_string_replacement || need_stmt_update) {
     dirty_section (DEBUG_INFO);
+    if (debug_sections[DEBUG_TYPES].data != NULL)
+      dirty_section (DEBUG_TYPES);
+  }
   if (need_strp_update || need_stmt_update)
     dirty_section (DEBUG_MACRO);
   if (need_stmt_update)
@@ -2485,6 +2502,15 @@ edit_dwarf2 (DSO *dso)
   /* Update any relocations addends we might have touched. */
   if (info_rel_updated)
     update_rela_data (dso, &debug_sections[DEBUG_INFO]);
+  if (types_rel_updated)
+    {
+      struct debug_section *types_sec = &debug_sections[DEBUG_TYPES];
+      while (types_sec != NULL)
+       {
+         update_rela_data (dso, types_sec);
+         types_sec = types_sec->next;
+       }
+    }
 
   if (macro_rel_updated)
     {
@@ -3036,6 +3062,17 @@ main (int argc, char *argv[])
       macro_sec = next;
     }
 
+  /* In case there were multiple (COMDAT) .debug_types sections,
+     free them.  */
+  struct debug_section *types_sec = &debug_sections[DEBUG_TYPES];
+  types_sec = types_sec->next;
+  while (types_sec != NULL)
+    {
+      struct debug_section *next = types_sec->next;
+      free (types_sec);
+      types_sec = next;
+    }
+
   poptFreeContext (optCon);
 
   return 0;
This page took 0.072296 seconds and 5 git commands to generate.