#include "defs.h"
#include "bfd.h"
+#include "elf-bfd.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "objfiles.h"
#include "gdb/gdb-index.h"
#include <ctype.h>
#include "gdb_bfd.h"
+#include "f-lang.h"
#include <fcntl.h>
#include "gdb_string.h"
#include "gdb_assert.h"
#include <sys/types.h>
-#ifdef HAVE_ZLIB_H
-#include <zlib.h>
-#endif
-#ifdef HAVE_MMAP
-#include <sys/mman.h>
-#ifndef MAP_FAILED
-#define MAP_FAILED ((void *) -1)
-#endif
-#endif
typedef struct symbol *symbolp;
DEF_VEC_P (symbolp);
static int dwarf2_read_debug = 0;
/* When non-zero, dump DIEs after they are read in. */
-static int dwarf2_die_debug = 0;
+static unsigned int dwarf2_die_debug = 0;
/* When non-zero, cross-check physname against demangler. */
static int check_physname = 0;
/* When non-zero, do not reject deprecated .gdb_index sections. */
-int use_deprecated_index_sections = 0;
-
-static int pagesize;
+static int use_deprecated_index_sections = 0;
/* When set, the file that we're processing is known to have debugging
info for C++ namespaces. GCC 3.3.x did not produce this information,
asection *asection;
gdb_byte *buffer;
bfd_size_type size;
- /* Not NULL if the section was actually mmapped. */
- void *map_addr;
- /* Page aligned size of mmapped area. */
- bfd_size_type map_len;
/* True if we have tried to read this section. */
int readin;
};
This is NULL if the table hasn't been allocated yet. */
htab_t dwo_files;
+ /* Non-zero if we've check for whether there is a DWP file. */
+ int dwp_checked;
+
+ /* The DWP file if there is one, or NULL. */
+ struct dwp_file *dwp_file;
+
+ /* 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;
23
};
-/* List of DWO sections. */
+/* List of DWO/DWP sections. */
-static const struct dwo_section_names
+static const struct dwop_section_names
{
struct dwarf2_section_names abbrev_dwo;
struct dwarf2_section_names info_dwo;
struct dwarf2_section_names str_dwo;
struct dwarf2_section_names str_offsets_dwo;
struct dwarf2_section_names types_dwo;
+ struct dwarf2_section_names cu_index;
+ struct dwarf2_section_names tu_index;
}
-dwo_section_names =
+dwop_section_names =
{
{ ".debug_abbrev.dwo", ".zdebug_abbrev.dwo" },
{ ".debug_info.dwo", ".zdebug_info.dwo" },
{ ".debug_str.dwo", ".zdebug_str.dwo" },
{ ".debug_str_offsets.dwo", ".zdebug_str_offsets.dwo" },
{ ".debug_types.dwo", ".zdebug_types.dwo" },
+ { ".debug_cu_index", ".zdebug_cu_index" },
+ { ".debug_tu_index", ".zdebug_tu_index" },
};
/* local data types */
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. */
/* 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. */
struct symtab **symtabs;
};
-/* These sections are what may appear in a "dwo" file. */
+/* These sections are what may appear in a DWO file. */
struct dwo_sections
{
struct dwarf2_section_info abbrev;
- struct dwarf2_section_info info;
struct dwarf2_section_info line;
struct dwarf2_section_info loc;
struct dwarf2_section_info macinfo;
struct dwarf2_section_info macro;
struct dwarf2_section_info str;
struct dwarf2_section_info str_offsets;
+ /* In the case of a virtual DWO file, these two are unused. */
+ struct dwarf2_section_info info;
VEC (dwarf2_section_info_def) *types;
};
cu_offset type_offset_in_tu;
};
-/* Data for one DWO file. */
+/* Data for one DWO file.
+ This includes virtual DWO files that have been packaged into a
+ DWP file. */
struct dwo_file
{
- /* The DW_AT_GNU_dwo_name attribute.
- We don't manage space for this, it's an attribute. */
- const char *dwo_name;
+ /* The DW_AT_GNU_dwo_name attribute. This is the hash key.
+ For virtual DWO files the name is constructed from the section offsets
+ of abbrev,line,loc,str_offsets so that we combine virtual DWO files
+ from related CU+TUs. */
+ const char *name;
- /* The bfd, when the file is open. Otherwise this is NULL. */
- bfd *dwo_bfd;
+ /* The bfd, when the file is open. Otherwise this is NULL.
+ This is unused(NULL) for virtual DWO files where we use dwp_file.dbfd. */
+ bfd *dbfd;
/* Section info for this file. */
struct dwo_sections sections;
htab_t tus;
};
+/* These sections are what may appear in a DWP file. */
+
+struct dwp_sections
+{
+ struct dwarf2_section_info str;
+ struct dwarf2_section_info cu_index;
+ struct dwarf2_section_info tu_index;
+ /* The .debug_info.dwo, .debug_types.dwo, and other sections are referenced
+ by section number. We don't need to record them here. */
+};
+
+/* These sections are what may appear in a virtual DWO file. */
+
+struct virtual_dwo_sections
+{
+ struct dwarf2_section_info abbrev;
+ struct dwarf2_section_info line;
+ struct dwarf2_section_info loc;
+ struct dwarf2_section_info macinfo;
+ struct dwarf2_section_info macro;
+ struct dwarf2_section_info str_offsets;
+ /* Each DWP hash table entry records one CU or one TU.
+ That is recorded here, and copied to dwo_unit.info_or_types_section. */
+ struct dwarf2_section_info info_or_types;
+};
+
+/* Contents of DWP hash tables. */
+
+struct dwp_hash_table
+{
+ uint32_t nr_units, nr_slots;
+ const gdb_byte *hash_table, *unit_table, *section_pool;
+};
+
+/* Data for one DWP file. */
+
+struct dwp_file
+{
+ /* Name of the file. */
+ const char *name;
+
+ /* The bfd, when the file is open. Otherwise this is NULL. */
+ bfd *dbfd;
+
+ /* Section info for this file. */
+ struct dwp_sections sections;
+
+ /* Table of CUs in the file. */
+ const struct dwp_hash_table *cus;
+
+ /* Table of TUs in the file. */
+ const struct dwp_hash_table *tus;
+
+ /* Table of loaded CUs/TUs. Each entry is a struct dwo_unit *. */
+ htab_t loaded_cutus;
+
+ /* Table to map ELF section numbers to their sections. */
+ unsigned int num_sections;
+ asection **elf_sections;
+};
+
+/* 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;
+ struct dwarf2_section_info gdb_index;
+
+ /* 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
/* The CU of the DIE we are parsing. */
struct dwarf2_cu *cu;
- /* Non-NULL if reading a DWO file. */
+ /* Non-NULL if reading a DWO file (including one packaged into a DWP). */
struct dwo_file *dwo_file;
/* The section the die comes from.
/* 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;
/* Blocks are a bunch of untyped bytes. */
struct dwarf_block
{
- unsigned int size;
+ size_t size;
/* Valid only if SIZE is not zero. */
gdb_byte *data;
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 *,
struct attribute *, struct attr_abbrev *,
gdb_byte *);
-static unsigned int read_1_byte (bfd *, gdb_byte *);
+static unsigned int read_1_byte (bfd *, const gdb_byte *);
-static int read_1_signed_byte (bfd *, gdb_byte *);
+static int read_1_signed_byte (bfd *, const gdb_byte *);
-static unsigned int read_2_bytes (bfd *, gdb_byte *);
+static unsigned int read_2_bytes (bfd *, const gdb_byte *);
-static unsigned int read_4_bytes (bfd *, gdb_byte *);
+static unsigned int read_4_bytes (bfd *, const gdb_byte *);
-static ULONGEST read_8_bytes (bfd *, gdb_byte *);
+static ULONGEST read_8_bytes (bfd *, const gdb_byte *);
static CORE_ADDR read_address (bfd *, gdb_byte *ptr, struct dwarf2_cu *,
unsigned int *);
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 *);
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);
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,
static htab_t allocate_dwo_unit_table (struct objfile *objfile);
static struct dwo_unit *lookup_dwo_comp_unit
- (struct dwarf2_per_cu_data *, char *, const char *, ULONGEST);
+ (struct dwarf2_per_cu_data *, const char *, const char *, ULONGEST);
static struct dwo_unit *lookup_dwo_type_unit
- (struct signatured_type *, char *, const char *);
+ (struct signatured_type *, const char *, const char *);
static void free_dwo_file_cleanup (void *);
-static void munmap_section_buffer (struct dwarf2_section_info *);
-
static void process_cu_includes (void);
#if WORDS_BIGENDIAN
dwarf2_locate_sections (bfd *abfd, asection *sectp, void *vnames)
{
const struct dwarf2_debug_sections *names;
+ flagword aflag = bfd_get_section_flags (abfd, sectp);
if (vnames == NULL)
names = &dwarf2_elf_names;
else
names = (const struct dwarf2_debug_sections *) vnames;
- if (section_is_p (sectp->name, &names->info))
+ if ((aflag & SEC_HAS_CONTENTS) == 0)
+ {
+ }
+ else if (section_is_p (sectp->name, &names->info))
{
dwarf2_per_objfile->info.asection = sectp;
dwarf2_per_objfile->info.size = bfd_get_section_size (sectp);
}
else if (section_is_p (sectp->name, &names->eh_frame))
{
- flagword aflag = bfd_get_section_flags (abfd, sectp);
-
- if (aflag & SEC_HAS_CONTENTS)
- {
- dwarf2_per_objfile->eh_frame.asection = sectp;
- dwarf2_per_objfile->eh_frame.size = bfd_get_section_size (sectp);
- }
+ dwarf2_per_objfile->eh_frame.asection = sectp;
+ dwarf2_per_objfile->eh_frame.size = bfd_get_section_size (sectp);
}
else if (section_is_p (sectp->name, &names->ranges))
{
dwarf2_per_objfile->has_section_at_zero = 1;
}
-/* Decompress a section that was compressed using zlib. Store the
- decompressed buffer, and its size, in OUTBUF and OUTSIZE. */
-
-static void
-zlib_decompress_section (struct objfile *objfile, asection *sectp,
- gdb_byte **outbuf, bfd_size_type *outsize)
-{
- bfd *abfd = sectp->owner;
-#ifndef HAVE_ZLIB_H
- error (_("Support for zlib-compressed DWARF data (from '%s') "
- "is disabled in this copy of GDB"),
- bfd_get_filename (abfd));
-#else
- bfd_size_type compressed_size = bfd_get_section_size (sectp);
- gdb_byte *compressed_buffer = xmalloc (compressed_size);
- struct cleanup *cleanup = make_cleanup (xfree, compressed_buffer);
- bfd_size_type uncompressed_size;
- gdb_byte *uncompressed_buffer;
- z_stream strm;
- int rc;
- int header_size = 12;
-
- if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0
- || bfd_bread (compressed_buffer,
- compressed_size, abfd) != compressed_size)
- error (_("Dwarf Error: Can't read DWARF data from '%s'"),
- bfd_get_filename (abfd));
-
- /* Read the zlib header. In this case, it should be "ZLIB" followed
- by the uncompressed section size, 8 bytes in big-endian order. */
- if (compressed_size < header_size
- || strncmp (compressed_buffer, "ZLIB", 4) != 0)
- error (_("Dwarf Error: Corrupt DWARF ZLIB header from '%s'"),
- bfd_get_filename (abfd));
- uncompressed_size = compressed_buffer[4]; uncompressed_size <<= 8;
- uncompressed_size += compressed_buffer[5]; uncompressed_size <<= 8;
- uncompressed_size += compressed_buffer[6]; uncompressed_size <<= 8;
- uncompressed_size += compressed_buffer[7]; uncompressed_size <<= 8;
- uncompressed_size += compressed_buffer[8]; uncompressed_size <<= 8;
- uncompressed_size += compressed_buffer[9]; uncompressed_size <<= 8;
- uncompressed_size += compressed_buffer[10]; uncompressed_size <<= 8;
- uncompressed_size += compressed_buffer[11];
-
- /* It is possible the section consists of several compressed
- buffers concatenated together, so we uncompress in a loop. */
- strm.zalloc = NULL;
- strm.zfree = NULL;
- strm.opaque = NULL;
- strm.avail_in = compressed_size - header_size;
- strm.next_in = (Bytef*) compressed_buffer + header_size;
- strm.avail_out = uncompressed_size;
- uncompressed_buffer = obstack_alloc (&objfile->objfile_obstack,
- uncompressed_size);
- rc = inflateInit (&strm);
- while (strm.avail_in > 0)
- {
- if (rc != Z_OK)
- error (_("Dwarf Error: setting up DWARF uncompression in '%s': %d"),
- bfd_get_filename (abfd), rc);
- strm.next_out = ((Bytef*) uncompressed_buffer
- + (uncompressed_size - strm.avail_out));
- rc = inflate (&strm, Z_FINISH);
- if (rc != Z_STREAM_END)
- error (_("Dwarf Error: zlib error uncompressing from '%s': %d"),
- bfd_get_filename (abfd), rc);
- rc = inflateReset (&strm);
- }
- rc = inflateEnd (&strm);
- if (rc != Z_OK
- || strm.avail_out != 0)
- error (_("Dwarf Error: concluding DWARF uncompression in '%s': %d"),
- bfd_get_filename (abfd), rc);
-
- do_cleanups (cleanup);
- *outbuf = uncompressed_buffer;
- *outsize = uncompressed_size;
-#endif
-}
-
/* A helper function that decides whether a section is empty,
or not present. */
if (info->readin)
return;
info->buffer = NULL;
- info->map_addr = NULL;
info->readin = 1;
if (dwarf2_section_empty_p (info))
return;
- /* Note that ABFD may not be from OBJFILE, e.g. a DWO section. */
abfd = sectp->owner;
- /* Check if the file has a 4-byte header indicating compression. */
- if (info->size > sizeof (header)
- && bfd_seek (abfd, sectp->filepos, SEEK_SET) == 0
- && bfd_bread (header, sizeof (header), abfd) == sizeof (header))
- {
- /* Upon decompression, update the buffer and its size. */
- if (strncmp (header, "ZLIB", sizeof (header)) == 0)
- {
- zlib_decompress_section (objfile, sectp, &info->buffer,
- &info->size);
- return;
- }
- }
-
-#ifdef HAVE_MMAP
- if (pagesize == 0)
- pagesize = getpagesize ();
-
- /* Only try to mmap sections which are large enough: we don't want to
- waste space due to fragmentation. Also, only try mmap for sections
- without relocations. */
-
- if (info->size > 4 * pagesize && (sectp->flags & SEC_RELOC) == 0)
+ /* If the section has relocations, we must read it ourselves.
+ Otherwise we attach it to the BFD. */
+ if ((sectp->flags & SEC_RELOC) == 0)
{
- info->buffer = bfd_mmap (abfd, 0, info->size, PROT_READ,
- MAP_PRIVATE, sectp->filepos,
- &info->map_addr, &info->map_len);
+ const gdb_byte *bytes = gdb_bfd_map_section (sectp, &info->size);
- if ((caddr_t)info->buffer != MAP_FAILED)
- {
-#if HAVE_POSIX_MADVISE
- posix_madvise (info->map_addr, info->map_len, POSIX_MADV_WILLNEED);
-#endif
- return;
- }
+ /* We have to cast away const here for historical reasons.
+ Fixing dwarf2read to be const-correct would be quite nice. */
+ info->buffer = (gdb_byte *) bytes;
+ return;
}
-#endif
- /* If we get here, we are a normal, not-compressed section. */
- info->buffer = buf
- = obstack_alloc (&objfile->objfile_obstack, info->size);
+ buf = obstack_alloc (&objfile->objfile_obstack, info->size);
+ info->buffer = buf;
/* When debugging .o files, we may need to apply relocations; see
http://sourceware.org/ml/gdb-patches/2002-04/msg00136.html .
*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);
+ }
+ else if (section_is_p (sectp->name, &dwarf2_elf_names.gdb_index))
+ {
+ dwz_file->gdb_index.asection = sectp;
+ dwz_file->gdb_index.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;
+}
\f
/* DWARF quick_symbols_functions support. */
return 1;
}
-/* Read the CU list from the mapped index, and use it to create all
- the CU objects for this objfile. Return 0 if something went wrong,
- 1 if everything went ok. */
+/* A helper for create_cus_from_index that handles a given list of
+ CUs. */
static int
-create_cus_from_index (struct objfile *objfile, const gdb_byte *cu_list,
- offset_type cu_list_elements)
+create_cus_from_index_list (struct objfile *objfile,
+ const gdb_byte *cu_list, offset_type n_elements,
+ struct dwarf2_section_info *section,
+ int is_dwz,
+ int base_offset)
{
offset_type i;
- dwarf2_per_objfile->n_comp_units = cu_list_elements / 2;
- dwarf2_per_objfile->all_comp_units
- = obstack_alloc (&objfile->objfile_obstack,
- dwarf2_per_objfile->n_comp_units
- * sizeof (struct dwarf2_per_cu_data *));
-
- for (i = 0; i < cu_list_elements; i += 2)
+ for (i = 0; i < n_elements; i += 2)
{
struct dwarf2_per_cu_data *the_cu;
ULONGEST offset, length;
the_cu->offset.sect_off = offset;
the_cu->length = length;
the_cu->objfile = objfile;
- the_cu->info_or_types_section = &dwarf2_per_objfile->info;
+ the_cu->info_or_types_section = section;
the_cu->v.quick = OBSTACK_ZALLOC (&objfile->objfile_obstack,
struct dwarf2_per_cu_quick_data);
- dwarf2_per_objfile->all_comp_units[i / 2] = the_cu;
+ the_cu->is_dwz = is_dwz;
+ dwarf2_per_objfile->all_comp_units[base_offset + i / 2] = the_cu;
}
return 1;
}
+/* Read the CU list from the mapped index, and use it to create all
+ the CU objects for this objfile. Return 0 if something went wrong,
+ 1 if everything went ok. */
+
+static int
+create_cus_from_index (struct objfile *objfile,
+ const gdb_byte *cu_list, offset_type cu_list_elements,
+ const gdb_byte *dwz_list, offset_type dwz_elements)
+{
+ struct dwz_file *dwz;
+
+ dwarf2_per_objfile->n_comp_units = (cu_list_elements + dwz_elements) / 2;
+ dwarf2_per_objfile->all_comp_units
+ = obstack_alloc (&objfile->objfile_obstack,
+ dwarf2_per_objfile->n_comp_units
+ * sizeof (struct dwarf2_per_cu_data *));
+
+ if (!create_cus_from_index_list (objfile, cu_list, cu_list_elements,
+ &dwarf2_per_objfile->info, 0, 0))
+ return 0;
+
+ if (dwz_elements == 0)
+ return 1;
+
+ dwz = dwarf2_get_dwz_file ();
+ return create_cus_from_index_list (objfile, dwz_list, dwz_elements,
+ &dwz->info, 1, cu_list_elements / 2);
+}
+
/* Create the signatured type hash table from the index. */
static int
}
}
-/* Read the index file. If everything went ok, initialize the "quick"
- elements of all the CUs and return 1. Otherwise, return 0. */
+/* A helper function that reads the .gdb_index from SECTION and fills
+ in MAP. FILENAME is the name of the file containing the section;
+ it is used for error reporting. DEPRECATED_OK is nonzero if it is
+ ok to use deprecated sections.
+
+ CU_LIST, CU_LIST_ELEMENTS, TYPES_LIST, and TYPES_LIST_ELEMENTS are
+ out parameters that are filled in with information about the CU and
+ TU lists in the section.
+
+ Returns 1 if all went well, 0 otherwise. */
static int
-dwarf2_read_index (struct objfile *objfile)
+read_index_from_section (struct objfile *objfile,
+ const char *filename,
+ int deprecated_ok,
+ struct dwarf2_section_info *section,
+ struct mapped_index *map,
+ const gdb_byte **cu_list,
+ offset_type *cu_list_elements,
+ const gdb_byte **types_list,
+ offset_type *types_list_elements)
{
char *addr;
- struct mapped_index *map;
+ offset_type version;
offset_type *metadata;
- const gdb_byte *cu_list;
- const gdb_byte *types_list = NULL;
- offset_type version, cu_list_elements;
- offset_type types_list_elements = 0;
int i;
- if (dwarf2_section_empty_p (&dwarf2_per_objfile->gdb_index))
+ if (dwarf2_section_empty_p (section))
return 0;
/* Older elfutils strip versions could keep the section in the main
executable while splitting it for the separate debug info file. */
- if ((bfd_get_file_flags (dwarf2_per_objfile->gdb_index.asection)
- & SEC_HAS_CONTENTS) == 0)
+ if ((bfd_get_file_flags (section->asection) & SEC_HAS_CONTENTS) == 0)
return 0;
- dwarf2_read_section (objfile, &dwarf2_per_objfile->gdb_index);
+ dwarf2_read_section (objfile, section);
- addr = dwarf2_per_objfile->gdb_index.buffer;
+ addr = section->buffer;
/* Version check. */
version = MAYBE_SWAP (*(offset_type *) addr);
/* Versions earlier than 3 emitted every copy of a psymbol. This
if (!warning_printed)
{
warning (_("Skipping obsolete .gdb_index section in %s."),
- objfile->name);
+ filename);
warning_printed = 1;
}
return 0;
Versions earlier than 6 did not emit psymbols for inlined
functions. Using these files will cause GDB not to be able to
set breakpoints on inlined functions by name, so we ignore these
- indices unless the --use-deprecated-index-sections command line
- option was supplied. */
- if (version < 6 && !use_deprecated_index_sections)
+ indices unless the user has done
+ "set use-deprecated-index-sections on". */
+ if (version < 6 && !deprecated_ok)
{
static int warning_printed = 0;
if (!warning_printed)
{
- warning (_("Skipping deprecated .gdb_index section in %s, pass "
- "--use-deprecated-index-sections to use them anyway"),
- objfile->name);
+ warning (_("\
+Skipping deprecated .gdb_index section in %s.\n\
+Do \"set use-deprecated-index-sections on\" before the file is read\n\
+to use the section anyway."),
+ filename);
warning_printed = 1;
}
return 0;
if (version > 7)
return 0;
- map = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct mapped_index);
map->version = version;
- map->total_size = dwarf2_per_objfile->gdb_index.size;
+ map->total_size = section->size;
metadata = (offset_type *) (addr + sizeof (offset_type));
i = 0;
- cu_list = addr + MAYBE_SWAP (metadata[i]);
- cu_list_elements = ((MAYBE_SWAP (metadata[i + 1]) - MAYBE_SWAP (metadata[i]))
- / 8);
+ *cu_list = addr + MAYBE_SWAP (metadata[i]);
+ *cu_list_elements = ((MAYBE_SWAP (metadata[i + 1]) - MAYBE_SWAP (metadata[i]))
+ / 8);
++i;
- types_list = addr + MAYBE_SWAP (metadata[i]);
- types_list_elements = ((MAYBE_SWAP (metadata[i + 1])
- - MAYBE_SWAP (metadata[i]))
- / 8);
+ *types_list = addr + MAYBE_SWAP (metadata[i]);
+ *types_list_elements = ((MAYBE_SWAP (metadata[i + 1])
+ - MAYBE_SWAP (metadata[i]))
+ / 8);
++i;
map->address_table = addr + MAYBE_SWAP (metadata[i]);
map->constant_pool = addr + MAYBE_SWAP (metadata[i]);
+ return 1;
+}
+
+
+/* Read the index file. If everything went ok, initialize the "quick"
+ elements of all the CUs and return 1. Otherwise, return 0. */
+
+static int
+dwarf2_read_index (struct objfile *objfile)
+{
+ struct mapped_index local_map, *map;
+ const gdb_byte *cu_list, *types_list, *dwz_list = NULL;
+ offset_type cu_list_elements, types_list_elements, dwz_list_elements = 0;
+
+ if (!read_index_from_section (objfile, objfile->name,
+ use_deprecated_index_sections,
+ &dwarf2_per_objfile->gdb_index, &local_map,
+ &cu_list, &cu_list_elements,
+ &types_list, &types_list_elements))
+ return 0;
+
/* Don't use the index if it's empty. */
- if (map->symbol_table_slots == 0)
+ if (local_map.symbol_table_slots == 0)
return 0;
- if (!create_cus_from_index (objfile, cu_list, cu_list_elements))
+ /* If there is a .dwz file, read it so we can get its CU list as
+ well. */
+ if (bfd_get_section_by_name (objfile->obfd, ".gnu_debugaltlink") != NULL)
+ {
+ struct dwz_file *dwz = dwarf2_get_dwz_file ();
+ struct mapped_index dwz_map;
+ const gdb_byte *dwz_types_ignore;
+ offset_type dwz_types_elements_ignore;
+
+ if (!read_index_from_section (objfile, bfd_get_filename (dwz->dwz_bfd),
+ 1,
+ &dwz->gdb_index, &dwz_map,
+ &dwz_list, &dwz_list_elements,
+ &dwz_types_ignore,
+ &dwz_types_elements_ignore))
+ {
+ warning (_("could not read '.gdb_index' section from %s; skipping"),
+ bfd_get_filename (dwz->dwz_bfd));
+ return 0;
+ }
+ }
+
+ if (!create_cus_from_index (objfile, cu_list, cu_list_elements,
+ dwz_list, dwz_list_elements))
return 0;
if (types_list_elements)
return 0;
}
- create_addrmap_from_index (objfile, map);
+ create_addrmap_from_index (objfile, &local_map);
+
+ map = obstack_alloc (&objfile->objfile_obstack, sizeof (struct mapped_index));
+ *map = local_map;
dwarf2_per_objfile->index_table = map;
dwarf2_per_objfile->using_index = 1;
int is_static = GDB_INDEX_SYMBOL_STATIC_VALUE (cu_index_and_attrs);
gdb_index_symbol_kind symbol_kind =
GDB_INDEX_SYMBOL_KIND_VALUE (cu_index_and_attrs);
-
- if (want_specific_block
- && index->version >= 7
+ /* Only check the symbol attributes if they're present.
+ Indices prior to version 7 don't record them,
+ and indices >= 7 may elide them for certain symbols
+ (gold does this). */
+ int attrs_valid =
+ (index->version >= 7
+ && symbol_kind != GDB_INDEX_SYMBOL_KIND_NONE);
+
+ if (attrs_valid
+ && want_specific_block
&& want_static != is_static)
continue;
- /* Only check the symbol's kind if it has one.
- Indices prior to version 7 don't record it. */
- if (index->version >= 7)
+ /* Only check the symbol's kind if it has one. */
+ if (attrs_valid)
{
switch (domain)
{
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. */
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,
}
/* Create the hash table of all entries in the .debug_types section.
- DWO_FILE is a pointer to the DWO file for .debug_types.dwo, NULL otherwise.
+ DWO_FILE is a pointer to the DWO file for .debug_types.dwo,
+ NULL otherwise.
+ Note: This function processes DWO files only, not DWP files.
The result is a pointer to the hash table or NULL if there are
no types. */
{
bfd *abfd;
gdb_byte *info_ptr, *end_ptr;
+ struct dwarf2_section_info *abbrev_section;
dwarf2_read_section (objfile, section);
info_ptr = section->buffer;
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)
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)
{
/* Set up for reading the DWO CU/TU. */
cu->dwo_unit = dwo_unit;
section = dwo_unit->info_or_types_section;
+ dwarf2_read_section (objfile, section);
begin_info_ptr = info_ptr = section->buffer + dwo_unit->offset.sect_off;
dwo_abbrev_section = &dwo_unit->dwo_file->sections.abbrev;
init_cu_die_reader (&reader, cu, section, dwo_unit->dwo_file);
if (this_cu->is_debug_types)
{
ULONGEST signature;
+ cu_offset type_offset_in_tu;
info_ptr = read_and_check_type_unit_head (&cu->header, section,
dwo_abbrev_section,
info_ptr,
- &signature, NULL);
+ &signature,
+ &type_offset_in_tu);
gdb_assert (sig_type->signature == signature);
gdb_assert (dwo_unit->offset.sect_off == cu->header.offset.sect_off);
- gdb_assert (dwo_unit->length == get_cu_length (&cu->header));
+ /* For DWOs coming from DWP files, we don't know the CU length
+ nor the type's offset in the TU until now. */
+ dwo_unit->length = get_cu_length (&cu->header);
+ dwo_unit->type_offset_in_tu = type_offset_in_tu;
/* Establish the type offset that can be used to lookup the type.
For DWO files, we don't know it until now. */
dwo_abbrev_section,
info_ptr, 0);
gdb_assert (dwo_unit->offset.sect_off == cu->header.offset.sect_off);
- gdb_assert (dwo_unit->length == get_cu_length (&cu->header));
+ /* For DWOs coming from DWP files, we don't know the CU length
+ until now. */
+ dwo_unit->length = get_cu_length (&cu->header);
}
/* Discard the original CU's abbrev table, and read the DWO's. */
/* Read CU/TU THIS_CU in section SECTION,
but do not follow DW_AT_GNU_dwo_name if present.
- DWO_FILE, if non-NULL, is the DWO file to read (the caller is assumed to
- have already done the lookup to find the DWO file).
+ DWOP_FILE, if non-NULL, is the DWO/DWP file to read (the caller is assumed
+ to have already done the lookup to find the DWO/DWP file).
The caller is required to fill in THIS_CU->section, THIS_CU->offset, and
THIS_CU->is_debug_types, but nothing else.
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);
}
struct gdbarch *gdbarch = get_objfile_arch (objfile);
fprintf_unfiltered (gdb_stdlog,
- "Psymtab for %s unit @0x%x: 0x%s - 0x%s"
+ "Psymtab for %s unit @0x%x: %s - %s"
", %d global, %d static syms\n",
per_cu->is_debug_types ? "type" : "comp",
per_cu->offset.sect_off,
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. */
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,
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,
}
per_cu = dwarf2_find_containing_comp_unit (pdi->d.offset,
+ pdi->is_dwz,
cu->objfile);
/* Go read the partial unit, if needed. */
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)
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;
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:
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
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))
if (child->tag == DW_TAG_template_type_param)
{
- c_print_type (type, "", buf, -1, 0);
+ c_print_type (type, "", buf, -1, 0, &type_print_raw_options);
continue;
}
{
struct type *type = read_type_die (die, cu);
- c_type_print_args (type, buf, 1, cu->language);
+ c_type_print_args (type, buf, 1, cu->language,
+ &type_print_raw_options);
if (cu->language == language_java)
{
names. */
if (die->tag == DW_TAG_subprogram)
java_print_type (TYPE_TARGET_TYPE (type), "", buf,
- 0, 0);
+ 0, 0, &type_print_raw_options);
}
else if (cu->language == language_cplus)
{
}
}
\f
-/* DWO files. */
+/* DWO/DWP files.
+
+ http://gcc.gnu.org/wiki/DebugFission
+ http://gcc.gnu.org/wiki/DebugFissionDWP
+
+ To simplify handling of both DWO files ("object" files with the DWARF info)
+ and DWP files (a file with the DWOs packaged up into one file), we treat
+ DWP files as having a collection of virtual DWO files. */
static hashval_t
hash_dwo_file (const void *item)
{
const struct dwo_file *dwo_file = item;
- return htab_hash_string (dwo_file->dwo_name);
+ return htab_hash_string (dwo_file->name);
}
static int
const struct dwo_file *lhs = item_lhs;
const struct dwo_file *rhs = item_rhs;
- return strcmp (lhs->dwo_name, rhs->dwo_name) == 0;
+ return strcmp (lhs->name, rhs->name) == 0;
}
/* Allocate a hash table for DWO files. */
dummy_obstack_deallocate);
}
+/* Lookup DWO file DWO_NAME. */
+
+static void **
+lookup_dwo_file_slot (const char *dwo_name)
+{
+ struct dwo_file find_entry;
+ void **slot;
+
+ if (dwarf2_per_objfile->dwo_files == NULL)
+ dwarf2_per_objfile->dwo_files = allocate_dwo_file_hash_table ();
+
+ memset (&find_entry, 0, sizeof (find_entry));
+ find_entry.name = dwo_name;
+ slot = htab_find_slot (dwarf2_per_objfile->dwo_files, &find_entry, INSERT);
+
+ return slot;
+}
+
static hashval_t
hash_dwo_unit (const void *item)
{
dummy_obstack_deallocate);
}
-/* This function is mapped across the sections and remembers the offset and
- size of each of the DWO debugging sections we are interested in. */
-
-static void
-dwarf2_locate_dwo_sections (bfd *abfd, asection *sectp, void *dwo_file_ptr)
-{
- struct dwo_file *dwo_file = dwo_file_ptr;
- const struct dwo_section_names *names = &dwo_section_names;
-
- if (section_is_p (sectp->name, &names->abbrev_dwo))
- {
- dwo_file->sections.abbrev.asection = sectp;
- dwo_file->sections.abbrev.size = bfd_get_section_size (sectp);
- }
- else if (section_is_p (sectp->name, &names->info_dwo))
- {
- dwo_file->sections.info.asection = sectp;
- dwo_file->sections.info.size = bfd_get_section_size (sectp);
- }
- else if (section_is_p (sectp->name, &names->line_dwo))
- {
- dwo_file->sections.line.asection = sectp;
- dwo_file->sections.line.size = bfd_get_section_size (sectp);
- }
- else if (section_is_p (sectp->name, &names->loc_dwo))
- {
- dwo_file->sections.loc.asection = sectp;
- dwo_file->sections.loc.size = bfd_get_section_size (sectp);
- }
- else if (section_is_p (sectp->name, &names->macinfo_dwo))
- {
- dwo_file->sections.macinfo.asection = sectp;
- dwo_file->sections.macinfo.size = bfd_get_section_size (sectp);
- }
- else if (section_is_p (sectp->name, &names->macro_dwo))
- {
- dwo_file->sections.macro.asection = sectp;
- dwo_file->sections.macro.size = bfd_get_section_size (sectp);
- }
- else if (section_is_p (sectp->name, &names->str_dwo))
- {
- dwo_file->sections.str.asection = sectp;
- dwo_file->sections.str.size = bfd_get_section_size (sectp);
- }
- else if (section_is_p (sectp->name, &names->str_offsets_dwo))
- {
- dwo_file->sections.str_offsets.asection = sectp;
- dwo_file->sections.str_offsets.size = bfd_get_section_size (sectp);
- }
- else if (section_is_p (sectp->name, &names->types_dwo))
- {
- struct dwarf2_section_info type_section;
-
- memset (&type_section, 0, sizeof (type_section));
- type_section.asection = sectp;
- type_section.size = bfd_get_section_size (sectp);
- VEC_safe_push (dwarf2_section_info_def, dwo_file->sections.types,
- &type_section);
- }
-}
-
-/* Structure used to pass data to create_debug_info_hash_table_reader. */
+/* Structure used to pass data to create_dwo_debug_info_hash_table_reader. */
struct create_dwo_info_table_data
{
htab_t cu_htab;
};
-/* die_reader_func for create_debug_info_hash_table. */
+/* die_reader_func for create_dwo_debug_info_hash_table. */
static void
-create_debug_info_hash_table_reader (const struct die_reader_specs *reader,
- gdb_byte *info_ptr,
- struct die_info *comp_unit_die,
- int has_children,
- void *datap)
+create_dwo_debug_info_hash_table_reader (const struct die_reader_specs *reader,
+ gdb_byte *info_ptr,
+ struct die_info *comp_unit_die,
+ int has_children,
+ void *datap)
{
struct dwarf2_cu *cu = reader->cu;
struct objfile *objfile = dwarf2_per_objfile->objfile;
{
error (_("Dwarf Error: debug entry at offset 0x%x is missing"
" its dwo_id [in module %s]"),
- offset.sect_off, dwo_file->dwo_name);
+ offset.sect_off, dwo_file->name);
return;
}
" offset 0x%x, dwo_id 0x%s [in module %s]"),
offset.sect_off, dup_dwo_unit->offset.sect_off,
phex (dwo_unit->signature, sizeof (dwo_unit->signature)),
- dwo_file->dwo_name);
+ dwo_file->name);
}
else
*slot = dwo_unit;
sizeof (dwo_unit->signature)));
}
-/* Create a hash table to map DWO IDs to their CU entry in .debug_info.dwo. */
+/* Create a hash table to map DWO IDs to their CU entry in
+ .debug_info.dwo in DWO_FILE.
+ Note: This function processes DWO files only, not DWP files. */
static htab_t
-create_debug_info_hash_table (struct dwo_file *dwo_file)
+create_dwo_debug_info_hash_table (struct dwo_file *dwo_file)
{
struct objfile *objfile = dwarf2_per_objfile->objfile;
struct dwarf2_section_info *section = &dwo_file->sections.info;
init_cutu_and_read_dies_no_follow (&per_cu,
&dwo_file->sections.abbrev,
dwo_file,
- create_debug_info_hash_table_reader,
+ create_dwo_debug_info_hash_table_reader,
&create_dwo_info_table_data);
info_ptr += per_cu.length;
return cu_htab;
}
-/* Subroutine of open_dwo_file to simplify it.
+/* DWP file .debug_{cu,tu}_index section format:
+ [ref: http://gcc.gnu.org/wiki/DebugFissionDWP]
+
+ Both index sections have the same format, and serve to map a 64-bit
+ signature to a set of section numbers. Each section begins with a header,
+ followed by a hash table of 64-bit signatures, a parallel table of 32-bit
+ indexes, and a pool of 32-bit section numbers. The index sections will be
+ aligned at 8-byte boundaries in the file.
+
+ The index section header contains two unsigned 32-bit values (using the
+ byte order of the application binary):
+
+ N, the number of compilation units or type units in the index
+ M, the number of slots in the hash table
+
+ (We assume that N and M will not exceed 2^32 - 1.)
+
+ The size of the hash table, M, must be 2^k such that 2^k > 3*N/2.
+
+ The hash table begins at offset 8 in the section, and consists of an array
+ of M 64-bit slots. Each slot contains a 64-bit signature (using the byte
+ order of the application binary). Unused slots in the hash table are 0.
+ (We rely on the extreme unlikeliness of a signature being exactly 0.)
+
+ The parallel table begins immediately after the hash table
+ (at offset 8 + 8 * M from the beginning of the section), and consists of an
+ array of 32-bit indexes (using the byte order of the application binary),
+ corresponding 1-1 with slots in the hash table. Each entry in the parallel
+ table contains a 32-bit index into the pool of section numbers. For unused
+ hash table slots, the corresponding entry in the parallel table will be 0.
+
+ Given a 64-bit compilation unit signature or a type signature S, an entry
+ in the hash table is located as follows:
+
+ 1) Calculate a primary hash H = S & MASK(k), where MASK(k) is a mask with
+ the low-order k bits all set to 1.
+
+ 2) Calculate a secondary hash H' = (((S >> 32) & MASK(k)) | 1).
+
+ 3) If the hash table entry at index H matches the signature, use that
+ entry. If the hash table entry at index H is unused (all zeroes),
+ terminate the search: the signature is not present in the table.
+
+ 4) Let H = (H + H') modulo M. Repeat at Step 3.
+
+ Because M > N and H' and M are relatively prime, the search is guaranteed
+ to stop at an unused slot or find the match.
+
+ The pool of section numbers begins immediately following the hash table
+ (at offset 8 + 12 * M from the beginning of the section). The pool of
+ section numbers consists of an array of 32-bit words (using the byte order
+ of the application binary). Each item in the array is indexed starting
+ from 0. The hash table entry provides the index of the first section
+ number in the set. Additional section numbers in the set follow, and the
+ set is terminated by a 0 entry (section number 0 is not used in ELF).
+
+ In each set of section numbers, the .debug_info.dwo or .debug_types.dwo
+ section must be the first entry in the set, and the .debug_abbrev.dwo must
+ be the second entry. Other members of the set may follow in any order. */
+
+/* Create a hash table to map DWO IDs to their CU/TU entry in
+ .debug_{info,types}.dwo in DWP_FILE.
+ Returns NULL if there isn't one.
+ Note: This function processes DWP files only, not DWO files. */
+
+static struct dwp_hash_table *
+create_dwp_hash_table (struct dwp_file *dwp_file, int is_debug_types)
+{
+ struct objfile *objfile = dwarf2_per_objfile->objfile;
+ bfd *dbfd = dwp_file->dbfd;
+ char *index_ptr, *index_end;
+ struct dwarf2_section_info *index;
+ uint32_t version, nr_units, nr_slots;
+ struct dwp_hash_table *htab;
+
+ if (is_debug_types)
+ index = &dwp_file->sections.tu_index;
+ else
+ index = &dwp_file->sections.cu_index;
+
+ if (dwarf2_section_empty_p (index))
+ return NULL;
+ dwarf2_read_section (objfile, index);
+
+ index_ptr = index->buffer;
+ index_end = index_ptr + index->size;
+
+ version = read_4_bytes (dbfd, index_ptr);
+ index_ptr += 8; /* Skip the unused word. */
+ nr_units = read_4_bytes (dbfd, index_ptr);
+ index_ptr += 4;
+ nr_slots = read_4_bytes (dbfd, index_ptr);
+ index_ptr += 4;
+
+ if (version != 1)
+ {
+ error (_("Dwarf Error: unsupported DWP file version (%u)"
+ " [in module %s]"),
+ version, dwp_file->name);
+ }
+ if (nr_slots != (nr_slots & -nr_slots))
+ {
+ error (_("Dwarf Error: number of slots in DWP hash table (%u)"
+ " is not power of 2 [in module %s]"),
+ nr_slots, dwp_file->name);
+ }
+
+ htab = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwp_hash_table);
+ htab->nr_units = nr_units;
+ htab->nr_slots = nr_slots;
+ htab->hash_table = index_ptr;
+ htab->unit_table = htab->hash_table + sizeof (uint64_t) * nr_slots;
+ htab->section_pool = htab->unit_table + sizeof (uint32_t) * nr_slots;
+
+ return htab;
+}
+
+/* Update SECTIONS with the data from SECTP.
+
+ This function is like the other "locate" section routines that are
+ passed to bfd_map_over_sections, but in this context the sections to
+ read comes from the DWP hash table, not the full ELF section table.
+
+ The result is non-zero for success, or zero if an error was found. */
+
+static int
+locate_virtual_dwo_sections (asection *sectp,
+ struct virtual_dwo_sections *sections)
+{
+ const struct dwop_section_names *names = &dwop_section_names;
+
+ if (section_is_p (sectp->name, &names->abbrev_dwo))
+ {
+ /* There can be only one. */
+ if (sections->abbrev.asection != NULL)
+ return 0;
+ sections->abbrev.asection = sectp;
+ sections->abbrev.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->info_dwo)
+ || section_is_p (sectp->name, &names->types_dwo))
+ {
+ /* There can be only one. */
+ if (sections->info_or_types.asection != NULL)
+ return 0;
+ sections->info_or_types.asection = sectp;
+ sections->info_or_types.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->line_dwo))
+ {
+ /* There can be only one. */
+ if (sections->line.asection != NULL)
+ return 0;
+ sections->line.asection = sectp;
+ sections->line.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->loc_dwo))
+ {
+ /* There can be only one. */
+ if (sections->loc.asection != NULL)
+ return 0;
+ sections->loc.asection = sectp;
+ sections->loc.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->macinfo_dwo))
+ {
+ /* There can be only one. */
+ if (sections->macinfo.asection != NULL)
+ return 0;
+ sections->macinfo.asection = sectp;
+ sections->macinfo.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->macro_dwo))
+ {
+ /* There can be only one. */
+ if (sections->macro.asection != NULL)
+ return 0;
+ sections->macro.asection = sectp;
+ sections->macro.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->str_offsets_dwo))
+ {
+ /* There can be only one. */
+ if (sections->str_offsets.asection != NULL)
+ return 0;
+ sections->str_offsets.asection = sectp;
+ sections->str_offsets.size = bfd_get_section_size (sectp);
+ }
+ else
+ {
+ /* No other kind of section is valid. */
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Create a dwo_unit object for the DWO with signature SIGNATURE.
+ HTAB is the hash table from the DWP file.
+ SECTION_INDEX is the index of the DWO in HTAB. */
+
+static struct dwo_unit *
+create_dwo_in_dwp (struct dwp_file *dwp_file,
+ const struct dwp_hash_table *htab,
+ uint32_t section_index,
+ ULONGEST signature, int is_debug_types)
+{
+ struct objfile *objfile = dwarf2_per_objfile->objfile;
+ bfd *dbfd = dwp_file->dbfd;
+ const char *kind = is_debug_types ? "TU" : "CU";
+ struct dwo_file *dwo_file;
+ struct dwo_unit *dwo_unit;
+ struct virtual_dwo_sections sections;
+ void **dwo_file_slot;
+ char *virtual_dwo_name;
+ struct dwarf2_section_info *cutu;
+ struct cleanup *cleanups;
+ int i;
+
+ if (dwarf2_read_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "Reading %s %u/0x%s in DWP file: %s\n",
+ kind,
+ section_index, phex (signature, sizeof (signature)),
+ dwp_file->name);
+ }
+
+ /* Fetch the sections of this DWO.
+ Put a limit on the number of sections we look for so that bad data
+ doesn't cause us to loop forever. */
+
+#define MAX_NR_DWO_SECTIONS \
+ (1 /* .debug_info or .debug_types */ \
+ + 1 /* .debug_abbrev */ \
+ + 1 /* .debug_line */ \
+ + 1 /* .debug_loc */ \
+ + 1 /* .debug_str_offsets */ \
+ + 1 /* .debug_macro */ \
+ + 1 /* .debug_macinfo */ \
+ + 1 /* trailing zero */)
+
+ memset (§ions, 0, sizeof (sections));
+ cleanups = make_cleanup (null_cleanup, 0);
+
+ for (i = 0; i < MAX_NR_DWO_SECTIONS; ++i)
+ {
+ asection *sectp;
+ uint32_t section_nr =
+ read_4_bytes (dbfd,
+ htab->section_pool
+ + (section_index + i) * sizeof (uint32_t));
+
+ if (section_nr == 0)
+ break;
+ if (section_nr >= dwp_file->num_sections)
+ {
+ error (_("Dwarf Error: bad DWP hash table, section number too large"
+ " [in module %s]"),
+ dwp_file->name);
+ }
+
+ sectp = dwp_file->elf_sections[section_nr];
+ if (! locate_virtual_dwo_sections (sectp, §ions))
+ {
+ error (_("Dwarf Error: bad DWP hash table, invalid section found"
+ " [in module %s]"),
+ dwp_file->name);
+ }
+ }
+
+ if (i < 2
+ || sections.info_or_types.asection == NULL
+ || sections.abbrev.asection == NULL)
+ {
+ error (_("Dwarf Error: bad DWP hash table, missing DWO sections"
+ " [in module %s]"),
+ dwp_file->name);
+ }
+ if (i == MAX_NR_DWO_SECTIONS)
+ {
+ error (_("Dwarf Error: bad DWP hash table, too many DWO sections"
+ " [in module %s]"),
+ dwp_file->name);
+ }
+
+ /* It's easier for the rest of the code if we fake a struct dwo_file and
+ have dwo_unit "live" in that. At least for now.
+
+ The DWP file can be made up of a random collection of CUs and TUs.
+ However, for each CU + set of TUs that came from the same original
+ DWO file, we want combine them back into a virtual DWO file to save space
+ (fewer struct dwo_file objects to allocated). Remember that for really
+ large apps there can be on the order of 8K CUs and 200K TUs, or more. */
+
+ xasprintf (&virtual_dwo_name, "virtual-dwo/%d-%d-%d-%d",
+ sections.abbrev.asection ? sections.abbrev.asection->id : 0,
+ sections.line.asection ? sections.line.asection->id : 0,
+ sections.loc.asection ? sections.loc.asection->id : 0,
+ (sections.str_offsets.asection
+ ? sections.str_offsets.asection->id
+ : 0));
+ make_cleanup (xfree, virtual_dwo_name);
+ /* Can we use an existing virtual DWO file? */
+ dwo_file_slot = lookup_dwo_file_slot (virtual_dwo_name);
+ /* Create one if necessary. */
+ if (*dwo_file_slot == NULL)
+ {
+ if (dwarf2_read_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "Creating virtual DWO: %s\n",
+ virtual_dwo_name);
+ }
+ dwo_file = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_file);
+ dwo_file->name = obstack_copy0 (&objfile->objfile_obstack,
+ virtual_dwo_name,
+ strlen (virtual_dwo_name));
+ dwo_file->sections.abbrev = sections.abbrev;
+ dwo_file->sections.line = sections.line;
+ dwo_file->sections.loc = sections.loc;
+ dwo_file->sections.macinfo = sections.macinfo;
+ dwo_file->sections.macro = sections.macro;
+ dwo_file->sections.str_offsets = sections.str_offsets;
+ /* The "str" section is global to the entire DWP file. */
+ dwo_file->sections.str = dwp_file->sections.str;
+ /* The info or types section is assigned later to dwo_unit,
+ there's no need to record it in dwo_file.
+ Also, we can't simply record type sections in dwo_file because
+ we record a pointer into the vector in dwo_unit. As we collect more
+ types we'll grow the vector and eventually have to reallocate space
+ for it, invalidating all the pointers into the current copy. */
+ *dwo_file_slot = dwo_file;
+ }
+ else
+ {
+ if (dwarf2_read_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "Using existing virtual DWO: %s\n",
+ virtual_dwo_name);
+ }
+ dwo_file = *dwo_file_slot;
+ }
+ do_cleanups (cleanups);
+
+ dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
+ dwo_unit->dwo_file = dwo_file;
+ dwo_unit->signature = signature;
+ dwo_unit->info_or_types_section =
+ obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct dwarf2_section_info));
+ *dwo_unit->info_or_types_section = sections.info_or_types;
+ /* offset, length, type_offset_in_tu are set later. */
+
+ return dwo_unit;
+}
+
+/* Lookup the DWO with SIGNATURE in DWP_FILE. */
+
+static struct dwo_unit *
+lookup_dwo_in_dwp (struct dwp_file *dwp_file,
+ const struct dwp_hash_table *htab,
+ ULONGEST signature, int is_debug_types)
+{
+ bfd *dbfd = dwp_file->dbfd;
+ uint32_t mask = htab->nr_slots - 1;
+ uint32_t hash = signature & mask;
+ uint32_t hash2 = ((signature >> 32) & mask) | 1;
+ unsigned int i;
+ void **slot;
+ struct dwo_unit find_dwo_cu, *dwo_cu;
+
+ memset (&find_dwo_cu, 0, sizeof (find_dwo_cu));
+ find_dwo_cu.signature = signature;
+ slot = htab_find_slot (dwp_file->loaded_cutus, &find_dwo_cu, INSERT);
+
+ if (*slot != NULL)
+ return *slot;
+
+ /* Use a for loop so that we don't loop forever on bad debug info. */
+ for (i = 0; i < htab->nr_slots; ++i)
+ {
+ ULONGEST signature_in_table;
+
+ signature_in_table =
+ read_8_bytes (dbfd, htab->hash_table + hash * sizeof (uint64_t));
+ if (signature_in_table == signature)
+ {
+ uint32_t section_index =
+ read_4_bytes (dbfd, htab->unit_table + hash * sizeof (uint32_t));
+
+ *slot = create_dwo_in_dwp (dwp_file, htab, section_index,
+ signature, is_debug_types);
+ return *slot;
+ }
+ if (signature_in_table == 0)
+ return NULL;
+ hash = (hash + hash2) & mask;
+ }
+
+ error (_("Dwarf Error: bad DWP hash table, lookup didn't terminate"
+ " [in module %s]"),
+ dwp_file->name);
+}
+
+/* Subroutine of open_dwop_file to simplify it.
Open the file specified by FILE_NAME and hand it off to BFD for
preliminary analysis. Return a newly initialized bfd *, which
includes a canonicalized copy of FILE_NAME.
+ If IS_DWP is TRUE, we're opening a DWP file, otherwise a DWO file.
In case of trouble, return NULL.
NOTE: This function is derived from symfile_bfd_open. */
static bfd *
-try_open_dwo_file (const char *file_name)
+try_open_dwop_file (const char *file_name, int is_dwp)
{
bfd *sym_bfd;
- int desc;
+ int desc, flags;
char *absolute_name;
- desc = openp (debug_file_directory, OPF_TRY_CWD_FIRST, file_name,
+ flags = OPF_TRY_CWD_FIRST;
+ if (is_dwp)
+ flags |= OPF_SEARCH_IN_PATH;
+ desc = openp (debug_file_directory, flags, file_name,
O_RDONLY | O_BINARY, &absolute_name);
if (desc < 0)
return NULL;
- sym_bfd = gdb_bfd_ref (bfd_fopen (absolute_name, gnutarget, FOPEN_RB, desc));
+ sym_bfd = gdb_bfd_open (absolute_name, gnutarget, desc);
if (!sym_bfd)
{
xfree (absolute_name);
return NULL;
}
+ xfree (absolute_name);
bfd_set_cacheable (sym_bfd, 1);
if (!bfd_check_format (sym_bfd, bfd_object))
{
- xfree (absolute_name);
gdb_bfd_unref (sym_bfd); /* This also closes desc. */
return NULL;
}
return sym_bfd;
}
-/* Try to open DWO file DWO_NAME.
+/* Try to open DWO/DWP file FILE_NAME.
COMP_DIR is the DW_AT_comp_dir attribute.
+ If IS_DWP is TRUE, we're opening a DWP file, otherwise a DWO file.
The result is the bfd handle of the file.
If there is a problem finding or opening the file, return NULL.
Upon success, the canonicalized path of the file is stored in the bfd,
same as symfile_bfd_open. */
static bfd *
-open_dwo_file (const char *dwo_name, const char *comp_dir)
+open_dwop_file (const char *file_name, const char *comp_dir, int is_dwp)
{
bfd *abfd;
- if (IS_ABSOLUTE_PATH (dwo_name))
- return try_open_dwo_file (dwo_name);
+ if (IS_ABSOLUTE_PATH (file_name))
+ return try_open_dwop_file (file_name, is_dwp);
/* Before trying the search path, try DWO_NAME in COMP_DIR. */
if (comp_dir != NULL)
{
- char *path_to_try = concat (comp_dir, SLASH_STRING, dwo_name, NULL);
+ char *path_to_try = concat (comp_dir, SLASH_STRING, file_name, NULL);
/* NOTE: If comp_dir is a relative path, this will also try the
search path, which seems useful. */
- abfd = try_open_dwo_file (path_to_try);
+ abfd = try_open_dwop_file (path_to_try, is_dwp);
xfree (path_to_try);
if (abfd != NULL)
return abfd;
if (*debug_file_directory == '\0')
return NULL;
- return try_open_dwo_file (dwo_name);
+ return try_open_dwop_file (file_name, is_dwp);
+}
+
+/* This function is mapped across the sections and remembers the offset and
+ size of each of the DWO debugging sections we are interested in. */
+
+static void
+dwarf2_locate_dwo_sections (bfd *abfd, asection *sectp, void *dwo_sections_ptr)
+{
+ struct dwo_sections *dwo_sections = dwo_sections_ptr;
+ const struct dwop_section_names *names = &dwop_section_names;
+
+ if (section_is_p (sectp->name, &names->abbrev_dwo))
+ {
+ dwo_sections->abbrev.asection = sectp;
+ dwo_sections->abbrev.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->info_dwo))
+ {
+ dwo_sections->info.asection = sectp;
+ dwo_sections->info.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->line_dwo))
+ {
+ dwo_sections->line.asection = sectp;
+ dwo_sections->line.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->loc_dwo))
+ {
+ dwo_sections->loc.asection = sectp;
+ dwo_sections->loc.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->macinfo_dwo))
+ {
+ dwo_sections->macinfo.asection = sectp;
+ dwo_sections->macinfo.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->macro_dwo))
+ {
+ dwo_sections->macro.asection = sectp;
+ dwo_sections->macro.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->str_dwo))
+ {
+ dwo_sections->str.asection = sectp;
+ dwo_sections->str.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->str_offsets_dwo))
+ {
+ dwo_sections->str_offsets.asection = sectp;
+ dwo_sections->str_offsets.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->types_dwo))
+ {
+ struct dwarf2_section_info type_section;
+
+ memset (&type_section, 0, sizeof (type_section));
+ type_section.asection = sectp;
+ type_section.size = bfd_get_section_size (sectp);
+ VEC_safe_push (dwarf2_section_info_def, dwo_sections->types,
+ &type_section);
+ }
+}
+
+/* Initialize the use of the DWO file specified by DWO_NAME.
+ The result is NULL if DWO_NAME can't be found. */
+
+static struct dwo_file *
+open_and_init_dwo_file (const char *dwo_name, const char *comp_dir)
+{
+ struct objfile *objfile = dwarf2_per_objfile->objfile;
+ struct dwo_file *dwo_file;
+ bfd *dbfd;
+ struct cleanup *cleanups;
+
+ dbfd = open_dwop_file (dwo_name, comp_dir, 0);
+ if (dbfd == NULL)
+ {
+ if (dwarf2_read_debug)
+ fprintf_unfiltered (gdb_stdlog, "DWO file not found: %s\n", dwo_name);
+ return NULL;
+ }
+ dwo_file = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_file);
+ dwo_file->name = obstack_copy0 (&objfile->objfile_obstack,
+ dwo_name, strlen (dwo_name));
+ dwo_file->dbfd = dbfd;
+
+ cleanups = make_cleanup (free_dwo_file_cleanup, dwo_file);
+
+ bfd_map_over_sections (dbfd, dwarf2_locate_dwo_sections, &dwo_file->sections);
+
+ dwo_file->cus = create_dwo_debug_info_hash_table (dwo_file);
+
+ dwo_file->tus = create_debug_types_hash_table (dwo_file,
+ dwo_file->sections.types);
+
+ discard_cleanups (cleanups);
+
+ if (dwarf2_read_debug)
+ fprintf_unfiltered (gdb_stdlog, "DWO file found: %s\n", dwo_name);
+
+ return dwo_file;
+}
+
+/* This function is mapped across the sections and remembers the offset and
+ size of each of the DWP debugging sections we are interested in. */
+
+static void
+dwarf2_locate_dwp_sections (bfd *abfd, asection *sectp, void *dwp_file_ptr)
+{
+ struct dwp_file *dwp_file = dwp_file_ptr;
+ const struct dwop_section_names *names = &dwop_section_names;
+ unsigned int elf_section_nr = elf_section_data (sectp)->this_idx;
+
+ /* Record the ELF section number for later lookup: this is what the
+ .debug_cu_index,.debug_tu_index tables use. */
+ gdb_assert (elf_section_nr < dwp_file->num_sections);
+ dwp_file->elf_sections[elf_section_nr] = sectp;
+
+ /* Look for specific sections that we need. */
+ if (section_is_p (sectp->name, &names->str_dwo))
+ {
+ dwp_file->sections.str.asection = sectp;
+ dwp_file->sections.str.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->cu_index))
+ {
+ dwp_file->sections.cu_index.asection = sectp;
+ dwp_file->sections.cu_index.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names->tu_index))
+ {
+ dwp_file->sections.tu_index.asection = sectp;
+ dwp_file->sections.tu_index.size = bfd_get_section_size (sectp);
+ }
+}
+
+/* Hash function for dwp_file loaded CUs/TUs. */
+
+static hashval_t
+hash_dwp_loaded_cutus (const void *item)
+{
+ const struct dwo_unit *dwo_unit = item;
+
+ /* This drops the top 32 bits of the signature, but is ok for a hash. */
+ return dwo_unit->signature;
+}
+
+/* Equality function for dwp_file loaded CUs/TUs. */
+
+static int
+eq_dwp_loaded_cutus (const void *a, const void *b)
+{
+ const struct dwo_unit *dua = a;
+ const struct dwo_unit *dub = b;
+
+ return dua->signature == dub->signature;
+}
+
+/* Allocate a hash table for dwp_file loaded CUs/TUs. */
+
+static htab_t
+allocate_dwp_loaded_cutus_table (struct objfile *objfile)
+{
+ return htab_create_alloc_ex (3,
+ hash_dwp_loaded_cutus,
+ eq_dwp_loaded_cutus,
+ NULL,
+ &objfile->objfile_obstack,
+ hashtab_obstack_allocate,
+ dummy_obstack_deallocate);
}
-/* Initialize the use of the DWO file specified by DWO_NAME. */
+/* Initialize the use of the DWP file for the current objfile.
+ By convention the name of the DWP file is ${objfile}.dwp.
+ The result is NULL if it can't be found. */
-static struct dwo_file *
-init_dwo_file (const char *dwo_name, const char *comp_dir)
+static struct dwp_file *
+open_and_init_dwp_file (const char *comp_dir)
{
struct objfile *objfile = dwarf2_per_objfile->objfile;
- struct dwo_file *dwo_file = OBSTACK_ZALLOC (&objfile->objfile_obstack,
- struct dwo_file);
- bfd *abfd;
+ struct dwp_file *dwp_file;
+ char *dwp_name;
+ bfd *dbfd;
struct cleanup *cleanups;
- if (dwarf2_read_debug)
- fprintf_unfiltered (gdb_stdlog, "Reading DWO file %s:\n", dwo_name);
-
- abfd = open_dwo_file (dwo_name, comp_dir);
- if (abfd == NULL)
- return NULL;
- dwo_file->dwo_name = dwo_name;
- dwo_file->dwo_bfd = abfd;
-
- cleanups = make_cleanup (free_dwo_file_cleanup, dwo_file);
-
- bfd_map_over_sections (abfd, dwarf2_locate_dwo_sections, dwo_file);
-
- dwo_file->cus = create_debug_info_hash_table (dwo_file);
+ xasprintf (&dwp_name, "%s.dwp", dwarf2_per_objfile->objfile->name);
+ cleanups = make_cleanup (xfree, dwp_name);
- dwo_file->tus = create_debug_types_hash_table (dwo_file,
- dwo_file->sections.types);
+ dbfd = open_dwop_file (dwp_name, comp_dir, 1);
+ if (dbfd == NULL)
+ {
+ if (dwarf2_read_debug)
+ fprintf_unfiltered (gdb_stdlog, "DWP file not found: %s\n", dwp_name);
+ do_cleanups (cleanups);
+ return NULL;
+ }
+ dwp_file = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwp_file);
+ dwp_file->name = obstack_copy0 (&objfile->objfile_obstack,
+ dwp_name, strlen (dwp_name));
+ dwp_file->dbfd = dbfd;
+ do_cleanups (cleanups);
- discard_cleanups (cleanups);
+ cleanups = make_cleanup (free_dwo_file_cleanup, dwp_file);
- return dwo_file;
-}
+ /* +1: section 0 is unused */
+ dwp_file->num_sections = bfd_count_sections (dbfd) + 1;
+ dwp_file->elf_sections =
+ OBSTACK_CALLOC (&objfile->objfile_obstack,
+ dwp_file->num_sections, asection *);
-/* Lookup DWO file DWO_NAME. */
+ bfd_map_over_sections (dbfd, dwarf2_locate_dwp_sections, dwp_file);
-static struct dwo_file *
-lookup_dwo_file (char *dwo_name, const char *comp_dir)
-{
- struct dwo_file *dwo_file;
- struct dwo_file find_entry;
- void **slot;
+ dwp_file->cus = create_dwp_hash_table (dwp_file, 0);
- if (dwarf2_per_objfile->dwo_files == NULL)
- dwarf2_per_objfile->dwo_files = allocate_dwo_file_hash_table ();
+ dwp_file->tus = create_dwp_hash_table (dwp_file, 1);
- /* Have we already seen this DWO file? */
- find_entry.dwo_name = dwo_name;
- slot = htab_find_slot (dwarf2_per_objfile->dwo_files, &find_entry, INSERT);
+ dwp_file->loaded_cutus = allocate_dwp_loaded_cutus_table (objfile);
- /* If not, read it in and build a table of the DWOs it contains. */
- if (*slot == NULL)
- *slot = init_dwo_file (dwo_name, comp_dir);
+ discard_cleanups (cleanups);
- /* NOTE: This will be NULL if unable to open the file. */
- dwo_file = *slot;
+ if (dwarf2_read_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "DWP file found: %s\n", dwp_file->name);
+ fprintf_unfiltered (gdb_stdlog,
+ " %u CUs, %u TUs\n",
+ dwp_file->cus ? dwp_file->cus->nr_units : 0,
+ dwp_file->tus ? dwp_file->tus->nr_units : 0);
+ }
- return dwo_file;
+ return dwp_file;
}
-/* Lookup the DWO CU referenced from THIS_CU in DWO file DWO_NAME.
+/* Subroutine of lookup_dwo_comp_unit, lookup_dwo_type_unit.
+ Look up the CU/TU with signature SIGNATURE, either in DWO file DWO_NAME
+ or in the DWP file for the objfile, referenced by THIS_UNIT.
If non-NULL, comp_dir is the DW_AT_comp_dir attribute.
- SIGNATURE is the "dwo_id" of the CU (for consistency we use the same
- nomenclature as TUs).
+ IS_DEBUG_TYPES is non-zero if reading a TU, otherwise read a CU.
+
+ This is called, for example, when wanting to read a variable with a
+ complex location. Therefore we don't want to do file i/o for every call.
+ Therefore we don't want to look for a DWO file on every call.
+ Therefore we first see if we've already seen SIGNATURE in a DWP file,
+ then we check if we've already seen DWO_NAME, and only THEN do we check
+ for a DWO file.
+
The result is a pointer to the dwo_unit object or NULL if we didn't find it
- (dwo_id mismatch or couldn't find the DWO file). */
+ (dwo_id mismatch or couldn't find the DWO/DWP file). */
static struct dwo_unit *
-lookup_dwo_comp_unit (struct dwarf2_per_cu_data *this_cu,
- char *dwo_name, const char *comp_dir,
- ULONGEST signature)
+lookup_dwo_cutu (struct dwarf2_per_cu_data *this_unit,
+ const char *dwo_name, const char *comp_dir,
+ ULONGEST signature, int is_debug_types)
{
struct objfile *objfile = dwarf2_per_objfile->objfile;
+ const char *kind = is_debug_types ? "TU" : "CU";
+ void **dwo_file_slot;
struct dwo_file *dwo_file;
+ struct dwp_file *dwp_file;
- dwo_file = lookup_dwo_file (dwo_name, comp_dir);
- if (dwo_file == NULL)
- return NULL;
+ /* Have we already read SIGNATURE from a DWP file? */
- /* Look up the DWO using its signature(dwo_id). */
+ if (! dwarf2_per_objfile->dwp_checked)
+ {
+ dwarf2_per_objfile->dwp_file = open_and_init_dwp_file (comp_dir);
+ dwarf2_per_objfile->dwp_checked = 1;
+ }
+ dwp_file = dwarf2_per_objfile->dwp_file;
- if (dwo_file->cus != NULL)
+ if (dwp_file != NULL)
{
- struct dwo_unit find_dwo_cu, *dwo_cu;
+ const struct dwp_hash_table *dwp_htab =
+ is_debug_types ? dwp_file->tus : dwp_file->cus;
- find_dwo_cu.signature = signature;
- dwo_cu = htab_find (dwo_file->cus, &find_dwo_cu);
+ if (dwp_htab != NULL)
+ {
+ struct dwo_unit *dwo_cutu =
+ lookup_dwo_in_dwp (dwp_file, dwp_htab, signature, is_debug_types);
- if (dwo_cu != NULL)
- return dwo_cu;
+ if (dwo_cutu != NULL)
+ {
+ if (dwarf2_read_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "Virtual DWO %s %s found: @%s\n",
+ kind, hex_string (signature),
+ host_address_to_string (dwo_cutu));
+ }
+ return dwo_cutu;
+ }
+ }
}
- /* We didn't find it. This must mean a dwo_id mismatch. */
-
- complaint (&symfile_complaints,
- _("Could not find DWO CU referenced by CU at offset 0x%x"
- " [in module %s]"),
- this_cu->offset.sect_off, objfile->name);
- return NULL;
-}
+ /* Have we already seen DWO_NAME? */
-/* Lookup the DWO TU referenced from THIS_TU in DWO file DWO_NAME.
- If non-NULL, comp_dir is the DW_AT_comp_dir attribute.
- The result is a pointer to the dwo_unit object or NULL if we didn't find it
- (dwo_id mismatch or couldn't find the DWO file). */
+ dwo_file_slot = lookup_dwo_file_slot (dwo_name);
+ if (*dwo_file_slot == NULL)
+ {
+ /* Read in the file and build a table of the DWOs it contains. */
+ *dwo_file_slot = open_and_init_dwo_file (dwo_name, comp_dir);
+ }
+ /* NOTE: This will be NULL if unable to open the file. */
+ dwo_file = *dwo_file_slot;
-static struct dwo_unit *
-lookup_dwo_type_unit (struct signatured_type *this_tu,
- char *dwo_name, const char *comp_dir)
-{
- struct objfile *objfile = dwarf2_per_objfile->objfile;
- struct dwo_file *dwo_file;
+ if (dwo_file != NULL)
+ {
+ htab_t htab = is_debug_types ? dwo_file->tus : dwo_file->cus;
- dwo_file = lookup_dwo_file (dwo_name, comp_dir);
- if (dwo_file == NULL)
- return NULL;
+ if (htab != NULL)
+ {
+ struct dwo_unit find_dwo_cutu, *dwo_cutu;
- /* Look up the DWO using its signature(dwo_id). */
+ memset (&find_dwo_cutu, 0, sizeof (find_dwo_cutu));
+ find_dwo_cutu.signature = signature;
+ dwo_cutu = htab_find (htab, &find_dwo_cutu);
- if (dwo_file->tus != NULL)
- {
- struct dwo_unit find_dwo_tu, *dwo_tu;
+ if (dwo_cutu != NULL)
+ {
+ if (dwarf2_read_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "DWO %s %s(%s) found: @%s\n",
+ kind, dwo_name, hex_string (signature),
+ host_address_to_string (dwo_cutu));
+ }
+ return dwo_cutu;
+ }
+ }
+ }
- find_dwo_tu.signature = this_tu->signature;
- dwo_tu = htab_find (dwo_file->tus, &find_dwo_tu);
+ /* We didn't find it. This could mean a dwo_id mismatch, or
+ someone deleted the DWO/DWP file, or the search path isn't set up
+ correctly to find the file. */
- if (dwo_tu != NULL)
- return dwo_tu;
+ if (dwarf2_read_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "DWO %s %s(%s) not found\n",
+ kind, dwo_name, hex_string (signature));
}
- /* We didn't find it. This must mean a dwo_id mismatch. */
-
complaint (&symfile_complaints,
- _("Could not find DWO TU referenced by TU at offset 0x%x"
+ _("Could not find DWO CU referenced by CU at offset 0x%x"
" [in module %s]"),
- this_tu->per_cu.offset.sect_off, objfile->name);
+ this_unit->offset.sect_off, objfile->name);
return NULL;
}
+/* Lookup the DWO CU DWO_NAME/SIGNATURE referenced from THIS_CU.
+ See lookup_dwo_cutu_unit for details. */
+
+static struct dwo_unit *
+lookup_dwo_comp_unit (struct dwarf2_per_cu_data *this_cu,
+ const char *dwo_name, const char *comp_dir,
+ ULONGEST signature)
+{
+ return lookup_dwo_cutu (this_cu, dwo_name, comp_dir, signature, 0);
+}
+
+/* Lookup the DWO TU DWO_NAME/SIGNATURE referenced from THIS_TU.
+ See lookup_dwo_cutu_unit for details. */
+
+static struct dwo_unit *
+lookup_dwo_type_unit (struct signatured_type *this_tu,
+ const char *dwo_name, const char *comp_dir)
+{
+ return lookup_dwo_cutu (&this_tu->per_cu, dwo_name, comp_dir, this_tu->signature, 1);
+}
+
/* Free all resources associated with DWO_FILE.
Close the DWO file and munmap the sections.
All memory should be on the objfile obstack. */
int ix;
struct dwarf2_section_info *section;
- gdb_assert (dwo_file->dwo_bfd != objfile->obfd);
- gdb_bfd_unref (dwo_file->dwo_bfd);
-
- munmap_section_buffer (&dwo_file->sections.abbrev);
- munmap_section_buffer (&dwo_file->sections.info);
- munmap_section_buffer (&dwo_file->sections.line);
- munmap_section_buffer (&dwo_file->sections.loc);
- munmap_section_buffer (&dwo_file->sections.str);
- munmap_section_buffer (&dwo_file->sections.str_offsets);
-
- for (ix = 0;
- VEC_iterate (dwarf2_section_info_def, dwo_file->sections.types,
- ix, section);
- ++ix)
- munmap_section_buffer (section);
+ gdb_assert (dwo_file->dbfd != objfile->obfd);
+ gdb_bfd_unref (dwo_file->dbfd);
VEC_free (dwarf2_section_info_def, dwo_file->sections.types);
}
when we finish processing a function scope, we may need to go
back to building a containing block's symbol lists. */
local_symbols = new->locals;
- param_symbols = new->params;
using_directives = new->using_directives;
/* If we've finished processing a top-level function, subsequent
range_beginning += base;
range_end += base;
+ /* A not-uncommon case of bad debug info.
+ Don't pollute the addrmap with bad data. */
+ if (range_beginning + baseaddr == 0
+ && !dwarf2_per_objfile->has_section_at_zero)
+ {
+ complaint (&symfile_complaints,
+ _(".debug_ranges entry has start address of zero"
+ " [in module %s]"), objfile->name);
+ continue;
+ }
+
if (ranges_pst != NULL)
addrmap_set_empty (objfile->psymtabs_addrmap,
range_beginning + baseaddr,
if (start == end)
continue;
- record_block_range (block,
- baseaddr + base + start,
- baseaddr + base + end - 1);
+ start += base + baseaddr;
+ end += base + baseaddr;
+
+ /* A not-uncommon case of bad debug info.
+ Don't pollute the addrmap with bad data. */
+ if (start == 0 && !dwarf2_per_objfile->has_section_at_zero)
+ {
+ complaint (&symfile_complaints,
+ _(".debug_ranges entry has start address of zero"
+ " [in module %s]"), objfile->name);
+ continue;
+ }
+
+ record_block_range (block, start, end - 1);
}
}
}
return set_die_type (die, set_type, cu);
}
-/* First cut: install each common block member as a global variable. */
+/* A helper for read_common_block that creates a locexpr baton.
+ SYM is the symbol which we are marking as computed.
+ COMMON_DIE is the DIE for the common block.
+ COMMON_LOC is the location expression attribute for the common
+ block itself.
+ MEMBER_LOC is the location expression attribute for the particular
+ member of the common block that we are processing.
+ CU is the CU from which the above come. */
+
+static void
+mark_common_block_symbol_computed (struct symbol *sym,
+ struct die_info *common_die,
+ struct attribute *common_loc,
+ struct attribute *member_loc,
+ struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = dwarf2_per_objfile->objfile;
+ struct dwarf2_locexpr_baton *baton;
+ gdb_byte *ptr;
+ unsigned int cu_off;
+ enum bfd_endian byte_order = gdbarch_byte_order (get_objfile_arch (objfile));
+ LONGEST offset = 0;
+
+ gdb_assert (common_loc && member_loc);
+ gdb_assert (attr_form_is_block (common_loc));
+ gdb_assert (attr_form_is_block (member_loc)
+ || attr_form_is_constant (member_loc));
+
+ baton = obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct dwarf2_locexpr_baton));
+ baton->per_cu = cu->per_cu;
+ gdb_assert (baton->per_cu);
+
+ baton->size = 5 /* DW_OP_call4 */ + 1 /* DW_OP_plus */;
+
+ if (attr_form_is_constant (member_loc))
+ {
+ offset = dwarf2_get_attr_constant_value (member_loc, 0);
+ baton->size += 1 /* DW_OP_addr */ + cu->header.addr_size;
+ }
+ else
+ baton->size += DW_BLOCK (member_loc)->size;
+
+ ptr = obstack_alloc (&objfile->objfile_obstack, baton->size);
+ baton->data = ptr;
+
+ *ptr++ = DW_OP_call4;
+ cu_off = common_die->offset.sect_off - cu->per_cu->offset.sect_off;
+ store_unsigned_integer (ptr, 4, byte_order, cu_off);
+ ptr += 4;
+
+ if (attr_form_is_constant (member_loc))
+ {
+ *ptr++ = DW_OP_addr;
+ store_unsigned_integer (ptr, cu->header.addr_size, byte_order, offset);
+ ptr += cu->header.addr_size;
+ }
+ else
+ {
+ /* We have to copy the data here, because DW_OP_call4 will only
+ use a DW_AT_location attribute. */
+ memcpy (ptr, DW_BLOCK (member_loc)->data, DW_BLOCK (member_loc)->size);
+ ptr += DW_BLOCK (member_loc)->size;
+ }
+
+ *ptr++ = DW_OP_plus;
+ gdb_assert (ptr - baton->data == baton->size);
+
+ SYMBOL_COMPUTED_OPS (sym) = &dwarf2_locexpr_funcs;
+ SYMBOL_LOCATION_BATON (sym) = baton;
+ SYMBOL_CLASS (sym) = LOC_COMPUTED;
+}
+
+/* Create appropriate locally-scoped variables for all the
+ DW_TAG_common_block entries. Also create a struct common_block
+ listing all such variables for `info common'. COMMON_BLOCK_DOMAIN
+ is used to sepate the common blocks name namespace from regular
+ variable names. */
static void
read_common_block (struct die_info *die, struct dwarf2_cu *cu)
{
- struct die_info *child_die;
struct attribute *attr;
- struct symbol *sym;
- CORE_ADDR base = (CORE_ADDR) 0;
attr = dwarf2_attr (die, DW_AT_location, cu);
if (attr)
/* Support the .debug_loc offsets. */
if (attr_form_is_block (attr))
{
- base = decode_locdesc (DW_BLOCK (attr), cu);
+ /* Ok. */
}
else if (attr_form_is_section_offset (attr))
{
dwarf2_complex_location_expr_complaint ();
+ attr = NULL;
}
else
{
dwarf2_invalid_attrib_class_complaint ("DW_AT_location",
"common block member");
+ attr = NULL;
}
}
+
if (die->child != NULL)
{
- child_die = die->child;
- while (child_die && child_die->tag)
- {
- LONGEST offset;
+ struct objfile *objfile = cu->objfile;
+ struct die_info *child_die;
+ size_t n_entries = 0, size;
+ struct common_block *common_block;
+ struct symbol *sym;
+
+ for (child_die = die->child;
+ child_die && child_die->tag;
+ child_die = sibling_die (child_die))
+ ++n_entries;
+ size = (sizeof (struct common_block)
+ + (n_entries - 1) * sizeof (struct symbol *));
+ common_block = obstack_alloc (&objfile->objfile_obstack, size);
+ memset (common_block->contents, 0, n_entries * sizeof (struct symbol *));
+ common_block->n_entries = 0;
+
+ for (child_die = die->child;
+ child_die && child_die->tag;
+ child_die = sibling_die (child_die))
+ {
+ /* Create the symbol in the DW_TAG_common_block block in the current
+ symbol scope. */
sym = new_symbol (child_die, NULL, cu);
- if (sym != NULL
- && handle_data_member_location (child_die, cu, &offset))
+ if (sym != NULL)
{
- SYMBOL_VALUE_ADDRESS (sym) = base + offset;
- add_symbol_to_list (sym, &global_symbols);
+ struct attribute *member_loc;
+
+ common_block->contents[common_block->n_entries++] = sym;
+
+ member_loc = dwarf2_attr (child_die, DW_AT_data_member_location,
+ cu);
+ if (member_loc)
+ {
+ /* GDB has handled this for a long time, but it is
+ not specified by DWARF. It seems to have been
+ emitted by gfortran at least as recently as:
+ http://gcc.gnu.org/bugzilla/show_bug.cgi?id=23057. */
+ complaint (&symfile_complaints,
+ _("Variable in common block has "
+ "DW_AT_data_member_location "
+ "- DIE at 0x%x [in module %s]"),
+ child_die->offset.sect_off, cu->objfile->name);
+
+ if (attr_form_is_section_offset (member_loc))
+ dwarf2_complex_location_expr_complaint ();
+ else if (attr_form_is_constant (member_loc)
+ || attr_form_is_block (member_loc))
+ {
+ if (attr)
+ mark_common_block_symbol_computed (sym, die, attr,
+ member_loc, cu);
+ }
+ else
+ dwarf2_complex_location_expr_complaint ();
+ }
}
- child_die = sibling_die (child_die);
}
+
+ sym = new_symbol (die, objfile_type (objfile)->builtin_void, cu);
+ SYMBOL_VALUE_COMMON_BLOCK (sym) = common_block;
}
}
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
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:
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)
(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);
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;
{
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);
&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;
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:
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,
/* Read dwarf information from a buffer. */
static unsigned int
-read_1_byte (bfd *abfd, gdb_byte *buf)
+read_1_byte (bfd *abfd, const gdb_byte *buf)
{
return bfd_get_8 (abfd, buf);
}
static int
-read_1_signed_byte (bfd *abfd, gdb_byte *buf)
+read_1_signed_byte (bfd *abfd, const gdb_byte *buf)
{
return bfd_get_signed_8 (abfd, buf);
}
static unsigned int
-read_2_bytes (bfd *abfd, gdb_byte *buf)
+read_2_bytes (bfd *abfd, const gdb_byte *buf)
{
return bfd_get_16 (abfd, buf);
}
static int
-read_2_signed_bytes (bfd *abfd, gdb_byte *buf)
+read_2_signed_bytes (bfd *abfd, const gdb_byte *buf)
{
return bfd_get_signed_16 (abfd, buf);
}
static unsigned int
-read_4_bytes (bfd *abfd, gdb_byte *buf)
+read_4_bytes (bfd *abfd, const gdb_byte *buf)
{
return bfd_get_32 (abfd, buf);
}
static int
-read_4_signed_bytes (bfd *abfd, gdb_byte *buf)
+read_4_signed_bytes (bfd *abfd, const gdb_byte *buf)
{
return bfd_get_signed_32 (abfd, buf);
}
static ULONGEST
-read_8_bytes (bfd *abfd, gdb_byte *buf)
+read_8_bytes (bfd *abfd, const gdb_byte *buf)
{
return bfd_get_64 (abfd, buf);
}
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,
We don't need to read the entire CU(/TU).
We just need the header and top level die.
+
IWBN to use the aging mechanism to let us lazily later discard the CU.
- See however init_cutu_and_read_dies_simple. */
+ For now we skip this optimization. */
if (cu != NULL)
{
{
struct dwarf2_read_addr_index_data aidata;
- init_cutu_and_read_dies_simple (per_cu, dwarf2_read_addr_index_reader,
- &aidata);
+ /* Note: We can't use init_cutu_and_read_dies_simple here,
+ we need addr_base. */
+ init_cutu_and_read_dies (per_cu, NULL, 0, 0,
+ dwarf2_read_addr_index_reader, &aidata);
addr_base = aidata.addr_base;
addr_size = aidata.addr_size;
}
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.
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)
{
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 "
{
var_decode_location (attr, sym, cu);
attr2 = dwarf2_attr (die, DW_AT_external, cu);
+
+ /* Fortran explicitly imports any global symbols to the local
+ scope by DW_TAG_common_block. */
+ if (cu->language == language_fortran && die->parent
+ && die->parent->tag == DW_TAG_common_block)
+ attr2 = NULL;
+
if (SYMBOL_CLASS (sym) == LOC_STATIC
&& SYMBOL_VALUE_ADDRESS (sym) == 0
&& !dwarf2_per_objfile->has_section_at_zero)
the minimal symbol table whenever the variable is
referenced. */
attr2 = dwarf2_attr (die, DW_AT_external, cu);
- if (attr2 && (DW_UNSND (attr2) != 0)
- && dwarf2_attr (die, DW_AT_type, cu) != NULL)
+
+ /* Fortran explicitly imports any global symbols to the local
+ scope by DW_TAG_common_block. */
+ if (cu->language == language_fortran && die->parent
+ && die->parent->tag == DW_TAG_common_block)
+ {
+ /* SYMBOL_CLASS doesn't matter here because
+ read_common_block is going to reset it. */
+ if (!suppress_add)
+ list_to_add = cu->list_in_scope;
+ }
+ else if (attr2 && (DW_UNSND (attr2) != 0)
+ && dwarf2_attr (die, DW_AT_type, cu) != NULL)
{
/* A variable with DW_AT_external is never static, but it
may be block-scoped. */
SYMBOL_CLASS (sym) = LOC_TYPEDEF;
list_to_add = &global_symbols;
break;
+ case DW_TAG_common_block:
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_DOMAIN (sym) = COMMON_BLOCK_DOMAIN;
+ add_symbol_to_list (sym, cu->list_in_scope);
+ break;
default:
/* Not a tag we recognize. Hopefully we aren't processing
trash data, but since we must specifically ignore things
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);
/* 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);
case DW_FORM_block4:
case DW_FORM_block:
case DW_FORM_block1:
- fprintf_unfiltered (f, "block: size %d",
- DW_BLOCK (&die->attrs[i])->size);
+ fprintf_unfiltered (f, "block: size %s",
+ pulongest (DW_BLOCK (&die->attrs[i])->size));
break;
case DW_FORM_exprloc:
- fprintf_unfiltered (f, "expression: size %u",
- DW_BLOCK (&die->attrs[i])->size);
+ fprintf_unfiltered (f, "expression: size %s",
+ pulongest (DW_BLOCK (&die->attrs[i])->size));
break;
case DW_FORM_ref_addr:
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:
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]) : "",
case DW_FORM_ref4:
case DW_FORM_ref8:
case DW_FORM_ref_udata:
+ case DW_FORM_GNU_ref_alt:
return 1;
default:
return 0;
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;
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))
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]"),
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);
decode_locdesc (struct dwarf_block *blk, struct dwarf2_cu *cu)
{
struct objfile *objfile = cu->objfile;
- int i;
- int size = blk->size;
+ size_t i;
+ size_t size = blk->size;
gdb_byte *data = blk->data;
CORE_ADDR stack[64];
int stacki;
/* We don't create a macro table for this compilation unit
at all until we actually get a filename. */
if (! pending_macros)
- pending_macros = new_macro_table (&objfile->objfile_obstack,
- objfile->macro_cache);
+ pending_macros = new_macro_table (&objfile->per_bfd->storage_obstack,
+ objfile->per_bfd->macro_cache);
if (! current_file)
{
case DW_FORM_sec_offset:
case DW_FORM_strp:
+ case DW_FORM_GNU_strp_alt:
bytes += offset_size;
break;
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)
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;
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
+ || section_is_dwz)
+ {
+ 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. */
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);
}
}
break;
case DW_MACRO_GNU_transparent_include:
+ case DW_MACRO_GNU_transparent_include_alt:
{
LONGEST offset;
void **slot;
+ 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;
+ gdb_byte *new_mac_ptr;
offset = read_offset_1 (abfd, mac_ptr, offset_size);
mac_ptr += offset_size;
- slot = htab_find_slot (include_hash, mac_ptr, INSERT);
+ 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;
+ }
+
+ new_mac_ptr = include_section->buffer + offset;
+ slot = htab_find_slot (include_hash, new_mac_ptr, INSERT);
+
if (*slot != NULL)
{
/* This has actually happened; see
}
else
{
- *slot = mac_ptr;
+ *slot = new_mac_ptr;
- dwarf_decode_macro_bytes (abfd,
- section->buffer + offset,
- mac_end, current_file,
+ dwarf_decode_macro_bytes (include_bfd, new_mac_ptr,
+ 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);
+ htab_remove_elt (include_hash, new_mac_ptr);
}
}
break;
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;
break;
case DW_MACRO_GNU_transparent_include:
+ case DW_MACRO_GNU_transparent_include_alt:
/* Note that, according to the spec, a transparent include
chain cannot call DW_MACRO_GNU_start_file. So, we can just
skip this opcode. */
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);
}
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));
cmd_show_list (show_dwarf2_cmdlist, from_tty, "");
}
-/* If section described by INFO was mmapped, munmap it now. */
-
-static void
-munmap_section_buffer (struct dwarf2_section_info *info)
-{
- if (info->map_addr != NULL)
- {
-#ifdef HAVE_MMAP
- int res;
-
- res = munmap (info->map_addr, info->map_len);
- gdb_assert (res == 0);
-#else
- /* Without HAVE_MMAP, we should never be here to begin with. */
- gdb_assert_not_reached ("no mmap support");
-#endif
- }
-}
-
-/* munmap debug sections for OBJFILE, if necessary. */
+/* Free data associated with OBJFILE, if necessary. */
static void
dwarf2_per_objfile_free (struct objfile *objfile, void *d)
{
struct dwarf2_per_objfile *data = d;
int ix;
- struct dwarf2_section_info *section;
-
- /* This is sorted according to the order they're defined in to make it easier
- to keep in sync. */
- munmap_section_buffer (&data->info);
- munmap_section_buffer (&data->abbrev);
- munmap_section_buffer (&data->line);
- munmap_section_buffer (&data->loc);
- munmap_section_buffer (&data->macinfo);
- munmap_section_buffer (&data->macro);
- munmap_section_buffer (&data->str);
- munmap_section_buffer (&data->ranges);
- munmap_section_buffer (&data->addr);
- munmap_section_buffer (&data->frame);
- munmap_section_buffer (&data->eh_frame);
- munmap_section_buffer (&data->gdb_index);
-
- for (ix = 0;
- VEC_iterate (dwarf2_section_info_def, data->types, ix, section);
- ++ix)
- munmap_section_buffer (section);
for (ix = 0; ix < dwarf2_per_objfile->n_comp_units; ++ix)
VEC_free (dwarf2_per_cu_ptr,
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);
}
\f
NULL,
&setdebuglist, &showdebuglist);
- add_setshow_zinteger_cmd ("dwarf2-die", no_class, &dwarf2_die_debug, _("\
+ add_setshow_zuinteger_cmd ("dwarf2-die", no_class, &dwarf2_die_debug, _("\
Set debugging of the dwarf2 DIE reader."), _("\
Show debugging of the dwarf2 DIE reader."), _("\
When enabled (non-zero), DIEs are dumped after they are read in.\n\
The value is the maximum depth to print."),
- NULL,
- NULL,
- &setdebuglist, &showdebuglist);
+ NULL,
+ NULL,
+ &setdebuglist, &showdebuglist);
add_setshow_boolean_cmd ("check-physname", no_class, &check_physname, _("\
Set cross-checking of \"physname\" code against demangler."), _("\
NULL, show_check_physname,
&setdebuglist, &showdebuglist);
+ add_setshow_boolean_cmd ("use-deprecated-index-sections",
+ no_class, &use_deprecated_index_sections, _("\
+Set whether to use deprecated gdb_index sections."), _("\
+Show whether to use deprecated gdb_index sections."), _("\
+When enabled, deprecated .gdb_index sections are used anyway.\n\
+Normally they are ignored either because of a missing feature or\n\
+performance issue.\n\
+Warning: This option must be enabled before gdb reads the file."),
+ NULL,
+ NULL,
+ &setlist, &showlist);
+
c = add_cmd ("gdb-index", class_files, save_gdb_index_command,
_("\
Save a gdb-index file.\n\