From 365867289923565656f39d44301481caa33a88ea Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Wed, 18 Jul 2012 19:59:35 +0000 Subject: [PATCH] * dwarf2read.c (struct dwarf2_per_objfile) : New field. (struct dwarf2_per_cu_data) : No longer bitfield. : New field. (struct dwz_file): New. (struct partial_die_info) : New fields. (locate_dwz_sections, dwarf2_get_dwz_file) (get_abbrev_section_for_cu): New functions. (error_check_comp_unit_head, read_and_check_comp_unit_head) (read_and_check_type_unit_head): Add abbrev_section argument. (create_debug_types_hash_table): Update. (init_cutu_and_read_dies): Use proper abbrev section. (init_cutu_and_read_dies_no_follow): Likewise. (set_partial_user): Do nothing if PST==NULL. (read_comp_units_from_section): New function. (create_all_comp_units): Use it. (scan_partial_symbols, partial_die_parent_scope): Update. (skip_one_die): Handle DW_FORM_GNU_ref_alt, DW_FORM_GNU_strp_alt. (process_imported_unit_die, read_partial_die): Handle .dwz files. (find_partial_die): Add offset_in_dwz argument. Update. (guess_partial_die_structure_name, fixup_partial_die): Update. (read_attribute_value): Handle DW_FORM_GNU_ref_alt, DW_FORM_GNU_strp_alt. (read_indirect_string_from_dwz): New function. (dwarf2_const_value_attr): Handle DW_FORM_GNU_strp_alt. (dump_die_shallow): Handle DW_FORM_GNU_ref_alt, DW_FORM_GNU_strp_alt. (is_ref_attr): Handle DW_FORM_GNU_ref_alt. (follow_die_offset): Add offset_in_dwz argument. (follow_die_ref, dwarf2_fetch_die_location_block): Update. (skip_form_bytes): Handle DW_FORM_GNU_strp_alt. (dwarf_decode_macro_bytes): Add section_is_dwz argument. Handle new macro forms. (dwarf_decode_macros): Update. (dwarf2_find_containing_comp_unit): Add offset_in_dwz argument. (dwarf2_per_objfile_free): Unref dwz_bfd, if it exists (lookup_die_type): Handle DW_FORM_GNU_ref_alt. (create_debug_types_hash_table): Use correct abbrev section. (get_debug_line_section): New function. (dwarf_decode_line_header, dwarf_decode_lines_1): Use it. (process_full_comp_unit): Pass 'required' argument to end_symtab_get_static_block. * buildsym.h (end_symtab_get_static_block): Update. * buildsym.c (end_symtab_get_static_block): Add 'required' argument. (end_symtab, end_expandable_symtab): Update. --- gdb/ChangeLog | 47 +++++ gdb/buildsym.c | 14 +- gdb/buildsym.h | 3 +- gdb/dwarf2read.c | 485 +++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 467 insertions(+), 82 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 10dacd665cd..a182ac2fb7e 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,50 @@ +2012-07-18 Tom Tromey + + * dwarf2read.c (struct dwarf2_per_objfile) : New field. + (struct dwarf2_per_cu_data) : No longer bitfield. + : New field. + (struct dwz_file): New. + (struct partial_die_info) : New fields. + (locate_dwz_sections, dwarf2_get_dwz_file) + (get_abbrev_section_for_cu): New functions. + (error_check_comp_unit_head, read_and_check_comp_unit_head) + (read_and_check_type_unit_head): Add abbrev_section argument. + (create_debug_types_hash_table): Update. + (init_cutu_and_read_dies): Use proper abbrev section. + (init_cutu_and_read_dies_no_follow): Likewise. + (set_partial_user): Do nothing if PST==NULL. + (read_comp_units_from_section): New function. + (create_all_comp_units): Use it. + (scan_partial_symbols, partial_die_parent_scope): Update. + (skip_one_die): Handle DW_FORM_GNU_ref_alt, DW_FORM_GNU_strp_alt. + (process_imported_unit_die, read_partial_die): Handle .dwz files. + (find_partial_die): Add offset_in_dwz argument. Update. + (guess_partial_die_structure_name, fixup_partial_die): Update. + (read_attribute_value): Handle DW_FORM_GNU_ref_alt, + DW_FORM_GNU_strp_alt. + (read_indirect_string_from_dwz): New function. + (dwarf2_const_value_attr): Handle DW_FORM_GNU_strp_alt. + (dump_die_shallow): Handle DW_FORM_GNU_ref_alt, DW_FORM_GNU_strp_alt. + (is_ref_attr): Handle DW_FORM_GNU_ref_alt. + (follow_die_offset): Add offset_in_dwz argument. + (follow_die_ref, dwarf2_fetch_die_location_block): Update. + (skip_form_bytes): Handle DW_FORM_GNU_strp_alt. + (dwarf_decode_macro_bytes): Add section_is_dwz argument. + Handle new macro forms. + (dwarf_decode_macros): Update. + (dwarf2_find_containing_comp_unit): Add offset_in_dwz argument. + (dwarf2_per_objfile_free): Unref dwz_bfd, if it exists + (lookup_die_type): Handle DW_FORM_GNU_ref_alt. + (create_debug_types_hash_table): Use correct abbrev section. + (get_debug_line_section): New function. + (dwarf_decode_line_header, dwarf_decode_lines_1): Use it. + (process_full_comp_unit): Pass 'required' argument to + end_symtab_get_static_block. + * buildsym.h (end_symtab_get_static_block): Update. + * buildsym.c (end_symtab_get_static_block): Add 'required' + argument. + (end_symtab, end_expandable_symtab): Update. + 2012-07-18 Tom Tromey * dwarf2read.c: Don't include zlib.h or sys/mman.h. diff --git a/gdb/buildsym.c b/gdb/buildsym.c index d547012166b..e4882fb7fce 100644 --- a/gdb/buildsym.c +++ b/gdb/buildsym.c @@ -966,11 +966,14 @@ reset_symtab_globals (void) file's text. If EXPANDABLE is non-zero the STATIC_BLOCK dictionary is made - expandable. */ + expandable. + + If REQUIRED is non-zero, then a symtab is created even if it does + not contain any symbols. */ struct block * end_symtab_get_static_block (CORE_ADDR end_addr, struct objfile *objfile, - int expandable) + int expandable, int required) { /* Finish the lexical context of the last function in the file; pop the context stack. */ @@ -1038,7 +1041,8 @@ end_symtab_get_static_block (CORE_ADDR end_addr, struct objfile *objfile, cleanup_undefined_stabs_types (objfile); finish_global_stabs (objfile); - if (pending_blocks == NULL + if (!required + && pending_blocks == NULL && file_symbols == NULL && global_symbols == NULL && have_line_numbers == 0 @@ -1296,7 +1300,7 @@ end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section) { struct block *static_block; - static_block = end_symtab_get_static_block (end_addr, objfile, 0); + static_block = end_symtab_get_static_block (end_addr, objfile, 0, 0); return end_symtab_from_static_block (static_block, objfile, section, 0); } @@ -1308,7 +1312,7 @@ end_expandable_symtab (CORE_ADDR end_addr, struct objfile *objfile, { struct block *static_block; - static_block = end_symtab_get_static_block (end_addr, objfile, 1); + static_block = end_symtab_get_static_block (end_addr, objfile, 1, 0); return end_symtab_from_static_block (static_block, objfile, section, 1); } diff --git a/gdb/buildsym.h b/gdb/buildsym.h index 162ee8c79df..33b34c8de94 100644 --- a/gdb/buildsym.h +++ b/gdb/buildsym.h @@ -260,7 +260,8 @@ extern char *pop_subfile (void); extern struct block *end_symtab_get_static_block (CORE_ADDR end_addr, struct objfile *objfile, - int expandable); + int expandable, + int required); extern struct symtab *end_symtab_from_static_block (struct block *static_block, struct objfile *objfile, diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index da23cc44122..ee25219b9ae 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -233,6 +233,10 @@ struct dwarf2_per_objfile This is NULL if the table hasn't been allocated yet. */ htab_t dwo_files; + /* The shared '.dwz' file, if one exists. This is used when the + original data was compressed using 'dwz -m'. */ + struct dwz_file *dwz_file; + /* A flag indicating wether this objfile has a section loaded at a VMA of 0. */ int has_section_at_zero; @@ -491,15 +495,13 @@ struct dwarf2_cu struct dwarf2_per_cu_data { - /* The start offset and length of this compilation unit. 2**29-1 - bytes should suffice to store the length of any compilation unit - - if it doesn't, GDB will fall over anyway. + /* The start offset and length of this compilation unit. NOTE: Unlike comp_unit_head.length, this length includes initial_length_size. If the DIE refers to a DWO file, this is always of the original die, not the DWO file. */ sect_offset offset; - unsigned int length : 29; + unsigned int length; /* Flag indicating this compilation unit will be read in before any of the current compilation units are processed. */ @@ -514,6 +516,9 @@ struct dwarf2_per_cu_data /* Non-zero if this CU is from .debug_types. */ unsigned int is_debug_types : 1; + /* Non-zero if this CU is from the .dwz file. */ + unsigned int is_dwz : 1; + /* The section this CU/TU lives in. If the DIE refers to a DWO file, this is always the original die, not the DWO file. */ @@ -701,6 +706,21 @@ struct dwo_file htab_t tus; }; +/* This represents a '.dwz' file. */ + +struct dwz_file +{ + /* A dwz file can only contain a few sections. */ + struct dwarf2_section_info abbrev; + struct dwarf2_section_info info; + struct dwarf2_section_info str; + struct dwarf2_section_info line; + struct dwarf2_section_info macro; + + /* The dwz's BFD. */ + bfd *dwz_bfd; +}; + /* Struct used to pass misc. parameters to read_die_and_children, et al. which are used for both .debug_info and .debug_types dies. All parameters here are unchanging for the life of the call. This @@ -814,6 +834,12 @@ struct partial_die_info /* Flag set if fixup_partial_die has been called on this die. */ unsigned int fixup_called : 1; + /* Flag set if DW_TAG_imported_unit uses DW_FORM_GNU_ref_alt. */ + unsigned int is_dwz : 1; + + /* Flag set if spec_offset uses DW_FORM_GNU_ref_alt. */ + unsigned int spec_is_dwz : 1; + /* The name of this DIE. Normally the value of DW_AT_name, but sometimes a default name for unnamed DIEs. */ char *name; @@ -1199,7 +1225,7 @@ static gdb_byte *read_partial_die (const struct die_reader_specs *, unsigned int, gdb_byte *); -static struct partial_die_info *find_partial_die (sect_offset, +static struct partial_die_info *find_partial_die (sect_offset, int, struct dwarf2_cu *); static void fixup_partial_die (struct partial_die_info *, @@ -1244,6 +1270,8 @@ static char *read_indirect_string (bfd *, gdb_byte *, const struct comp_unit_head *, unsigned int *); +static char *read_indirect_string_from_dwz (struct dwz_file *, LONGEST); + static ULONGEST read_unsigned_leb128 (bfd *, gdb_byte *, unsigned int *); static LONGEST read_signed_leb128 (bfd *, gdb_byte *, unsigned int *); @@ -1510,7 +1538,7 @@ static hashval_t partial_die_hash (const void *item); static int partial_die_eq (const void *item_lhs, const void *item_rhs); static struct dwarf2_per_cu_data *dwarf2_find_containing_comp_unit - (sect_offset offset, struct objfile *objfile); + (sect_offset offset, unsigned int offset_in_dwz, struct objfile *objfile); static void init_one_comp_unit (struct dwarf2_cu *cu, struct dwarf2_per_cu_data *per_cu); @@ -1573,6 +1601,12 @@ static void find_file_and_directory (struct die_info *die, static char *file_full_name (int file, struct line_header *lh, const char *comp_dir); +static gdb_byte *read_and_check_comp_unit_head + (struct comp_unit_head *header, + struct dwarf2_section_info *section, + struct dwarf2_section_info *abbrev_section, gdb_byte *info_ptr, + int is_debug_types_section); + static void init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu, struct abbrev_table *abbrev_table, int use_existing_cu, int keep, @@ -1885,6 +1919,106 @@ dwarf2_get_section_info (struct objfile *objfile, *sizep = info->size; } +/* A helper function to find the sections for a .dwz file. */ + +static void +locate_dwz_sections (bfd *abfd, asection *sectp, void *arg) +{ + struct dwz_file *dwz_file = arg; + + /* Note that we only support the standard ELF names, because .dwz + is ELF-only (at the time of writing). */ + if (section_is_p (sectp->name, &dwarf2_elf_names.abbrev)) + { + dwz_file->abbrev.asection = sectp; + dwz_file->abbrev.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &dwarf2_elf_names.info)) + { + dwz_file->info.asection = sectp; + dwz_file->info.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &dwarf2_elf_names.str)) + { + dwz_file->str.asection = sectp; + dwz_file->str.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &dwarf2_elf_names.line)) + { + dwz_file->line.asection = sectp; + dwz_file->line.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &dwarf2_elf_names.macro)) + { + dwz_file->macro.asection = sectp; + dwz_file->macro.size = bfd_get_section_size (sectp); + } +} + +/* Open the separate '.dwz' debug file, if needed. Error if the file + cannot be found. */ + +static struct dwz_file * +dwarf2_get_dwz_file (void) +{ + bfd *abfd, *dwz_bfd; + asection *section; + gdb_byte *data; + struct cleanup *cleanup; + const char *filename; + struct dwz_file *result; + + if (dwarf2_per_objfile->dwz_file != NULL) + return dwarf2_per_objfile->dwz_file; + + abfd = dwarf2_per_objfile->objfile->obfd; + section = bfd_get_section_by_name (abfd, ".gnu_debugaltlink"); + if (section == NULL) + error (_("could not find '.gnu_debugaltlink' section")); + if (!bfd_malloc_and_get_section (abfd, section, &data)) + error (_("could not read '.gnu_debugaltlink' section: %s"), + bfd_errmsg (bfd_get_error ())); + cleanup = make_cleanup (xfree, data); + + filename = data; + if (!IS_ABSOLUTE_PATH (filename)) + { + char *abs = gdb_realpath (dwarf2_per_objfile->objfile->name); + char *rel; + + make_cleanup (xfree, abs); + abs = ldirname (abs); + make_cleanup (xfree, abs); + + rel = concat (abs, SLASH_STRING, filename, (char *) NULL); + make_cleanup (xfree, rel); + filename = rel; + } + + /* The format is just a NUL-terminated file name, followed by the + build-id. For now, though, we ignore the build-id. */ + dwz_bfd = gdb_bfd_open (filename, gnutarget, -1); + if (dwz_bfd == NULL) + error (_("could not read '%s': %s"), filename, + bfd_errmsg (bfd_get_error ())); + + if (!bfd_check_format (dwz_bfd, bfd_object)) + { + gdb_bfd_unref (dwz_bfd); + error (_("file '%s' was not usable: %s"), filename, + bfd_errmsg (bfd_get_error ())); + } + + result = OBSTACK_ZALLOC (&dwarf2_per_objfile->objfile->objfile_obstack, + struct dwz_file); + result->dwz_bfd = dwz_bfd; + + bfd_map_over_sections (dwz_bfd, locate_dwz_sections, result); + + do_cleanups (cleanup); + + return result; +} /* DWARF quick_symbols_functions support. */ @@ -3560,6 +3694,22 @@ read_comp_unit_head (struct comp_unit_head *cu_header, return info_ptr; } +/* Helper function that returns the proper abbrev section for + THIS_CU. */ + +static struct dwarf2_section_info * +get_abbrev_section_for_cu (struct dwarf2_per_cu_data *this_cu) +{ + struct dwarf2_section_info *abbrev; + + if (this_cu->is_dwz) + abbrev = &dwarf2_get_dwz_file ()->abbrev; + else + abbrev = &dwarf2_per_objfile->abbrev; + + return abbrev; +} + /* Subroutine of read_and_check_comp_unit_head and read_and_check_type_unit_head to simplify them. Perform various error checking on the header. */ @@ -3578,8 +3728,7 @@ error_check_comp_unit_head (struct comp_unit_head *header, filename); if (header->abbrev_offset.sect_off - >= dwarf2_section_size (dwarf2_per_objfile->objfile, - &dwarf2_per_objfile->abbrev)) + >= dwarf2_section_size (dwarf2_per_objfile->objfile, abbrev_section)) error (_("Dwarf Error: bad offset (0x%lx) in compilation unit header " "(offset 0x%lx + 6) [in module %s]"), (long) header->abbrev_offset.sect_off, (long) header->offset.sect_off, @@ -3816,6 +3965,7 @@ create_debug_types_hash_table (struct dwo_file *dwo_file, { bfd *abfd; gdb_byte *info_ptr, *end_ptr; + struct dwarf2_section_info *abbrev_section; dwarf2_read_section (objfile, section); info_ptr = section->buffer; @@ -3827,6 +3977,11 @@ create_debug_types_hash_table (struct dwo_file *dwo_file, not present, in which case section->asection will be NULL. */ abfd = section->asection->owner; + if (dwo_file) + abbrev_section = &dwo_file->sections.abbrev; + else + abbrev_section = &dwarf2_per_objfile->abbrev; + if (types_htab == NULL) { if (dwo_file) @@ -4066,7 +4221,8 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu, dwarf2_read_section (objfile, section); begin_info_ptr = info_ptr = section->buffer + this_cu->offset.sect_off; - abbrev_section = &dwarf2_per_objfile->abbrev; + + abbrev_section = get_abbrev_section_for_cu (this_cu); if (use_existing_cu && this_cu->cu != NULL) { @@ -4448,7 +4604,7 @@ init_cutu_and_read_dies_simple (struct dwarf2_per_cu_data *this_cu, void *data) { init_cutu_and_read_dies_no_follow (this_cu, - &dwarf2_per_objfile->abbrev, + get_abbrev_section_for_cu (this_cu), NULL, die_reader_func, data); } @@ -5076,6 +5232,9 @@ set_partial_user (struct objfile *objfile) struct partial_symtab *pst = per_cu->v.psymtab; int j; + if (pst == NULL) + continue; + for (j = 0; j < pst->number_of_dependencies; ++j) { /* Set the 'user' field only if it is not already set. */ @@ -5170,38 +5329,32 @@ load_partial_comp_unit (struct dwarf2_per_cu_data *this_cu) load_partial_comp_unit_reader, NULL); } -/* Create a list of all compilation units in OBJFILE. - This is only done for -readnow and building partial symtabs. */ - static void -create_all_comp_units (struct objfile *objfile) +read_comp_units_from_section (struct objfile *objfile, + struct dwarf2_section_info *section, + unsigned int is_dwz, + int *n_allocated, + int *n_comp_units, + struct dwarf2_per_cu_data ***all_comp_units) { - int n_allocated; - int n_comp_units; - struct dwarf2_per_cu_data **all_comp_units; gdb_byte *info_ptr; + bfd *abfd = section->asection->owner; - dwarf2_read_section (objfile, &dwarf2_per_objfile->info); - info_ptr = dwarf2_per_objfile->info.buffer; + dwarf2_read_section (objfile, section); - n_comp_units = 0; - n_allocated = 10; - all_comp_units = xmalloc (n_allocated - * sizeof (struct dwarf2_per_cu_data *)); + info_ptr = section->buffer; - while (info_ptr < dwarf2_per_objfile->info.buffer - + dwarf2_per_objfile->info.size) + while (info_ptr < section->buffer + section->size) { unsigned int length, initial_length_size; struct dwarf2_per_cu_data *this_cu; sect_offset offset; - offset.sect_off = info_ptr - dwarf2_per_objfile->info.buffer; + offset.sect_off = info_ptr - section->buffer; /* Read just enough information to find out where the next compilation unit is. */ - length = read_initial_length (objfile->obfd, info_ptr, - &initial_length_size); + length = read_initial_length (abfd, info_ptr, &initial_length_size); /* Save the compilation unit for later lookup. */ this_cu = obstack_alloc (&objfile->objfile_obstack, @@ -5209,20 +5362,50 @@ create_all_comp_units (struct objfile *objfile) memset (this_cu, 0, sizeof (*this_cu)); this_cu->offset = offset; this_cu->length = length + initial_length_size; + this_cu->is_dwz = is_dwz; this_cu->objfile = objfile; - this_cu->info_or_types_section = &dwarf2_per_objfile->info; + this_cu->info_or_types_section = section; - if (n_comp_units == n_allocated) + if (*n_comp_units == *n_allocated) { - n_allocated *= 2; - all_comp_units = xrealloc (all_comp_units, - n_allocated - * sizeof (struct dwarf2_per_cu_data *)); + *n_allocated *= 2; + *all_comp_units = xrealloc (*all_comp_units, + *n_allocated + * sizeof (struct dwarf2_per_cu_data *)); } - all_comp_units[n_comp_units++] = this_cu; + (*all_comp_units)[*n_comp_units] = this_cu; + ++*n_comp_units; info_ptr = info_ptr + this_cu->length; } +} + +/* Create a list of all compilation units in OBJFILE. + This is only done for -readnow and building partial symtabs. */ + +static void +create_all_comp_units (struct objfile *objfile) +{ + int n_allocated; + int n_comp_units; + struct dwarf2_per_cu_data **all_comp_units; + + n_comp_units = 0; + n_allocated = 10; + all_comp_units = xmalloc (n_allocated + * sizeof (struct dwarf2_per_cu_data *)); + + read_comp_units_from_section (objfile, &dwarf2_per_objfile->info, 0, + &n_allocated, &n_comp_units, &all_comp_units); + + if (bfd_get_section_by_name (objfile->obfd, ".gnu_debugaltlink") != NULL) + { + struct dwz_file *dwz = dwarf2_get_dwz_file (); + + read_comp_units_from_section (objfile, &dwz->info, 1, + &n_allocated, &n_comp_units, + &all_comp_units); + } dwarf2_per_objfile->all_comp_units = obstack_alloc (&objfile->objfile_obstack, @@ -5315,6 +5498,7 @@ scan_partial_symbols (struct partial_die_info *first_die, CORE_ADDR *lowpc, } per_cu = dwarf2_find_containing_comp_unit (pdi->d.offset, + pdi->is_dwz, cu->objfile); /* Go read the partial unit, if needed. */ @@ -5372,7 +5556,8 @@ partial_die_parent_scope (struct partial_die_info *pdi, real_pdi = pdi; while (real_pdi->has_specification) - real_pdi = find_partial_die (real_pdi->spec_offset, cu); + real_pdi = find_partial_die (real_pdi->spec_offset, + real_pdi->spec_is_dwz, cu); parent = real_pdi->die_parent; if (parent == NULL) @@ -5872,6 +6057,9 @@ skip_one_die (const struct die_reader_specs *reader, gdb_byte *info_ptr, else info_ptr += cu->header.offset_size; break; + case DW_FORM_GNU_ref_alt: + info_ptr += cu->header.offset_size; + break; case DW_FORM_addr: info_ptr += cu->header.addr_size; break; @@ -5901,6 +6089,7 @@ skip_one_die (const struct die_reader_specs *reader, gdb_byte *info_ptr, break; case DW_FORM_sec_offset: case DW_FORM_strp: + case DW_FORM_GNU_strp_alt: info_ptr += cu->header.offset_size; break; case DW_FORM_exprloc: @@ -6568,7 +6757,9 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu, it, by scanning the DIE's below the compilation unit. */ get_scope_pc_bounds (cu->dies, &lowpc, &highpc, cu); - static_block = end_symtab_get_static_block (highpc + baseaddr, objfile, 0); + static_block + = end_symtab_get_static_block (highpc + baseaddr, objfile, 0, + per_cu->s.imported_symtabs != NULL); /* If the comp unit has DW_AT_ranges, it may have discontiguous ranges. Also, DW_AT_ranges may record ranges not belonging to any child DIEs @@ -6719,9 +6910,11 @@ process_imported_unit_die (struct die_info *die, struct dwarf2_cu *cu) struct dwarf2_per_cu_data *per_cu; struct symtab *imported_symtab; sect_offset offset; + int is_dwz; offset = dwarf2_get_ref_die_offset (attr); - per_cu = dwarf2_find_containing_comp_unit (offset, cu->objfile); + is_dwz = (attr->form == DW_FORM_GNU_ref_alt || cu->per_cu->is_dwz); + per_cu = dwarf2_find_containing_comp_unit (offset, is_dwz, cu->objfile); /* Queue the unit, if needed. */ if (maybe_queue_comp_unit (cu, per_cu, cu->language)) @@ -12403,6 +12596,8 @@ read_partial_die (const struct die_reader_specs *reader, case DW_AT_extension: part_die->has_specification = 1; part_die->spec_offset = dwarf2_get_ref_die_offset (&attr); + part_die->spec_is_dwz = (attr.form == DW_FORM_GNU_ref_alt + || cu->per_cu->is_dwz); break; case DW_AT_sibling: /* Ignore absolute siblings, they might point outside of @@ -12449,7 +12644,11 @@ read_partial_die (const struct die_reader_specs *reader, case DW_AT_import: if (part_die->tag == DW_TAG_imported_unit) - part_die->d.offset = dwarf2_get_ref_die_offset (&attr); + { + part_die->d.offset = dwarf2_get_ref_die_offset (&attr); + part_die->is_dwz = (attr.form == DW_FORM_GNU_ref_alt + || cu->per_cu->is_dwz); + } break; default: @@ -12520,13 +12719,14 @@ find_partial_die_in_comp_unit (sect_offset offset, struct dwarf2_cu *cu) DW_FORM_ref_sig8). */ static struct partial_die_info * -find_partial_die (sect_offset offset, struct dwarf2_cu *cu) +find_partial_die (sect_offset offset, int offset_in_dwz, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct dwarf2_per_cu_data *per_cu = NULL; struct partial_die_info *pd = NULL; - if (offset_in_cu_p (&cu->header, offset)) + if (offset_in_dwz == cu->per_cu->is_dwz + && offset_in_cu_p (&cu->header, offset)) { pd = find_partial_die_in_comp_unit (offset, cu); if (pd != NULL) @@ -12545,7 +12745,8 @@ find_partial_die (sect_offset offset, struct dwarf2_cu *cu) (long) cu->header.offset.sect_off, (long) offset.sect_off, bfd_get_filename (objfile->obfd)); } - per_cu = dwarf2_find_containing_comp_unit (offset, objfile); + per_cu = dwarf2_find_containing_comp_unit (offset, offset_in_dwz, + objfile); if (per_cu->cu == NULL || per_cu->cu->partial_dies == NULL) load_partial_comp_unit (per_cu); @@ -12603,7 +12804,8 @@ guess_partial_die_structure_name (struct partial_die_info *struct_pdi, real_pdi = struct_pdi; while (real_pdi->has_specification) - real_pdi = find_partial_die (real_pdi->spec_offset, cu); + real_pdi = find_partial_die (real_pdi->spec_offset, + real_pdi->spec_is_dwz, cu); if (real_pdi->die_parent != NULL) return; @@ -12651,7 +12853,8 @@ fixup_partial_die (struct partial_die_info *part_die, { struct partial_die_info *spec_die; - spec_die = find_partial_die (part_die->spec_offset, cu); + spec_die = find_partial_die (part_die->spec_offset, + part_die->spec_is_dwz, cu); fixup_partial_die (spec_die, cu); @@ -12739,6 +12942,10 @@ read_attribute_value (const struct die_reader_specs *reader, &cu->header, &bytes_read); info_ptr += bytes_read; break; + case DW_FORM_GNU_ref_alt: + DW_UNSND (attr) = read_offset (abfd, info_ptr, &cu->header, &bytes_read); + info_ptr += bytes_read; + break; case DW_FORM_addr: DW_ADDR (attr) = read_address (abfd, info_ptr, cu, &bytes_read); info_ptr += bytes_read; @@ -12781,10 +12988,25 @@ read_attribute_value (const struct die_reader_specs *reader, info_ptr += bytes_read; break; case DW_FORM_strp: - DW_STRING (attr) = read_indirect_string (abfd, info_ptr, cu_header, - &bytes_read); - DW_STRING_IS_CANONICAL (attr) = 0; - info_ptr += bytes_read; + if (!cu->per_cu->is_dwz) + { + DW_STRING (attr) = read_indirect_string (abfd, info_ptr, cu_header, + &bytes_read); + DW_STRING_IS_CANONICAL (attr) = 0; + info_ptr += bytes_read; + break; + } + /* FALLTHROUGH */ + case DW_FORM_GNU_strp_alt: + { + struct dwz_file *dwz = dwarf2_get_dwz_file (); + LONGEST str_offset = read_offset (abfd, info_ptr, cu_header, + &bytes_read); + + DW_STRING (attr) = read_indirect_string_from_dwz (dwz, str_offset); + DW_STRING_IS_CANONICAL (attr) = 0; + info_ptr += bytes_read; + } break; case DW_FORM_exprloc: case DW_FORM_block: @@ -12896,6 +13118,10 @@ read_attribute_value (const struct die_reader_specs *reader, bfd_get_filename (abfd)); } + /* Super hack. */ + if (cu->per_cu->is_dwz && is_ref_attr (attr)) + attr->form = DW_FORM_GNU_ref_alt; + /* We have seen instances where the compiler tried to emit a byte size attribute of -1 which ended up being encoded as an unsigned 0xffffffff. Although 0xffffffff is technically a valid size value, @@ -13192,6 +13418,30 @@ read_indirect_string_at_offset (bfd *abfd, LONGEST str_offset) return (char *) (dwarf2_per_objfile->str.buffer + str_offset); } +/* Read a string at offset STR_OFFSET in the .debug_str section from + the .dwz file DWZ. Throw an error if the offset is too large. If + the string consists of a single NUL byte, return NULL; otherwise + return a pointer to the string. */ + +static char * +read_indirect_string_from_dwz (struct dwz_file *dwz, LONGEST str_offset) +{ + dwarf2_read_section (dwarf2_per_objfile->objfile, &dwz->str); + + if (dwz->str.buffer == NULL) + error (_("DW_FORM_GNU_strp_alt used without .debug_str " + "section [in module %s]"), + bfd_get_filename (dwz->dwz_bfd)); + if (str_offset >= dwz->str.size) + error (_("DW_FORM_GNU_strp_alt pointing outside of " + ".debug_str section [in module %s]"), + bfd_get_filename (dwz->dwz_bfd)); + gdb_assert (HOST_CHAR_BIT == 8); + if (dwz->str.buffer[str_offset] == '\0') + return NULL; + return (char *) (dwz->str.buffer + str_offset); +} + static char * read_indirect_string (bfd *abfd, gdb_byte *buf, const struct comp_unit_head *cu_header, @@ -13663,6 +13913,30 @@ add_file_name (struct line_header *lh, fe->symtab = NULL; } +/* A convenience function to find the proper .debug_line section for a + CU. */ + +static struct dwarf2_section_info * +get_debug_line_section (struct dwarf2_cu *cu) +{ + struct dwarf2_section_info *section; + + /* For TUs in DWO files, the DW_AT_stmt_list attribute lives in the + DWO file. */ + if (cu->dwo_unit && cu->per_cu->is_debug_types) + section = &cu->dwo_unit->dwo_file->sections.line; + else if (cu->per_cu->is_dwz) + { + struct dwz_file *dwz = dwarf2_get_dwz_file (); + + section = &dwz->line; + } + else + section = &dwarf2_per_objfile->line; + + return section; +} + /* Read the statement program header starting at OFFSET in .debug_line, or .debug_line.dwo. Return a pointer to a struct line_header, allocated using xmalloc. @@ -13683,13 +13957,7 @@ dwarf_decode_line_header (unsigned int offset, struct dwarf2_cu *cu) struct dwarf2_section_info *section; bfd *abfd; - /* For TUs in DWO files, the DW_AT_stmt_list attribute lives in the - DWO file. */ - if (cu->dwo_unit && cu->per_cu->is_debug_types) - section = &cu->dwo_unit->dwo_file->sections.line; - else - section = &dwarf2_per_objfile->line; - + section = get_debug_line_section (cu); dwarf2_read_section (dwarf2_per_objfile->objfile, section); if (section->buffer == NULL) { @@ -14014,7 +14282,7 @@ dwarf_decode_lines_1 (struct line_header *lh, const char *comp_dir, GCd by the linker. Ignore it. PR gdb/12528 */ long line_offset - = line_ptr - dwarf2_per_objfile->line.buffer; + = line_ptr - get_debug_line_section (cu)->buffer; complaint (&symfile_complaints, _(".debug_line address at offset 0x%lx is 0 " @@ -14860,6 +15128,7 @@ dwarf2_const_value_attr (struct attribute *attr, struct type *type, case DW_FORM_string: case DW_FORM_strp: case DW_FORM_GNU_str_index: + case DW_FORM_GNU_strp_alt: /* DW_STRING is already allocated on the objfile obstack, point directly to it. */ *bytes = (gdb_byte *) DW_STRING (attr); @@ -15046,7 +15315,15 @@ lookup_die_type (struct die_info *die, struct attribute *attr, /* First see if we have it cached. */ - if (is_ref_attr (attr)) + if (attr->form == DW_FORM_GNU_ref_alt) + { + struct dwarf2_per_cu_data *per_cu; + sect_offset offset = dwarf2_get_ref_die_offset (attr); + + per_cu = dwarf2_find_containing_comp_unit (offset, 1, cu->objfile); + this_type = get_die_type_at_offset (offset, per_cu); + } + else if (is_ref_attr (attr)) { sect_offset offset = dwarf2_get_ref_die_offset (attr); @@ -15819,6 +16096,10 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die) fprintf_unfiltered (f, "ref address: "); fputs_filtered (hex_string (DW_UNSND (&die->attrs[i])), f); break; + case DW_FORM_GNU_ref_alt: + fprintf_unfiltered (f, "alt ref address: "); + fputs_filtered (hex_string (DW_UNSND (&die->attrs[i])), f); + break; case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: @@ -15850,6 +16131,7 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die) case DW_FORM_string: case DW_FORM_strp: case DW_FORM_GNU_str_index: + case DW_FORM_GNU_strp_alt: fprintf_unfiltered (f, "string: \"%s\" (%s canonicalized)", DW_STRING (&die->attrs[i]) ? DW_STRING (&die->attrs[i]) : "", @@ -15953,6 +16235,7 @@ is_ref_attr (struct attribute *attr) case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: + case DW_FORM_GNU_ref_alt: return 1; default: return 0; @@ -16030,7 +16313,8 @@ follow_die_ref_or_sig (struct die_info *src_die, struct attribute *attr, Returns NULL if OFFSET is invalid. */ static struct die_info * -follow_die_offset (sect_offset offset, struct dwarf2_cu **ref_cu) +follow_die_offset (sect_offset offset, int offset_in_dwz, + struct dwarf2_cu **ref_cu) { struct die_info temp_die; struct dwarf2_cu *target_cu, *cu = *ref_cu; @@ -16047,11 +16331,13 @@ follow_die_offset (sect_offset offset, struct dwarf2_cu **ref_cu) if (! offset_in_cu_p (&cu->header, offset)) return NULL; } - else if (! offset_in_cu_p (&cu->header, offset)) + else if (offset_in_dwz != cu->per_cu->is_dwz + || ! offset_in_cu_p (&cu->header, offset)) { struct dwarf2_per_cu_data *per_cu; - per_cu = dwarf2_find_containing_comp_unit (offset, cu->objfile); + per_cu = dwarf2_find_containing_comp_unit (offset, offset_in_dwz, + cu->objfile); /* If necessary, add it to the queue and load its DIEs. */ if (maybe_queue_comp_unit (cu, per_cu, cu->language)) @@ -16083,7 +16369,10 @@ follow_die_ref (struct die_info *src_die, struct attribute *attr, struct dwarf2_cu *cu = *ref_cu; struct die_info *die; - die = follow_die_offset (offset, ref_cu); + die = follow_die_offset (offset, + (attr->form == DW_FORM_GNU_ref_alt + || cu->per_cu->is_dwz), + ref_cu); if (!die) error (_("Dwarf Error: Cannot find DIE at 0x%x referenced from DIE " "at 0x%x [in module %s]"), @@ -16114,7 +16403,7 @@ dwarf2_fetch_die_location_block (cu_offset offset_in_cu, load_cu (per_cu); cu = per_cu->cu; - die = follow_die_offset (offset, &cu); + die = follow_die_offset (offset, per_cu->is_dwz, &cu); if (!die) error (_("Dwarf Error: Cannot find DIE at 0x%x referenced in module %s"), offset.sect_off, per_cu->objfile->name); @@ -16908,6 +17197,7 @@ skip_form_bytes (bfd *abfd, gdb_byte *bytes, gdb_byte *buffer_end, case DW_FORM_sec_offset: case DW_FORM_strp: + case DW_FORM_GNU_strp_alt: bytes += offset_size; break; @@ -17063,7 +17353,7 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, struct macro_source_file *current_file, struct line_header *lh, char *comp_dir, struct dwarf2_section_info *section, - int section_is_gnu, + int section_is_gnu, int section_is_dwz, unsigned int offset_size, struct objfile *objfile, htab_t include_hash) @@ -17114,6 +17404,8 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, case DW_MACRO_GNU_undef: case DW_MACRO_GNU_define_indirect: case DW_MACRO_GNU_undef_indirect: + case DW_MACRO_GNU_define_indirect_alt: + case DW_MACRO_GNU_undef_indirect_alt: { unsigned int bytes_read; int line; @@ -17136,11 +17428,20 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, str_offset = read_offset_1 (abfd, mac_ptr, offset_size); mac_ptr += offset_size; - body = read_indirect_string_at_offset (abfd, str_offset); + if (macinfo_type == DW_MACRO_GNU_define_indirect_alt + || macinfo_type == DW_MACRO_GNU_undef_indirect_alt) + { + struct dwz_file *dwz = dwarf2_get_dwz_file (); + + body = read_indirect_string_from_dwz (dwz, str_offset); + } + else + body = read_indirect_string_at_offset (abfd, str_offset); } is_define = (macinfo_type == DW_MACRO_GNU_define - || macinfo_type == DW_MACRO_GNU_define_indirect); + || macinfo_type == DW_MACRO_GNU_define_indirect + || macinfo_type == DW_MACRO_GNU_define_indirect_alt); if (! current_file) { /* DWARF violation as no main source is present. */ @@ -17164,7 +17465,8 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, else { gdb_assert (macinfo_type == DW_MACRO_GNU_undef - || macinfo_type == DW_MACRO_GNU_undef_indirect); + || macinfo_type == DW_MACRO_GNU_undef_indirect + || macinfo_type == DW_MACRO_GNU_undef_indirect_alt); macro_undef (current_file, line, body); } } @@ -17239,6 +17541,7 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, break; case DW_MACRO_GNU_transparent_include: + case DW_MACRO_GNU_transparent_include_alt: { LONGEST offset; void **slot; @@ -17257,13 +17560,32 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, } else { + bfd *include_bfd = abfd; + struct dwarf2_section_info *include_section = section; + struct dwarf2_section_info alt_section; + gdb_byte *include_mac_end = mac_end; + int is_dwz = section_is_dwz; + *slot = mac_ptr; - dwarf_decode_macro_bytes (abfd, - section->buffer + offset, - mac_end, current_file, + if (macinfo_type == DW_MACRO_GNU_transparent_include_alt) + { + struct dwz_file *dwz = dwarf2_get_dwz_file (); + + dwarf2_read_section (dwarf2_per_objfile->objfile, + &dwz->macro); + + include_bfd = dwz->macro.asection->owner; + include_section = &dwz->macro; + include_mac_end = dwz->macro.buffer + dwz->macro.size; + is_dwz = 1; + } + + dwarf_decode_macro_bytes (include_bfd, + include_section->buffer + offset, + include_mac_end, current_file, lh, comp_dir, - section, section_is_gnu, + section, section_is_gnu, is_dwz, offset_size, objfile, include_hash); htab_remove_elt (include_hash, mac_ptr); @@ -17482,7 +17804,8 @@ dwarf_decode_macros (struct dwarf2_cu *cu, unsigned int offset, slot = htab_find_slot (include_hash, mac_ptr, INSERT); *slot = mac_ptr; dwarf_decode_macro_bytes (abfd, mac_ptr, mac_end, - current_file, lh, comp_dir, section, section_is_gnu, + current_file, lh, comp_dir, section, + section_is_gnu, 0, offset_size, objfile, include_hash); do_cleanups (cleanup); } @@ -17737,28 +18060,35 @@ dwarf2_per_cu_text_offset (struct dwarf2_per_cu_data *per_cu) static struct dwarf2_per_cu_data * dwarf2_find_containing_comp_unit (sect_offset offset, + unsigned int offset_in_dwz, struct objfile *objfile) { struct dwarf2_per_cu_data *this_cu; int low, high; + const sect_offset *cu_off; low = 0; high = dwarf2_per_objfile->n_comp_units - 1; while (high > low) { + struct dwarf2_per_cu_data *mid_cu; int mid = low + (high - low) / 2; - if (dwarf2_per_objfile->all_comp_units[mid]->offset.sect_off - >= offset.sect_off) + mid_cu = dwarf2_per_objfile->all_comp_units[mid]; + cu_off = &mid_cu->offset; + if (mid_cu->is_dwz > offset_in_dwz + || (mid_cu->is_dwz == offset_in_dwz + && cu_off->sect_off >= offset.sect_off)) high = mid; else low = mid + 1; } gdb_assert (low == high); - if (dwarf2_per_objfile->all_comp_units[low]->offset.sect_off - > offset.sect_off) + this_cu = dwarf2_per_objfile->all_comp_units[low]; + cu_off = &this_cu->offset; + if (this_cu->is_dwz != offset_in_dwz || cu_off->sect_off > offset.sect_off) { - if (low == 0) + if (low == 0 || this_cu->is_dwz != offset_in_dwz) error (_("Dwarf Error: could not find partial DIE containing " "offset 0x%lx [in module %s]"), (long) offset.sect_off, bfd_get_filename (objfile->obfd)); @@ -18216,6 +18546,9 @@ dwarf2_per_objfile_free (struct objfile *objfile, void *d) if (data->dwo_files) free_dwo_files (data->dwo_files, objfile); + + if (data->dwz_file && data->dwz_file->dwz_bfd) + gdb_bfd_unref (data->dwz_file->dwz_bfd); } -- 2.30.2