aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog47
-rw-r--r--gdb/buildsym.c14
-rw-r--r--gdb/buildsym.h3
-rw-r--r--gdb/dwarf2read.c485
4 files changed, 467 insertions, 82 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 10dacd6..a182ac2 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,52 @@
2012-07-18 Tom Tromey <tromey@redhat.com>
+ * dwarf2read.c (struct dwarf2_per_objfile) <dwz_file>: New field.
+ (struct dwarf2_per_cu_data) <length>: No longer bitfield.
+ <is_dwz>: New field.
+ (struct dwz_file): New.
+ (struct partial_die_info) <is_dwz, spec_is_dwz>: 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 <tromey@redhat.com>
+
* dwarf2read.c: Don't include zlib.h or sys/mman.h.
(pagesize): Remove.
(struct dwarf2_section_info) <map_addr, map_len>: Remove.
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index d547012..e4882fb 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 162ee8c..33b34c8 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 da23cc4..ee25219 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);
}