Add ability to follow dwo links to readelf/objdump.
authorNick Clifton <nickc@redhat.com>
Tue, 21 Nov 2017 13:12:04 +0000 (13:12 +0000)
committerNick Clifton <nickc@redhat.com>
Tue, 21 Nov 2017 13:12:04 +0000 (13:12 +0000)
* dwarf.c (dwo_name, dwo_dir, dwo_id, dwo_id_len): New variables.
(read_and_display_attr_value): Record dwo variables if requested.
(display_augmentation_data): Rename to display_data and make
generic.
(load_dwo_file): New function.  Loads a separate dwarf object
file.
(load_separate_debug_file): Add reporting and loading of separate
dwarf objet files.
* readelf.c (process_section_headers): Add do_debug_links to list
of flags requiring a debug dump.
(display_debug_section): Tidy up code.
* doc/debug.options.texi: Add note that dwo links will also be
followed.
* testsuite/binutils-all/debuglink.s: Tidy code.
* testsuite/binutils-all/dwo.s: New test file.
* testsuite/binutils-all/readelf.wk2: New file - expected output
from readelf.
* testsuite/binutils-all/readelf.exp: Run the new test.

binutils/ChangeLog
binutils/doc/debug.options.texi
binutils/dwarf.c
binutils/readelf.c
binutils/testsuite/binutils-all/debuglink.s
binutils/testsuite/binutils-all/dwo.s [new file with mode: 0644]
binutils/testsuite/binutils-all/readelf.exp
binutils/testsuite/binutils-all/readelf.k2 [new file with mode: 0644]

index 2f4c0d80a5b7c1e7d8b7af40ed361c26e436800f..c6a20e100583ec51a250333add24e5560a238506 100644 (file)
@@ -1,3 +1,24 @@
+2017-11-21  Nick Clifton  <nickc@redhat.com>
+
+       * dwarf.c (dwo_name, dwo_dir, dwo_id, dwo_id_len): New variables.
+       (read_and_display_attr_value): Record dwo variables if requested.
+       (display_augmentation_data): Rename to display_data and make
+       generic.
+       (load_dwo_file): New function.  Loads a separate dwarf object
+       file.
+       (load_separate_debug_file): Add reporting and loading of separate
+       dwarf objet files.
+       * readelf.c (process_section_headers): Add do_debug_links to list
+       of flags requiring a debug dump.
+       (display_debug_section): Tidy up code.
+       * doc/debug.options.texi: Add note that dwo links will also be
+       followed.
+       * testsuite/binutils-all/debuglink.s: Tidy code.
+       * testsuite/binutils-all/dwo.s: New test file.
+       * testsuite/binutils-all/readelf.wk2: New file - expected output
+       from readelf.
+       * testsuite/binutils-all/readelf.exp: Run the new test.
+
 2017-11-18  Alan Modra  <amodra@gmail.com>
 
        PR 22443
 2017-11-18  Alan Modra  <amodra@gmail.com>
 
        PR 22443
index 9204b2bec4ab64cf52d77a7bf521a13c9afb1e17..57945654d2d86fb0abcc05f16adbe1da2c965521 100644 (file)
@@ -45,7 +45,10 @@ output from this option can also be restricted by the use of the
 @item k
 @itemx =links
 Displays the contents of the @samp{.gnu_debuglink} and/or
 @item k
 @itemx =links
 Displays the contents of the @samp{.gnu_debuglink} and/or
-@samp{.gnu_debugaltlink} sections.
+@samp{.gnu_debugaltlink} sections.  Also displays the link to a
+separate dwarf object file (dwo), if one is specified by the 
+DW_AT_GNU_dwo_name or DW_AT_dwo_name attributes in the
+@samp{.debug_info} section.
 
 @item K
 @itemx =follow-links
 
 @item K
 @itemx =follow-links
@@ -55,9 +58,9 @@ versions of the same debug section being displayed if both the main
 file and the separate debug info file contain sections with the same
 name.
 
 file and the separate debug info file contain sections with the same
 name.
 
-When displaying other debug information, if a link is encountered to
-a separate debug info file, then attempt to follow the link and
-display the referenced contents.
+In addition, when displaying DWARF attributes, if a form is found that
+references the separate debug info file, then the referenced contents
+will also be displayed.
 
 @item l
 @itemx =rawline
 
 @item l
 @itemx =rawline
index e6f6a43ef6bda2117bbb7698c337bd2bcbd79880..8b968797af5c4275add5e79a8bf4fd2d5a209eba 100644 (file)
@@ -48,6 +48,12 @@ static debug_info *debug_information = NULL;
    that the .debug_info section could not be loaded/parsed.  */
 #define DEBUG_INFO_UNAVAILABLE  (unsigned int) -1
 
    that the .debug_info section could not be loaded/parsed.  */
 #define DEBUG_INFO_UNAVAILABLE  (unsigned int) -1
 
+static const char *           dwo_name;
+static const char *           dwo_dir;
+static const unsigned char *  dwo_id;
+static bfd_size_type          dwo_id_len;
+static bfd_boolean            need_dwo_info;
+
 unsigned int eh_addr_size;
 
 int do_debug_info;
 unsigned int eh_addr_size;
 
 int do_debug_info;
@@ -731,7 +737,7 @@ fetch_indirect_line_string (dwarf_vma offset)
 
 static const char *
 fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set,
 
 static const char *
 fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set,
-                     dwarf_vma offset_size, int dwo)
+                     dwarf_vma offset_size, bfd_boolean dwo)
 {
   enum dwarf_section_display_enum str_sec_idx = dwo ? str_dwo : str;
   enum dwarf_section_display_enum idx_sec_idx = dwo ? str_index_dwo : str_index;
 {
   enum dwarf_section_display_enum str_sec_idx = dwo ? str_dwo : str;
   enum dwarf_section_display_enum idx_sec_idx = dwo ? str_index_dwo : str_index;
@@ -1369,21 +1375,21 @@ decode_location_expression (unsigned char * data,
          printf ("DW_OP_push_object_address");
          break;
        case DW_OP_call2:
          printf ("DW_OP_push_object_address");
          break;
        case DW_OP_call2:
-         /* XXX: Strictly speaking for 64-bit DWARF3 files
+         /* FIXME: Strictly speaking for 64-bit DWARF3 files
             this ought to be an 8-byte wide computation.  */
          SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 2, end);
          printf ("DW_OP_call2: <0x%s>",
                  dwarf_vmatoa ("x", svalue + cu_offset));
          break;
        case DW_OP_call4:
             this ought to be an 8-byte wide computation.  */
          SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 2, end);
          printf ("DW_OP_call2: <0x%s>",
                  dwarf_vmatoa ("x", svalue + cu_offset));
          break;
        case DW_OP_call4:
-         /* XXX: Strictly speaking for 64-bit DWARF3 files
+         /* FIXME: Strictly speaking for 64-bit DWARF3 files
             this ought to be an 8-byte wide computation.  */
          SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 4, end);
          printf ("DW_OP_call4: <0x%s>",
                  dwarf_vmatoa ("x", svalue + cu_offset));
          break;
        case DW_OP_call_ref:
             this ought to be an 8-byte wide computation.  */
          SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 4, end);
          printf ("DW_OP_call4: <0x%s>",
                  dwarf_vmatoa ("x", svalue + cu_offset));
          break;
        case DW_OP_call_ref:
-         /* XXX: Strictly speaking for 64-bit DWARF3 files
+         /* FIXME: Strictly speaking for 64-bit DWARF3 files
             this ought to be an 8-byte wide computation.  */
          if (dwarf_version == -1)
            {
             this ought to be an 8-byte wide computation.  */
          if (dwarf_version == -1)
            {
@@ -1452,7 +1458,7 @@ decode_location_expression (unsigned char * data,
          break;
        case DW_OP_implicit_pointer:
        case DW_OP_GNU_implicit_pointer:
          break;
        case DW_OP_implicit_pointer:
        case DW_OP_GNU_implicit_pointer:
-         /* XXX: Strictly speaking for 64-bit DWARF3 files
+         /* FIXME: Strictly speaking for 64-bit DWARF3 files
             this ought to be an 8-byte wide computation.  */
          if (dwarf_version == -1)
            {
             this ought to be an 8-byte wide computation.  */
          if (dwarf_version == -1)
            {
@@ -1713,6 +1719,32 @@ fetch_alt_indirect_string (dwarf_vma offset)
   return ret;
 }
        
   return ret;
 }
        
+static const char *
+get_AT_name (unsigned long attribute)
+{
+  const char *name;
+
+  if (attribute == 0)
+    return "DW_AT value: 0";
+
+  /* One value is shared by the MIPS and HP extensions:  */
+  if (attribute == DW_AT_MIPS_fde)
+    return "DW_AT_MIPS_fde or DW_AT_HP_unmodifiable";
+
+  name = get_DW_AT_name (attribute);
+
+  if (name == NULL)
+    {
+      static char buffer[100];
+
+      snprintf (buffer, sizeof (buffer), _("Unknown AT value: %lx"),
+               attribute);
+      return buffer;
+    }
+
+  return name;
+}
+
 static unsigned char *
 read_and_display_attr_value (unsigned long           attribute,
                             unsigned long           form,
 static unsigned char *
 read_and_display_attr_value (unsigned long           attribute,
                             unsigned long           form,
@@ -2036,8 +2068,8 @@ read_and_display_attr_value (unsigned long           attribute,
     case DW_FORM_GNU_str_index:
       if (!do_loc)
        {
     case DW_FORM_GNU_str_index:
       if (!do_loc)
        {
-         const char *suffix = strrchr (section->name, '.');
-         int dwo = (suffix && strcmp (suffix, ".dwo") == 0) ? 1 : 0;
+         const char * suffix = strrchr (section->name, '.');
+         bfd_boolean  dwo = (suffix && strcmp (suffix, ".dwo") == 0) ? TRUE : FALSE;
 
          printf (_("%c(indexed string: 0x%s): %s"), delimiter,
                  dwarf_vmatoa ("x", uvalue),
 
          printf (_("%c(indexed string: 0x%s): %s"), delimiter,
                  dwarf_vmatoa ("x", uvalue),
@@ -2188,6 +2220,69 @@ read_and_display_attr_value (unsigned long           attribute,
            }
          break;
 
            }
          break;
 
+       case DW_AT_GNU_dwo_name:
+       case DW_AT_dwo_name:
+         if (need_dwo_info)
+           switch (form)
+             {
+             case DW_FORM_strp:
+               dwo_name = (const char *) fetch_indirect_string (uvalue);
+               break;
+             case DW_FORM_GNU_str_index:
+               dwo_name = fetch_indexed_string (uvalue, this_set, offset_size, FALSE);
+               break;
+             case DW_FORM_string:
+               dwo_name = (const char *) orig_data;
+               break;
+             default:
+               warn (_("Unsupported form (%s) for attribute %s\n"),
+                     get_FORM_name (form), get_AT_name (attribute));
+               dwo_name = _("<unknown>");
+               break;
+             }
+         break;
+             
+       case DW_AT_comp_dir:
+         /* FIXME: Also extract a build-id in a CU/TU.  */
+         if (need_dwo_info)
+           switch (form)
+             {
+             case DW_FORM_strp:
+               dwo_dir = (const char *) fetch_indirect_string (uvalue);
+               break;
+             case DW_FORM_line_strp:
+               dwo_dir = (const char *) fetch_indirect_line_string (uvalue);
+               break;
+             case DW_FORM_GNU_str_index:
+               dwo_dir = fetch_indexed_string (uvalue, this_set, offset_size, FALSE);
+               break;
+             case DW_FORM_string:
+               dwo_dir = (const char *) orig_data;
+               break;
+             default:
+               warn (_("Unsupported form (%s) for attribute %s\n"),
+                     get_FORM_name (form), get_AT_name (attribute));
+               dwo_dir = _("<unknown>");
+               break;
+             }
+         break;
+             
+       case DW_AT_GNU_dwo_id:
+         if (need_dwo_info)
+           switch (form)
+             {
+             case DW_FORM_data8:
+               dwo_id = data - 8;
+               dwo_id_len = 8;
+               break;
+             default:
+               warn (_("Unsupported form (%s) for attribute %s\n"),
+                     get_FORM_name (form), get_AT_name (attribute));
+               dwo_id = NULL;
+               break;
+             }
+         break;
+             
        default:
          break;
        }
        default:
          break;
        }
@@ -2540,32 +2635,6 @@ read_and_display_attr_value (unsigned long           attribute,
   return data;
 }
 
   return data;
 }
 
-static const char *
-get_AT_name (unsigned long attribute)
-{
-  const char *name;
-
-  if (attribute == 0)
-    return "DW_AT value: 0";
-
-  /* One value is shared by the MIPS and HP extensions:  */
-  if (attribute == DW_AT_MIPS_fde)
-    return "DW_AT_MIPS_fde or DW_AT_HP_unmodifiable";
-
-  name = get_DW_AT_name (attribute);
-
-  if (name == NULL)
-    {
-      static char buffer[100];
-
-      snprintf (buffer, sizeof (buffer), _("Unknown AT value: %lx"),
-               attribute);
-      return buffer;
-    }
-
-  return name;
-}
-
 static unsigned char *
 read_and_display_attr (unsigned long           attribute,
                       unsigned long           form,
 static unsigned char *
 read_and_display_attr (unsigned long           attribute,
                       unsigned long           form,
@@ -2642,17 +2711,22 @@ introduce (struct dwarf_section * section, bfd_boolean raw)
     }
 }
   
     }
 }
   
-/* Process the contents of a .debug_info section.  If do_loc is non-zero
-   then we are scanning for location lists and we do not want to display
-   anything to the user.  If do_types is non-zero, we are processing
-   a .debug_types section instead of a .debug_info section.  */
+/* Process the contents of a .debug_info section.
+   If do_loc is TRUE then we are scanning for location lists and dwo tags
+   and we do not want to display anything to the user.
+   If do_types is TRUE, we are processing a .debug_types section instead of
+   a .debug_info section.
+   The information displayed is restricted by the values in DWARF_START_DIE
+   and DWARF_CUTOFF_LEVEL.
+   Returns TRUE upon success.  Otherwise an error or warning message is
+   printed and FALSE is returned.  */
 
 
-static int
-process_debug_info (struct dwarf_section *section,
-                   void *file,
-                   enum dwarf_section_display_enum abbrev_sec,
-                   int do_loc,
-                   int do_types)
+static bfd_boolean
+process_debug_info (struct dwarf_section *           section,
+                   void *                           file,
+                   enum dwarf_section_display_enum  abbrev_sec,
+                   bfd_boolean                      do_loc,
+                   bfd_boolean                      do_types)
 {
   unsigned char *start = section->start;
   unsigned char *end = start + section->size;
 {
   unsigned char *start = section->start;
   unsigned char *end = start + section->size;
@@ -2684,7 +2758,7 @@ process_debug_info (struct dwarf_section *section,
            {
              warn (_("Reserved length value (0x%s) found in section %s\n"),
                    dwarf_vmatoa ("x", length), section->name);
            {
              warn (_("Reserved length value (0x%s) found in section %s\n"),
                    dwarf_vmatoa ("x", length), section->name);
-             return 0;
+             return FALSE;
            }
          else
            section_begin += length + 4;
            }
          else
            section_begin += length + 4;
@@ -2696,14 +2770,14 @@ process_debug_info (struct dwarf_section *section,
            {
              warn (_("Corrupt unit length (0x%s) found in section %s\n"),
                    dwarf_vmatoa ("x", length), section->name);
            {
              warn (_("Corrupt unit length (0x%s) found in section %s\n"),
                    dwarf_vmatoa ("x", length), section->name);
-             return 0;
+             return FALSE;
            }
        }
 
       if (num_units == 0)
        {
          error (_("No comp units in %s section ?\n"), section->name);
            }
        }
 
       if (num_units == 0)
        {
          error (_("No comp units in %s section ?\n"), section->name);
-         return 0;
+         return FALSE;
        }
 
       /* Then allocate an array to hold the information.  */
        }
 
       /* Then allocate an array to hold the information.  */
@@ -2714,8 +2788,9 @@ process_debug_info (struct dwarf_section *section,
          error (_("Not enough memory for a debug info array of %u entries\n"),
                 num_units);
          alloc_num_debug_info_entries = num_debug_info_entries = 0;
          error (_("Not enough memory for a debug info array of %u entries\n"),
                 num_units);
          alloc_num_debug_info_entries = num_debug_info_entries = 0;
-         return 0;
+         return FALSE;
        }
        }
+
       /* PR 17531: file: 92ca3797.
         We cannot rely upon the debug_information array being initialised
         before it is used.  A corrupt file could easily contain references
       /* PR 17531: file: 92ca3797.
         We cannot rely upon the debug_information array being initialised
         before it is used.  A corrupt file could easily contain references
@@ -2741,7 +2816,7 @@ process_debug_info (struct dwarf_section *section,
     {
       warn (_("Unable to locate %s section!\n"),
            debug_displays [abbrev_sec].section.uncompressed_name);
     {
       warn (_("Unable to locate %s section!\n"),
            debug_displays [abbrev_sec].section.uncompressed_name);
-      return 0;
+      return FALSE;
     }
 
   if (!do_loc && dwarf_start_die == 0)
     }
 
   if (!do_loc && dwarf_start_die == 0)
@@ -3008,7 +3083,7 @@ process_debug_info (struct dwarf_section *section,
                    }
                }
              if (dwarf_start_die != 0 && level < saved_level)
                    }
                }
              if (dwarf_start_die != 0 && level < saved_level)
-               return 1;
+               return TRUE;
              continue;
            }
 
              continue;
            }
 
@@ -3048,7 +3123,7 @@ process_debug_info (struct dwarf_section *section,
                }
              warn (_("DIE at offset 0x%lx refers to abbreviation number %lu which does not exist\n"),
                    die_offset, abbrev_number);
                }
              warn (_("DIE at offset 0x%lx refers to abbreviation number %lu which does not exist\n"),
                    die_offset, abbrev_number);
-             return 0;
+             return FALSE;
            }
 
          if (!do_loc && do_printing)
            }
 
          if (!do_loc && do_printing)
@@ -3060,7 +3135,8 @@ process_debug_info (struct dwarf_section *section,
              need_base_address = 0;
              break;
            case DW_TAG_compile_unit:
              need_base_address = 0;
              break;
            case DW_TAG_compile_unit:
-             need_base_address = 1;
+             need_base_address = 1;    
+             need_dwo_info = do_loc;
              break;
            case DW_TAG_entry_point:
            case DW_TAG_subprogram:
              break;
            case DW_TAG_entry_point:
            case DW_TAG_subprogram:
@@ -3146,7 +3222,7 @@ process_debug_info (struct dwarf_section *section,
   if (!do_loc)
     printf ("\n");
 
   if (!do_loc)
     printf ("\n");
 
-  return 1;
+  return TRUE;
 }
 
 /* Locate and scan the .debug_info section in the file and record the pointer
 }
 
 /* Locate and scan the .debug_info section in the file and record the pointer
@@ -3171,12 +3247,12 @@ load_debug_info (void * file)
   (void) load_cu_tu_indexes (file);
 
   if (load_debug_section_with_follow (info, file)
   (void) load_cu_tu_indexes (file);
 
   if (load_debug_section_with_follow (info, file)
-      && process_debug_info (&debug_displays [info].section, file, abbrev, 1, 0))
+      && process_debug_info (&debug_displays [info].section, file, abbrev, TRUE, FALSE))
     return num_debug_info_entries;
 
   if (load_debug_section_with_follow (info_dwo, file)
       && process_debug_info (&debug_displays [info_dwo].section, file,
     return num_debug_info_entries;
 
   if (load_debug_section_with_follow (info_dwo, file)
       && process_debug_info (&debug_displays [info_dwo].section, file,
-                            abbrev_dwo, 1, 0))
+                            abbrev_dwo, TRUE, FALSE))
     return num_debug_info_entries;
 
   num_debug_info_entries = DEBUG_INFO_UNAVAILABLE;
     return num_debug_info_entries;
 
   num_debug_info_entries = DEBUG_INFO_UNAVAILABLE;
@@ -6161,19 +6237,19 @@ display_debug_str (struct dwarf_section *section,
 static int
 display_debug_info (struct dwarf_section *section, void *file)
 {
 static int
 display_debug_info (struct dwarf_section *section, void *file)
 {
-  return process_debug_info (section, file, section->abbrev_sec, 0, 0);
+  return process_debug_info (section, file, section->abbrev_sec, FALSE, FALSE);
 }
 
 static int
 display_debug_types (struct dwarf_section *section, void *file)
 {
 }
 
 static int
 display_debug_types (struct dwarf_section *section, void *file)
 {
-  return process_debug_info (section, file, section->abbrev_sec, 0, 1);
+  return process_debug_info (section, file, section->abbrev_sec, FALSE, TRUE);
 }
 
 static int
 display_trace_info (struct dwarf_section *section, void *file)
 {
 }
 
 static int
 display_trace_info (struct dwarf_section *section, void *file)
 {
-  return process_debug_info (section, file, section->abbrev_sec, 0, 0);
+  return process_debug_info (section, file, section->abbrev_sec, FALSE, TRUE);
 }
 
 static int
 }
 
 static int
@@ -7227,29 +7303,40 @@ read_cie (unsigned char *start, unsigned char *end,
   return start;
 }
 
   return start;
 }
 
-/* Prints out the contents on the augmentation data array.
-   If do_wide is not enabled, then formats the output to fit into 80 columns.  */
+/* Prints out the contents on the DATA array formatted as unsigned bytes.
+   If do_wide is not enabled, then formats the output to fit into 80 columns.
+   PRINTED contains the number of characters already written to the current
+   output line.  */
 
 static void
 
 static void
-display_augmentation_data (const unsigned char * data, const bfd_size_type len)
+display_data (bfd_size_type          printed,
+             const unsigned char *  data,
+             const bfd_size_type    len)
 {
 {
-  bfd_size_type i;
-
-  i = printf (_("  Augmentation data:    "));
-
-  if (do_wide || len < ((80 - i) / 3))
-    for (i = 0; i < len; ++i)
-      printf (" %02x", data[i]);
+  if (do_wide || len < ((80 - printed) / 3))
+    for (printed = 0; printed < len; ++printed)
+      printf (" %02x", data[printed]);
   else
     {
   else
     {
-      for (i = 0; i < len; ++i)
+      for (printed = 0; printed < len; ++printed)
        {
        {
-         if (i % (80 / 3) == 0)
+         if (printed % (80 / 3) == 0)
            putchar ('\n');
            putchar ('\n');
-         printf (" %02x", data[i]);
+         printf (" %02x", data[printed]);
        }
     }
        }
     }
-  putchar ('\n');
+}
+
+/* Prints out the contents on the augmentation data array.
+   If do_wide is not enabled, then formats the output to fit into 80 columns.  */
+
+static void
+display_augmentation_data (const unsigned char * data, const bfd_size_type len)
+{
+  bfd_size_type i;
+
+  i = printf (_("  Augmentation data:    "));
+  display_data (i, data, len);
 }
 
 static int
 }
 
 static int
@@ -8550,8 +8637,8 @@ display_debug_names (struct dwarf_section *section, void *file)
 }
 
 static int
 }
 
 static int
-display_debug_links (struct dwarf_section * section,
-                    void * file ATTRIBUTE_UNUSED)
+display_debug_links (struct dwarf_section *  section,
+                    void *                  file ATTRIBUTE_UNUSED)
 {
   const unsigned char * filename;
   unsigned int          filelen;
 {
   const unsigned char * filename;
   unsigned int          filelen;
@@ -8615,19 +8702,7 @@ display_debug_links (struct dwarf_section * section,
        }
 
       printed = printf (_("  Build-ID (%#lx bytes):"), (long) build_id_len);
        }
 
       printed = printf (_("  Build-ID (%#lx bytes):"), (long) build_id_len);
-
-      if (do_wide || build_id_len < ((80 - printed) / 3))
-       for (printed = 0; printed < build_id_len; ++printed)
-         printf (" %02x", build_id[printed]);
-      else
-       {
-         for (printed = 0; printed < build_id_len; ++printed)
-           {
-             if (printed % (80 / 3) == 0)
-               putchar ('\n');
-             printf (" %02x", build_id[printed]);
-           }
-       }
+      display_data (printed, build_id, build_id_len);
       putchar ('\n');
     }
 
       putchar ('\n');
     }
 
@@ -9723,21 +9798,84 @@ load_separate_debug_info (const char *            main_filename,
   return separate_debug_file;
 }
 
   return separate_debug_file;
 }
 
+/* Attempt to load a separate dwarf object file.  */
+
+static void *
+load_dwo_file (const char * main_filename)
+{
+  char * filename;
+
+  /* FIXME: Skip adding / if dwo_dir ends in /.  */
+  filename = concat (dwo_dir, "/", dwo_name, NULL);
+  if (filename == NULL)
+    {
+      warn (_("Out of memory allocating dwo filename\n"));
+      return NULL;
+    }
+
+  if ((separate_debug_file = open_debug_file (filename)) == NULL)
+    {
+      warn (_("Unable to load dwo file: %s\n"), filename);
+      free (filename);
+      return NULL;
+    }
+
+  /* FIXME: We should check the dwo_id.  */
+
+  printf (_("%s: Found separate debug object file: %s\n\n"), main_filename, filename);
+  separate_debug_filename = filename;
+  return separate_debug_file;
+}
+
 /* Load a separate debug info file, if it exists.
    Returns the data pointer that is the result of calling open_debug_file
 /* Load a separate debug info file, if it exists.
    Returns the data pointer that is the result of calling open_debug_file
-   on the separate debug info file.  */
+   on the separate debug info file, or NULL if there were problems or there
+   is no such file.  */
 
 void *
 load_separate_debug_file (void * file, const char * filename)
 {
 
 void *
 load_separate_debug_file (void * file, const char * filename)
 {
+  /* See if there is a dwo link.  */
+  if (load_debug_section (str, file)
+      && load_debug_section (abbrev, file)
+      && load_debug_section (info, file))
+    {
+      dwo_name = dwo_dir = NULL;
+      dwo_id = NULL;
+      dwo_id_len = 0;
+
+      if (process_debug_info (& debug_displays[info].section, file, abbrev, TRUE, FALSE))
+       {
+         if (dwo_name != NULL)
+           {
+             if (do_debug_links)
+               {
+                 printf (_("The %s section contains a link to a dwo file:\n"),
+                         debug_displays [info].section.uncompressed_name);
+                 printf (_("  Name:      %s\n"), dwo_name);
+                 printf (_("  Directory: %s\n"), dwo_dir ? dwo_dir : _("<not-found>"));
+                 if (dwo_id != NULL)
+                   display_data (printf (_("  ID:       ")), dwo_id, dwo_id_len);
+                 else
+                   printf (_("  ID: <unknown>\n"));
+                 printf ("\n\n");
+               }
+
+             /* FIXME: We do not check to see if there are any more dwo links in the file...  */
+             if (do_follow_links)
+               return load_dwo_file (filename);
+           }
+       }
+    }
+
   if (! do_follow_links)
     return NULL;
 
   /* FIXME: We do not check for the presence of both link sections in the same file.  */
   /* FIXME: We do not check the separate debug info file to see if it too contains debuglinks.  */
   /* FIXME: We do not check for the presence of multiple, same-name debuglink sections.  */
   if (! do_follow_links)
     return NULL;
 
   /* FIXME: We do not check for the presence of both link sections in the same file.  */
   /* FIXME: We do not check the separate debug info file to see if it too contains debuglinks.  */
   /* FIXME: We do not check for the presence of multiple, same-name debuglink sections.  */
+  /* FIXME: We do not check for the presence of a dwo link as well as a debuglink.  */
 
 
-  /* We try the alt version first as that is blessed by the DWARF5 standard.  */
   if (load_debug_section (gnu_debugaltlink, file))
     {
       Build_id_data * build_id_data;
   if (load_debug_section (gnu_debugaltlink, file))
     {
       Build_id_data * build_id_data;
index a372620c660fb81e19d3d5044497b72f9cea4488..ea7cc3e18eefe110b1fc0b03592346731f8399c8 100644 (file)
@@ -6084,7 +6084,7 @@ process_section_headers (Filedata * filedata)
                || do_debug_lines || do_debug_pubnames || do_debug_pubtypes
                || do_debug_aranges || do_debug_frames || do_debug_macinfo
                || do_debug_str || do_debug_loc || do_debug_ranges
                || do_debug_lines || do_debug_pubnames || do_debug_pubtypes
                || do_debug_aranges || do_debug_frames || do_debug_macinfo
                || do_debug_str || do_debug_loc || do_debug_ranges
-               || do_debug_addr || do_debug_cu_index)
+               || do_debug_addr || do_debug_cu_index || do_debug_links)
               && (const_strneq (name, ".debug_")
                    || const_strneq (name, ".zdebug_")))
        {
               && (const_strneq (name, ".debug_")
                    || const_strneq (name, ".zdebug_")))
        {
@@ -13658,40 +13658,43 @@ display_debug_section (int shndx, Elf_Internal_Shdr * section, Filedata * fileda
 
   /* See if we know how to display the contents of this section.  */
   for (i = 0; i < max; i++)
 
   /* See if we know how to display the contents of this section.  */
   for (i = 0; i < max; i++)
-    if (streq (debug_displays[i].section.uncompressed_name, name)
-       || (i == line && const_strneq (name, ".debug_line."))
-        || streq (debug_displays[i].section.compressed_name, name))
-      {
-       struct dwarf_section * sec = &debug_displays [i].section;
-       int secondary = (section != find_section (filedata, name));
+    {
+      enum dwarf_section_display_enum  id = (enum dwarf_section_display_enum) i;
+      struct dwarf_section_display *   display = debug_displays + i;
+      struct dwarf_section *           sec = & display->section;
 
 
-       if (secondary)
-         free_debug_section ((enum dwarf_section_display_enum) i);
+      if (streq (sec->uncompressed_name, name)
+         || (id == line && const_strneq (name, ".debug_line."))
+         || streq (sec->compressed_name, name))
+       {
+         bfd_boolean secondary = (section != find_section (filedata, name));
 
 
-       if (i == line && const_strneq (name, ".debug_line."))
-         sec->name = name;
-       else if (streq (sec->uncompressed_name, name))
-         sec->name = sec->uncompressed_name;
-       else
-         sec->name = sec->compressed_name;
+         if (secondary)
+           free_debug_section (id);
 
 
-       if (load_specific_debug_section ((enum dwarf_section_display_enum) i,
-                                         section, filedata))
-         {
-           /* If this debug section is part of a CU/TU set in a .dwp file,
-              restrict load_debug_section to the sections in that set.  */
-           section_subset = find_cu_tu_set (filedata, shndx);
+         if (i == line && const_strneq (name, ".debug_line."))
+           sec->name = name;
+         else if (streq (sec->uncompressed_name, name))
+           sec->name = sec->uncompressed_name;
+         else
+           sec->name = sec->compressed_name;
 
 
-           result &= debug_displays[i].display (sec, filedata);
+         if (load_specific_debug_section (id, section, filedata))
+           {
+             /* If this debug section is part of a CU/TU set in a .dwp file,
+                restrict load_debug_section to the sections in that set.  */
+             section_subset = find_cu_tu_set (filedata, shndx);
 
 
-           section_subset = NULL;
+             result &= display->display (sec, filedata);
 
 
-           if (secondary || (i != info && i != abbrev))
-             free_debug_section ((enum dwarf_section_display_enum) i);
-         }
+             section_subset = NULL;
 
 
-       break;
-      }
+             if (secondary || (id != info && id != abbrev))
+               free_debug_section (id);
+           }
+         break;
+       }
+    }
 
   if (i == max)
     {
 
   if (i == max)
     {
index a3691a03c39a603d21f63d560f25a75ac1aca7a4..daabf7a3f1180167a07c494ad1f72334d659343c 100644 (file)
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
        
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
        
-/* Create a fake .gnu_debuglink section.  */
+       /* Create a fake .gnu_debuglink section.  */
 
        .section .gnu_debuglink,"",%progbits
        .asciz "this_is_a_debuglink.debug"
        .balign 4
        .4byte 0x12345678
 
 
        .section .gnu_debuglink,"",%progbits
        .asciz "this_is_a_debuglink.debug"
        .balign 4
        .4byte 0x12345678
 
-/* Create a fake .gnu_debugaltlink section.  */
+       /* Create a fake .gnu_debugaltlink section.  */
 
        .section .gnu_debugaltlink,"",%progbits
        .asciz "linkdebug.debug"
 
        .section .gnu_debugaltlink,"",%progbits
        .asciz "linkdebug.debug"
@@ -32,9 +32,9 @@
        .dc.b 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
        .dc.b 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef
    
        .dc.b 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
        .dc.b 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef
    
-/* Create a .debug_str section for local use.  This is also to check
-   the ability to dump the same section twice, if it exists in
-   both the main file and the separate debug info file.  */
+       /* Create a .debug_str section for local use.  This is also to check
+          the ability to dump the same section twice, if it exists in
+          both the main file and the separate debug info file.  */
 
        .section        .debug_str,"MS",%progbits,1
 string1:
 
        .section        .debug_str,"MS",%progbits,1
 string1:
@@ -43,9 +43,9 @@ string1:
        .balign 2
 string_end:
        
        .balign 2
 string_end:
        
-/* Create a .debug_info section that contains strings references into the
-   separate debug info file.  Plus the abbreviations are stored in the
-   separate file too...  */
+       /* Create a .debug_info section that contains string references into
+          the separate debug info file.  Plus the abbreviations are stored
+          in the separate file too...  */
 
        .section        .debug_info,"",%progbits
        .4byte  debugE - debugS ;# Length of Compilation Unit Info
 
        .section        .debug_info,"",%progbits
        .4byte  debugE - debugS ;# Length of Compilation Unit Info
diff --git a/binutils/testsuite/binutils-all/dwo.s b/binutils/testsuite/binutils-all/dwo.s
new file mode 100644 (file)
index 0000000..0d13471
--- /dev/null
@@ -0,0 +1,84 @@
+/* Assembler source used to create an object file for testing readelf's
+   and objdump's ability to process separate dwarf object files.
+
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+       
+       /* Create a .debug_str section for local use.  This is also to check
+          the ability to dump the same section twice, if it exists in
+          both the main file and the separate debug info file.  */
+
+       .section        .debug_str,"MS",%progbits,1
+string1:
+       .asciz  "debugfile.dwo"
+string2:
+       .asciz  "/path/to/dwo/files"
+string3:
+       .asciz  "/another/path/"
+       .balign 2
+string_end:
+       
+       /* Create a .debug_info section that contains the dwo links.  */
+
+       .section        .debug_info,"",%progbits
+       .4byte  debugE - debugS ;# Length of Compilation Unit Info
+debugS:
+       .short  0x4     ;# DWARF version number.
+       .4byte  0x0     ;# Offset into .debug_abbrev section.
+       .byte   0x4     ;# Pointer Size (in bytes).
+
+       .uleb128 0x1    ;# Use abbrev #1.  This needs strings from the .debug_str section.
+       .4byte  string1
+       .4byte  string2
+
+       .uleb128 0x2    ;# Use abbrev #2.
+       .asciz   "file.dwo"
+       .4byte   string3
+       .8byte   0x12345678aabbccdd
+
+       ;# Minimal section alignment on alpha-* is 2, so ensure no new invalid CU
+       ;# will be started.
+       .balign 2, 0
+debugE:
+
+       .section        .debug_abbrev,"",%progbits
+
+       /* Create an abbrev containing a DWARF5 style dwo link.  */
+       .uleb128 0x01   ;# Abbrev code.
+       .uleb128 0x11   ;# DW_TAG_compile_unit
+       .byte    0x00   ;# DW_children_no
+       .uleb128 0x76   ;# DW_AT_dwo_name
+       .uleb128 0x0e   ;# DW_FORM_strp
+       .uleb128 0x1b   ;# DW_AT_comp_dir
+       .uleb128 0x0e   ;# DW_FORM_strp
+       .byte    0x00   ;# End of abbrev
+       .byte    0x00
+
+       /* Create an abbrev containing a GNU style dwo link.  */
+       .uleb128 0x02   ;# Abbrev code.
+       .uleb128 0x11   ;# DW_TAG_compile_unit
+       .byte    0x00   ;# DW_children_no
+       .uleb128 0x2130 ;# DW_AT_GNU_dwo_name
+       .uleb128 0x08   ;# DW_FORM_string
+       .uleb128 0x1b   ;# DW_AT_comp_dir
+       .uleb128 0x0e   ;# DW_FORM_strp
+       .uleb128 0x2131 ;# DW_AT_GNU_dwo_id
+       .uleb128 0x07   ;# DW_FORM_data8        
+       .byte    0x00   ;# End of abbrev
+       .byte    0x00
+
+       .byte    0x0    ;# Abbrevs terminator
+
index fdb310ca193111248fa04b44d055e20bcc30183a..f12625501a97663dbc0c369eaa176ae4b517a472 100644 (file)
@@ -469,7 +469,7 @@ if {![binutils_assemble_flags $srcdir/$subdir/dwarf-attributes.S tmpdir/dwarf-at
 
 # Check that debug link sections can be dumped.
 if {![binutils_assemble $srcdir/$subdir/debuglink.s tmpdir/debuglink.o]} then {
 
 # Check that debug link sections can be dumped.
 if {![binutils_assemble $srcdir/$subdir/debuglink.s tmpdir/debuglink.o]} then {
-    unresolved "readelf --debug-dump=links (failed to assemble)"
+    unresolved "readelf --debug-dump=links (failed to assemble debuglink.s)"
 } else {
     if ![is_remote host] {
        set tempfile tmpdir/debuglink.o
 } else {
     if ![is_remote host] {
        set tempfile tmpdir/debuglink.o
@@ -478,23 +478,29 @@ if {![binutils_assemble $srcdir/$subdir/debuglink.s tmpdir/debuglink.o]} then {
     }
 
     readelf_test {--debug-dump=links} $tempfile readelf.k  {}
     }
 
     readelf_test {--debug-dump=links} $tempfile readelf.k  {}
-}
 
 
-# Check that debug link sections can be followed.
-if {![binutils_assemble $srcdir/$subdir/debuglink.s tmpdir/debuglink.o]} then {
-    unresolved "readelf --debug-dump=follow-links (failed to assemble1)"
-} else {
+    # Check that debug link sections can be followed.
     if {![binutils_assemble $srcdir/$subdir/linkdebug.s tmpdir/linkdebug.debug]} then {
     if {![binutils_assemble $srcdir/$subdir/linkdebug.s tmpdir/linkdebug.debug]} then {
-       unresolved "readelf --debug-dump=follow-links (failed to assemble2)"
+       unresolved "readelf --debug-dump=follow-links (failed to assemble linkdebug.s)"
     } else {
     } else {
-       if ![is_remote host] {
-           set tempfile tmpdir/debuglink.o
-       } else {
-           set tempfile [remote_download host tmpdir/linkdebug.debug]
-           set tempfile [remote_download host tmpdir/debuglink.o]
+       if [is_remote host] {
+           set tempfile2 [remote_download host tmpdir/linkdebug.debug]
        }
 
        readelf_test {-wKis} $tempfile objdump.WK2  {}
     }
 }
 
        }
 
        readelf_test {-wKis} $tempfile objdump.WK2  {}
     }
 }
 
+if {![binutils_assemble $srcdir/$subdir/dwo.s tmpdir/dwo.o]} then {
+    unresolved "readelf --debug-dump=links (failed to assemble dwo.s)"
+} else {
+    if ![is_remote host] {
+       set tempfile tmpdir/dwo.o
+    } else {
+       set tempfile [remote_download host tmpdir/dwo.o]
+    }
+
+    readelf_test {--debug-dump=links} $tempfile readelf.k2  {}
+}
+
+
diff --git a/binutils/testsuite/binutils-all/readelf.k2 b/binutils/testsuite/binutils-all/readelf.k2
new file mode 100644 (file)
index 0000000..89ee4b4
--- /dev/null
@@ -0,0 +1,4 @@
+The \.debug_info section contains a link to a dwo file:
+  Name:      file\.dwo
+  Directory: /another/path/
+  ID:        (12|dd) (34|cc) (56|bb) (78|aa) (78|aa) (56|bb) (34|cc) (12|dd)
This page took 0.054232 seconds and 4 git commands to generate.