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 ! <> 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); } /*