From 59d119fed1c840b0091b3b0ba439ea1d29b02cab Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Jun 10 2013 14:45:10 +0000 Subject: Add support for the alternative debuging files generated by the DWZ program. Resolves: #965255 --- diff --git a/binutils-2.23.51.0.1-dwz-alt-debuginfo.patch b/binutils-2.23.51.0.1-dwz-alt-debuginfo.patch new file mode 100644 index 0000000..64469f7 --- /dev/null +++ b/binutils-2.23.51.0.1-dwz-alt-debuginfo.patch @@ -0,0 +1,618 @@ +diff -cp ../binutils-2.23.51.0.1.orig/bfd/bfd-in2.h bfd/bfd-in2.h +*** ../binutils-2.23.51.0.1.orig/bfd/bfd-in2.h 2013-06-10 15:31:21.349628699 +0100 +--- bfd/bfd-in2.h 2013-06-10 15:31:57.896629712 +0100 +*************** void *bfd_zalloc (bfd *abfd, bfd_size_ty +*** 1016,1023 **** +--- 1016,1027 ---- + 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); + +Only in bfd: bfd-in2.h.orig +Common subdirectories: ../binutils-2.23.51.0.1.orig/bfd/doc and bfd/doc +diff -cp ../binutils-2.23.51.0.1.orig/bfd/dwarf2.c bfd/dwarf2.c +*** ../binutils-2.23.51.0.1.orig/bfd/dwarf2.c 2013-06-10 15:31:20.693628681 +0100 +--- bfd/dwarf2.c 2013-06-10 15:32:36.805630791 +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); + } +Only in bfd: dwarf2.c.orig +Common subdirectories: ../binutils-2.23.51.0.1.orig/bfd/hosts and bfd/hosts +Common subdirectories: ../binutils-2.23.51.0.1.orig/bfd/.libs and bfd/.libs +diff -cp ../binutils-2.23.51.0.1.orig/bfd/opncls.c bfd/opncls.c +*** ../binutils-2.23.51.0.1.orig/bfd/opncls.c 2013-06-10 15:31:20.242628669 +0100 +--- bfd/opncls.c 2013-06-10 15:31:57.903629713 +0100 +*************** bfd_release (bfd *abfd, void *block) +*** 1052,1061 **** + + 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 +--- 1052,1062 ---- + + 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 +*** 1191,1196 **** +--- 1192,1245 ---- + } + + /* ++ 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 * +*** 1225,1230 **** +--- 1274,1310 ---- + 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 +*** 1234,1249 **** + 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; +--- 1314,1337 ---- + 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 +*** 1264,1270 **** + return NULL; + } + +! base = get_debug_link_info (abfd, & crc32); + if (base == NULL) + return NULL; + +--- 1352,1358 ---- + return NULL; + } + +! base = get_func (abfd, & crc32); + if (base == NULL) + return NULL; + +*************** find_separate_debug_file (bfd *abfd, con +*** 1303,1339 **** + + 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); +--- 1391,1412 ---- + + 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 +*** 1345,1363 **** + 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; + } + + +--- 1418,1435 ---- + 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 +*** 1390,1396 **** + char * + bfd_follow_gnu_debuglink (bfd *abfd, const char *dir) + { +! return find_separate_debug_file (abfd, dir); + } + + /* +--- 1462,1504 ---- + 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 +! <> 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); + } + + /* +Only in bfd: opncls.c.orig +Common subdirectories: ../binutils-2.23.51.0.1.orig/bfd/po and bfd/po diff --git a/binutils.spec b/binutils.spec index 4a52bfc..026b7f6 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.51.0.1 -Release: 9%{?dist} +Release: 10%{?dist} License: GPLv3+ Group: Development/Tools URL: http://sources.redhat.com/binutils @@ -51,6 +51,8 @@ Patch15: binutils-2.23.51.0.1-ppc64-dyn-rel-count.patch Patch16: binutils-2.23.51.0.1-readelf-corrupt-ar.patch # Fix lookup of stub names. BZ #962469 Patch17: binutils-2.23.51.0.1-ppc64-stub-lookup.patch +# Add support to BFD library for debug information held in alternate files. +Patch18: binutils-2.23.51.0.1-dwz-alt-debuginfo.patch %define gold_arches %ix86 x86_64 @@ -161,6 +163,7 @@ using libelf instead of BFD. %patch15 -p0 -b .dyn-rel-count~ %patch16 -p0 -b .corrupt-ar~ %patch17 -p0 -b .stub-lookup~ +%patch18 -p0 -b .dwz~ # We cannot run autotools as there is an exact requirement of autoconf-2.59. @@ -459,6 +462,9 @@ exit 0 %endif # %{isnative} %changelog +* Mon Jun 10 2013 Nick Clifton - 2.23.52.0.1-10 +- Add support for the alternative debuging files generated by the DWZ program. (#965255) + * Tue May 14 2013 Nick Clifton 2.23.51.0.1-9 - Fix stub lookups for PPC64. (#962469)