[binutils/f19] Add support for the alternative debuging files generated by the DWZ program. Resolves: #965255

Nicholas Clifton nickc at fedoraproject.org
Tue Jun 4 15:14:22 UTC 2013


commit 7c13ae2cad9300c924cd343b76c6709f8cbb0d50
Author: Nick Clifton <nickc at redhat.com>
Date:   Tue Jun 4 16:12:57 2013 +0100

    Add support for the alternative debuging files generated by the DWZ program.
    Resolves: #965255

 binutils-2.23.52.0.1-dwz-alt-debuginfo.patch |  611 ++++++++++++++++++++++++++
 binutils.spec                                |    8 +-
 2 files changed, 618 insertions(+), 1 deletions(-)
---
diff --git a/binutils-2.23.52.0.1-dwz-alt-debuginfo.patch b/binutils-2.23.52.0.1-dwz-alt-debuginfo.patch
new file mode 100644
index 0000000..5f48e7f
--- /dev/null
+++ b/binutils-2.23.52.0.1-dwz-alt-debuginfo.patch
@@ -0,0 +1,611 @@
+diff -cp ../binutils-2.23.52.0.1.orig/bfd/bfd-in2.h bfd/bfd-in2.h
+*** ../binutils-2.23.52.0.1.orig/bfd/bfd-in2.h	2013-06-04 15:26:45.127450022 +0100
+--- bfd/bfd-in2.h	2013-06-04 15:47:45.160484950 +0100
+*************** void *bfd_zalloc (bfd *abfd, bfd_size_ty
+*** 1044,1051 ****
+--- 1044,1055 ----
+  unsigned long bfd_calc_gnu_debuglink_crc32
+     (unsigned long crc, const unsigned char *buf, bfd_size_type len);
+  
++ char *bfd_get_alt_debug_link_info (bfd *abfd, unsigned long *crc32_out);
++ 
+  char *bfd_follow_gnu_debuglink (bfd *abfd, const char *dir);
+  
++ char *bfd_follow_gnu_debugaltlink (bfd *abfd, const char *dir);
++ 
+  struct bfd_section *bfd_create_gnu_debuglink_section
+     (bfd *abfd, const char *filename);
+  
+diff -cp ../binutils-2.23.52.0.1.orig/bfd/dwarf2.c bfd/dwarf2.c
+*** ../binutils-2.23.52.0.1.orig/bfd/dwarf2.c	2013-06-04 15:26:44.556450006 +0100
+--- bfd/dwarf2.c	2013-06-04 15:49:24.921487716 +0100
+*************** struct dwarf2_debug
+*** 108,113 ****
+--- 108,123 ----
+    asection *sec;
+    bfd_byte *sec_info_ptr;
+  
++   /* Support for alternate debug info sections created by the DWZ utility:
++      This includes a pointer to an alternate bfd which contains *extra*,
++      possibly duplicate debug sections, and pointers to the loaded
++      .debug_str and .debug_info sections from this bfd.  */
++   bfd *          alt_bfd_ptr;
++   bfd_byte *     alt_dwarf_str_buffer;
++   bfd_size_type  alt_dwarf_str_size;
++   bfd_byte *     alt_dwarf_info_buffer;
++   bfd_size_type  alt_dwarf_info_size;
++ 
+    /* A pointer to the memory block allocated for info_ptr.  Neither
+       info_ptr nor sec_info_ptr are guaranteed to stay pointing to the
+       beginning of the malloc block.  This is used only to free the
+*************** const struct dwarf_debug_section dwarf_d
+*** 290,295 ****
+--- 300,306 ----
+    { ".debug_aranges",		".zdebug_aranges" },
+    { ".debug_frame",		".zdebug_frame" },
+    { ".debug_info",		".zdebug_info" },
++   { ".debug_info",		".zdebug_info" },
+    { ".debug_line",		".zdebug_line" },
+    { ".debug_loc",		".zdebug_loc" },
+    { ".debug_macinfo",		".zdebug_macinfo" },
+*************** const struct dwarf_debug_section dwarf_d
+*** 300,305 ****
+--- 311,317 ----
+    { ".debug_static_func",	".zdebug_static_func" },
+    { ".debug_static_vars",	".zdebug_static_vars" },
+    { ".debug_str",		".zdebug_str", },
++   { ".debug_str",		".zdebug_str", },
+    { ".debug_types",		".zdebug_types" },
+    /* GNU DWARF 1 extensions */
+    { ".debug_sfnames",		".zdebug_sfnames" },
+*************** const struct dwarf_debug_section dwarf_d
+*** 312,323 ****
+--- 324,338 ----
+    { NULL,			NULL },
+  };
+  
++ /* NB/ Numbers in this enum must match up with indicies
++    into the dwarf_debug_sections[] array above.  */
+  enum dwarf_debug_section_enum
+  {
+    debug_abbrev = 0,
+    debug_aranges,
+    debug_frame,
+    debug_info,
++   debug_info_alt,
+    debug_line,
+    debug_loc,
+    debug_macinfo,
+*************** enum dwarf_debug_section_enum
+*** 328,333 ****
+--- 343,349 ----
+    debug_static_func,
+    debug_static_vars,
+    debug_str,
++   debug_str_alt,
+    debug_types,
+    debug_sfnames,
+    debug_srcinfo,
+*************** read_section (bfd *           abfd,
+*** 484,491 ****
+    asection *msec;
+    const char *section_name = sec->uncompressed_name;
+  
+!   /* read_section is a noop if the section has already been read.  */
+!   if (!*section_buffer)
+      {
+        msec = bfd_get_section_by_name (abfd, section_name);
+        if (! msec)
+--- 500,507 ----
+    asection *msec;
+    const char *section_name = sec->uncompressed_name;
+  
+!   /* The section may have already been read.  */
+!   if (*section_buffer == NULL)
+      {
+        msec = bfd_get_section_by_name (abfd, section_name);
+        if (! msec)
+*************** read_indirect_string (struct comp_unit *
+*** 626,631 ****
+--- 642,745 ----
+    return str;
+  }
+  
++ /* Like read_indirect_string but uses a .debug_str located in
++    an alternate filepointed to by the .gnu_debuglink section.
++    Used to impement DW_FORM_GNU_strp_alt.  */
++ 
++ static char *
++ read_alt_indirect_string (struct comp_unit * unit,
++ 			  bfd_byte *         buf,
++ 			  unsigned int *     bytes_read_ptr)
++ {
++   bfd_uint64_t offset;
++   struct dwarf2_debug *stash = unit->stash;
++   char *str;
++ 
++   if (unit->offset_size == 4)
++     offset = read_4_bytes (unit->abfd, buf);
++   else
++     offset = read_8_bytes (unit->abfd, buf);
++ 
++   *bytes_read_ptr = unit->offset_size;
++ 
++   if (stash->alt_bfd_ptr == NULL)
++     {
++       bfd *  debug_bfd;
++       char * debug_filename = bfd_follow_gnu_debugaltlink (unit->abfd, DEBUGDIR);
++ 
++       if (debug_filename == NULL)
++ 	return NULL;
++ 
++       if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL
++ 	  || ! bfd_check_format (debug_bfd, bfd_object))
++ 	{
++ 	  if (debug_bfd)
++ 	    bfd_close (debug_bfd);
++ 
++ 	  /* FIXME: Should we report our failure to follow the debuglink ?  */
++ 	  free (debug_filename);
++ 	  return NULL;
++ 	}
++       stash->alt_bfd_ptr = debug_bfd;
++     }
++   
++   if (! read_section (unit->stash->alt_bfd_ptr,
++ 		      stash->debug_sections + debug_str_alt,
++ 		      NULL, /* FIXME: Do we need to load alternate symbols ?  */
++ 		      offset,
++ 		      &stash->alt_dwarf_str_buffer,
++ 		      &stash->alt_dwarf_str_size))
++     return NULL;
++ 
++   str = (char *) stash->alt_dwarf_str_buffer + offset;
++   if (*str == '\0')
++     return NULL;
++ 
++   return str;
++ }
++ 
++ /* Resolve an alternate reference from UNIT at OFFSET.
++    Returns a pointer into the loaded alternate CU upon success
++    or NULL upon failure.  */
++ 
++ static bfd_byte *
++ read_alt_indirect_ref (struct comp_unit * unit,
++ 		       bfd_uint64_t       offset)
++ {
++   struct dwarf2_debug *stash = unit->stash;
++ 
++   if (stash->alt_bfd_ptr == NULL)
++     {
++       bfd *  debug_bfd;
++       char * debug_filename = bfd_follow_gnu_debugaltlink (unit->abfd, DEBUGDIR);
++ 
++       if (debug_filename == NULL)
++ 	return FALSE;
++ 
++       if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL
++ 	  || ! bfd_check_format (debug_bfd, bfd_object))
++ 	{
++ 	  if (debug_bfd)
++ 	    bfd_close (debug_bfd);
++ 
++ 	  /* FIXME: Should we report our failure to follow the debuglink ?  */
++ 	  free (debug_filename);
++ 	  return NULL;
++ 	}
++       stash->alt_bfd_ptr = debug_bfd;
++     }
++   
++   if (! read_section (unit->stash->alt_bfd_ptr,
++ 		      stash->debug_sections + debug_info_alt,
++ 		      NULL, /* FIXME: Do we need to load alternate symbols ?  */
++ 		      offset,
++ 		      &stash->alt_dwarf_info_buffer,
++ 		      &stash->alt_dwarf_info_size))
++     return NULL;
++ 
++   return stash->alt_dwarf_info_buffer + offset;
++ }
++ 
+  static bfd_uint64_t
+  read_address (struct comp_unit *unit, bfd_byte *buf)
+  {
+*************** read_attribute_value (struct attribute *
+*** 829,834 ****
+--- 943,949 ----
+        attr->u.val = read_address (unit, info_ptr);
+        info_ptr += unit->addr_size;
+        break;
++     case DW_FORM_GNU_ref_alt:
+      case DW_FORM_sec_offset:
+        if (unit->offset_size == 4)
+  	attr->u.val = read_4_bytes (unit->abfd, info_ptr);
+*************** read_attribute_value (struct attribute *
+*** 878,883 ****
+--- 993,1002 ----
+        attr->u.str = read_indirect_string (unit, info_ptr, &bytes_read);
+        info_ptr += bytes_read;
+        break;
++     case DW_FORM_GNU_strp_alt:
++       attr->u.str = read_alt_indirect_string (unit, info_ptr, &bytes_read);
++       info_ptr += bytes_read;
++       break;
+      case DW_FORM_exprloc:
+      case DW_FORM_block:
+        amt = sizeof (struct dwarf_block);
+*************** find_abstract_instance_name (struct comp
+*** 2009,2014 ****
+--- 2128,2144 ----
+  
+        info_ptr = unit->sec_info_ptr + die_ref;
+      }
++    else if (attr_ptr->form == DW_FORM_GNU_ref_alt)
++      {
++        info_ptr = read_alt_indirect_ref (unit, die_ref);
++        if (info_ptr == NULL)
++  	{
++  	  (*_bfd_error_handler)
++  	    (_("Dwarf Error: Unable to read alt ref %u."), die_ref);
++  	  bfd_set_error (bfd_error_bad_value);
++  	  return name;
++  	}
++      }
+    else
+      info_ptr = unit->info_ptr_unit + die_ref;
+    abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+*************** _bfd_dwarf2_cleanup_debug_info (bfd *abf
+*** 3692,3697 ****
+--- 3822,3833 ----
+      free (stash->dwarf_ranges_buffer);
+    if (stash->info_ptr_memory)
+      free (stash->info_ptr_memory);
++   if (stash->alt_dwarf_str_buffer)
++     free (stash->alt_dwarf_str_buffer);
++   if (stash->alt_dwarf_info_buffer)
++     free (stash->alt_dwarf_info_buffer);
++   if (stash->alt_bfd_ptr)
++     bfd_close (stash->alt_bfd_ptr);
+    if (stash->close_on_cleanup)
+      bfd_close (stash->bfd_ptr);
+  }
+diff -cp ../binutils-2.23.52.0.1.orig/bfd/opncls.c bfd/opncls.c
+*** ../binutils-2.23.52.0.1.orig/bfd/opncls.c	2013-06-04 15:26:43.723449983 +0100
+--- bfd/opncls.c	2013-06-04 15:47:45.183484951 +0100
+*************** bfd_release (bfd *abfd, void *block)
+*** 1049,1058 ****
+  
+     This facilitates "optional" provision of debugging information, without
+     having to provide two complete copies of every binary object (with and
+!    without debug symbols).
+! */
+  
+- #define GNU_DEBUGLINK	".gnu_debuglink"
+  /*
+  FUNCTION
+  	bfd_calc_gnu_debuglink_crc32
+--- 1049,1059 ----
+  
+     This facilitates "optional" provision of debugging information, without
+     having to provide two complete copies of every binary object (with and
+!    without debug symbols).  */
+! 
+! #define GNU_DEBUGLINK		".gnu_debuglink"
+! #define GNU_DEBUGALTLINK	".gnu_debugaltlink"
+  
+  /*
+  FUNCTION
+  	bfd_calc_gnu_debuglink_crc32
+*************** get_debug_link_info (bfd *abfd, unsigned
+*** 1188,1193 ****
+--- 1189,1242 ----
+  }
+  
+  /*
++ FUNCTION
++ 	bfd_get_alt_debug_link_info
++ 
++ SYNOPSIS
++ 	char *bfd_get_alt_debug_link_info (bfd *abfd, unsigned long *crc32_out);
++ 
++ DESCRIPTION
++ 	Fetch the filename and BuildID value for any alternate debuginfo
++ 	associated with @var{abfd}.  Return NULL if no such info found,
++ 	otherwise return filename and update @var{buildid_out}.  The
++ 	returned filename is allocated with @code{malloc}; freeing it
++ 	is the responsibility of the caller.
++ */
++ 
++ char *
++ bfd_get_alt_debug_link_info (bfd * abfd, unsigned long * buildid_out)
++ {
++   asection *sect;
++   bfd_byte *contents;
++   int buildid_offset;
++   char *name;
++ 
++   BFD_ASSERT (abfd);
++   BFD_ASSERT (buildid_out);
++ 
++   sect = bfd_get_section_by_name (abfd, GNU_DEBUGALTLINK);
++ 
++   if (sect == NULL)
++     return NULL;
++ 
++   if (!bfd_malloc_and_get_section (abfd, sect, & contents))
++     {
++       if (contents != NULL)
++ 	free (contents);
++       return NULL;
++     }
++ 
++   /* BuildID value is stored after the filename, aligned up to 4 bytes.  */
++   name = (char *) contents;
++   buildid_offset = strlen (name) + 1;
++   buildid_offset = (buildid_offset + 3) & ~3;
++ 
++   * buildid_out = bfd_get_32 (abfd, contents + buildid_offset);
++ 
++   return name;
++ }
++ 
++ /*
+  INTERNAL_FUNCTION
+  	separate_debug_file_exists
+  
+*************** separate_debug_file_exists (const char *
+*** 1222,1227 ****
+--- 1271,1307 ----
+    return crc == file_crc;
+  }
+  
++ /*
++ INTERNAL_FUNCTION
++ 	separate_alt_debug_file_exists
++ 
++ SYNOPSIS
++ 	bfd_boolean separate_alt_debug_file_exists
++ 	  (char *name, unsigned long crc32);
++ 
++ DESCRIPTION
++ 	Checks to see if @var{name} is a file and if its BuildID
++ 	matches @var{buildid}.
++ */
++ 
++ static bfd_boolean
++ separate_alt_debug_file_exists (const char *name,
++ 				const unsigned long buildid ATTRIBUTE_UNUSED)
++ {
++   FILE *f;
++ 
++   BFD_ASSERT (name);
++ 
++   f = real_fopen (name, FOPEN_RB);
++   if (f == NULL)
++     return FALSE;
++ 
++   /* FIXME: Add code to check buildid.  */
++ 
++   fclose (f);
++ 
++   return TRUE;
++ }
+  
+  /*
+  INTERNAL_FUNCTION
+*************** SYNOPSIS
+*** 1231,1246 ****
+  	char *find_separate_debug_file (bfd *abfd);
+  
+  DESCRIPTION
+! 	Searches @var{abfd} for a reference to separate debugging
+! 	information, scans various locations in the filesystem, including
+! 	the file tree rooted at @var{debug_file_directory}, and returns a
+! 	filename of such debugging information if the file is found and has
+! 	matching CRC32.  Returns NULL if no reference to debugging file
+! 	exists, or file cannot be found.
+  */
+  
+  static char *
+! find_separate_debug_file (bfd *abfd, const char *debug_file_directory)
+  {
+    char *base;
+    char *dir;
+--- 1311,1334 ----
+  	char *find_separate_debug_file (bfd *abfd);
+  
+  DESCRIPTION
+! 	Searches @var{abfd} for a section called @var{section_name} which
+! 	is expected to contain a reference to a file containing separate
+! 	debugging information.  The function scans various locations in
+! 	the filesystem, including the file tree rooted at
+! 	@var{debug_file_directory}, and returns the first matching
+! 	filename that it finds.  If @var{check_crc} is TRUE then the
+! 	contents of the file must also match the CRC value contained in
+! 	@var{section_name}.  Returns NULL if no valid file could be found.
+  */
+  
++ typedef char *      (* get_func_type) (bfd *, unsigned long *);
++ typedef bfd_boolean (* check_func_type) (const char *, const unsigned long);
++ 
+  static char *
+! find_separate_debug_file (bfd *           abfd,
+! 			  const char *    debug_file_directory,
+! 			  get_func_type   get_func,
+! 			  check_func_type check_func)
+  {
+    char *base;
+    char *dir;
+*************** find_separate_debug_file (bfd *abfd, con
+*** 1261,1267 ****
+        return NULL;
+      }
+  
+!   base = get_debug_link_info (abfd, & crc32);
+    if (base == NULL)
+      return NULL;
+  
+--- 1349,1355 ----
+        return NULL;
+      }
+  
+!   base = get_func (abfd, & crc32);
+    if (base == NULL)
+      return NULL;
+  
+*************** find_separate_debug_file (bfd *abfd, con
+*** 1300,1336 ****
+                    + strlen (base)
+                    + 1);
+    if (debugfile == NULL)
+!     {
+!       free (base);
+!       free (dir);
+!       free (canon_dir);
+!       return NULL;
+!     }
+  
+    /* First try in the same directory as the original file:  */
+    strcpy (debugfile, dir);
+    strcat (debugfile, base);
+  
+!   if (separate_debug_file_exists (debugfile, crc32))
+!     {
+!       free (base);
+!       free (dir);
+!       free (canon_dir);
+!       return debugfile;
+!     }
+  
+    /* Then try in a subdirectory called .debug.  */
+    strcpy (debugfile, dir);
+    strcat (debugfile, ".debug/");
+    strcat (debugfile, base);
+  
+!   if (separate_debug_file_exists (debugfile, crc32))
+!     {
+!       free (base);
+!       free (dir);
+!       free (canon_dir);
+!       return debugfile;
+!     }
+  
+    /* Then try in the global debugfile directory.  */
+    strcpy (debugfile, debug_file_directory);
+--- 1388,1409 ----
+                    + strlen (base)
+                    + 1);
+    if (debugfile == NULL)
+!     goto found; /* Actually this returns NULL.  */
+  
+    /* First try in the same directory as the original file:  */
+    strcpy (debugfile, dir);
+    strcat (debugfile, base);
+  
+!   if (check_func (debugfile, crc32))
+!     goto found;
+  
+    /* Then try in a subdirectory called .debug.  */
+    strcpy (debugfile, dir);
+    strcat (debugfile, ".debug/");
+    strcat (debugfile, base);
+  
+!   if (check_func (debugfile, crc32))
+!     goto found;
+  
+    /* Then try in the global debugfile directory.  */
+    strcpy (debugfile, debug_file_directory);
+*************** find_separate_debug_file (bfd *abfd, con
+*** 1342,1360 ****
+    strcat (debugfile, canon_dir);
+    strcat (debugfile, base);
+  
+!   if (separate_debug_file_exists (debugfile, crc32))
+!     {
+!       free (base);
+!       free (dir);
+!       free (canon_dir);
+!       return debugfile;
+!     }
+  
+    free (debugfile);
+    free (base);
+    free (dir);
+    free (canon_dir);
+!   return NULL;
+  }
+  
+  
+--- 1415,1432 ----
+    strcat (debugfile, canon_dir);
+    strcat (debugfile, base);
+  
+!   if (check_func (debugfile, crc32))
+!     goto found;
+  
++   /* Failed to find the file.  */
+    free (debugfile);
++   debugfile = NULL;
++ 
++  found:
+    free (base);
+    free (dir);
+    free (canon_dir);
+!   return debugfile;
+  }
+  
+  
+*************** RETURNS
+*** 1387,1393 ****
+  char *
+  bfd_follow_gnu_debuglink (bfd *abfd, const char *dir)
+  {
+!   return find_separate_debug_file (abfd, dir);
+  }
+  
+  /*
+--- 1459,1501 ----
+  char *
+  bfd_follow_gnu_debuglink (bfd *abfd, const char *dir)
+  {
+!   return find_separate_debug_file (abfd, dir,
+! 				   get_debug_link_info,
+! 				   separate_debug_file_exists);
+! }
+! 
+! /*
+! FUNCTION
+! 	bfd_follow_gnu_debugaltlink
+! 
+! SYNOPSIS
+! 	char *bfd_follow_gnu_debugaltlink (bfd *abfd, const char *dir);
+! 
+! DESCRIPTION
+! 
+! 	Takes a BFD and searches it for a .gnu_debugaltlink section.  If this
+! 	section is found, it examines the section for the name of a file
+! 	containing auxiliary debugging information.  It	then searches the
+! 	filesystem for this file in a set of standard locations, including
+! 	the directory tree rooted at @var{dir}, and if found returns the
+! 	full filename.
+! 
+! 	If @var{dir} is NULL, it will search a default path configured into
+! 	libbfd at build time.  [FIXME: This feature is not currently
+! 	implemented].
+! 
+! RETURNS
+! 	<<NULL>> on any errors or failure to locate the debug file,
+! 	otherwise a pointer to a heap-allocated string containing the
+! 	filename.  The caller is responsible for freeing this string.
+! */
+! 
+! char *
+! bfd_follow_gnu_debugaltlink (bfd *abfd, const char *dir)
+! {
+!   return find_separate_debug_file (abfd, dir,
+! 				   bfd_get_alt_debug_link_info,
+! 				   separate_alt_debug_file_exists);
+  }
+  
+  /*
diff --git a/binutils.spec b/binutils.spec
index 6690fd4..4571352 100644
--- a/binutils.spec
+++ b/binutils.spec
@@ -17,7 +17,7 @@
 Summary: A GNU collection of binary utilities
 Name: %{?cross}binutils%{?_with_debug:-debug}
 Version: 2.23.52.0.1
-Release: 8%{?dist}
+Release: 9%{?dist}
 License: GPLv3+
 Group: Development/Tools
 URL: http://sources.redhat.com/binutils
@@ -50,6 +50,8 @@ Patch13: binutils-2.23.52.0.1-revert-pr15149.patch
 Patch14: binutils-2.23.52.0.1-aarch64-lib64.patch
 # Check regular references without non-GOT references when building shared libraries.
 Patch15: binutils-2.23.52.0.1-check-regular-ifunc-refs.patch
+# Add support to BFD library for debug information held in alternate files.
+Patch16: binutils-2.23.52.0.1-dwz-alt-debuginfo.patch
 
 Provides: bundled(libiberty)
 
@@ -163,6 +165,7 @@ using libelf instead of BFD.
 %patch13 -p0 -b .revert-pr15149~
 %patch14 -p0 -b .aarch64-lib64~
 %patch15 -p0 -b .check-ifunc~
+%patch16 -p0 -b .dwz~
 
 # We cannot run autotools as there is an exact requirement of autoconf-2.59.
 
@@ -462,6 +465,9 @@ exit 0
 %endif # %{isnative}
 
 %changelog
+* Tue Jun 04 2013 Nick Clifton <nickc at redhat.com> - 2.23.52.0.1-9
+- Add support for the alternative debuging files generated by the DWZ program.  (#965255)
+
 * Wed Apr 17 2013 Nick Clifton <nickc at redhat.com> - 2.23.52.0.1-8
 - Import patch for FSF mainline PR 15371 to fix ifunc references in shared libraries.  (#927818)
 


More information about the scm-commits mailing list