From 95e34fb4f43f5cc57c48d4799c5c59d7dcf6c2a2 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Wed, 29 May 2013 14:58:35 +0000 Subject: * dwarf2.c (struct dwarf2_debug): Add fields for handling alternate debug info source. (dwarf_debug_sections): Add entries for alternate .debug_str and .debug_info sections. (dwarf_debug_section_enum): Likewise. (read_alt_indirect_string): New function. Handles a DW_FORM_GNU_strp_alt attribute. (read_alt_indirect_ref): New function. Handles a DW_FORM_GNU_ref_alt attribute. (read_attribute_value): Process DW_FORM_GNU_ref_alt and DW_FORM_GNU_strp_alt. (find_abstract_instance_name): Handle DW_FORM_GNU_ref_alt attributes. (_bfd_dwarf2_cleanup_debug_info): Free alternate debug info sources. * opncls.c (GNU_DEBUGALTLINK): Define. (bfd_get_alt_debug_link_info): New function. (separate_alt_debug_file_exists): New function. (find_separate_debug_file): Add parameters for fetch and check functions. (bfd_follow_gnu_debugaltlink): New function. * bfd-in2.h: Regenerate. --- bfd/dwarf2.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 142 insertions(+), 6 deletions(-) (limited to 'bfd/dwarf2.c') diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c index 7a1a4ae..c9349da 100644 --- a/bfd/dwarf2.c +++ b/bfd/dwarf2.c @@ -1,6 +1,5 @@ /* DWARF 2 support. - Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + Copyright 1994-2013 Free Software Foundation, Inc. Adapted from gdb/dwarf2read.c by Gavin Koch of Cygnus Solutions (gavin@cygnus.com). @@ -108,6 +107,16 @@ struct dwarf2_debug 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 @@ -290,6 +299,7 @@ const struct dwarf_debug_section dwarf_debug_sections[] = { ".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" }, @@ -300,6 +310,7 @@ const struct dwarf_debug_section dwarf_debug_sections[] = { ".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" }, @@ -312,12 +323,15 @@ const struct dwarf_debug_section dwarf_debug_sections[] = { 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, @@ -328,6 +342,7 @@ enum dwarf_debug_section_enum debug_static_func, debug_static_vars, debug_str, + debug_str_alt, debug_types, debug_sfnames, debug_srcinfo, @@ -484,8 +499,8 @@ read_section (bfd * abfd, asection *msec; const char *section_name = sec->uncompressed_name; - /* read_section is a noop if the section has already been read. */ - if (!*section_buffer) + /* The section may have already been read. */ + if (*section_buffer == NULL) { msec = bfd_get_section_by_name (abfd, section_name); if (! msec) @@ -626,6 +641,104 @@ read_indirect_string (struct comp_unit * unit, 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) { @@ -829,6 +942,7 @@ read_attribute_value (struct attribute *attr, 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); @@ -878,6 +992,10 @@ read_attribute_value (struct attribute *attr, 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); @@ -950,7 +1068,7 @@ read_attribute_value (struct attribute *attr, info_ptr = read_attribute_value (attr, form, unit, info_ptr); break; default: - (*_bfd_error_handler) (_("Dwarf Error: Invalid or unhandled FORM value: %u."), + (*_bfd_error_handler) (_("Dwarf Error: Invalid or unhandled FORM value: %#x."), form); bfd_set_error (bfd_error_bad_value); return NULL; @@ -1996,7 +2114,7 @@ find_abstract_instance_name (struct comp_unit *unit, struct abbrev_info *abbrev; bfd_uint64_t die_ref = attr_ptr->u.val; struct attribute attr; - char *name = 0; + char *name = NULL; /* DW_FORM_ref_addr can reference an entry in a different CU. It is an offset from the .debug_info section, not the current CU. */ @@ -2009,8 +2127,20 @@ find_abstract_instance_name (struct comp_unit *unit, 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); info_ptr += bytes_read; @@ -3694,4 +3824,10 @@ _bfd_dwarf2_cleanup_debug_info (bfd *abfd, void **pinfo) free (stash->info_ptr_memory); if (stash->close_on_cleanup) bfd_close (stash->bfd_ptr); + 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); } -- cgit v1.1