/* DWARF 2 debugging format support for GDB.
+
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
2004
Free Software Foundation, Inc.
#include "dwarf2loc.h"
#include "cp-support.h"
#include "hashtab.h"
+#include "command.h"
+#include "gdbcmd.h"
#include <fcntl.h>
#include "gdb_string.h"
char *macinfo_buffer;
char *ranges_buffer;
char *loc_buffer;
+
+ /* A list of all the compilation units. This is used to locate
+ the target compilation unit of a particular reference. */
+ struct dwarf2_per_cu_data **all_comp_units;
+
+ /* The number of compilation units in ALL_COMP_UNITS. */
+ int n_comp_units;
+
+ /* A chain of compilation units that are currently read in, so that
+ they can be freed later. */
+ struct dwarf2_per_cu_data *read_in_chain;
};
static struct dwarf2_per_objfile *dwarf2_per_objfile;
/* The data in a compilation unit header, after target2host
translation, looks like this. */
struct comp_unit_head
- {
- unsigned long length;
- short version;
- unsigned int abbrev_offset;
- unsigned char addr_size;
- unsigned char signed_addr_p;
- unsigned int offset_size; /* size of file offsets; either 4 or 8 */
- unsigned int initial_length_size; /* size of the length field; either
- 4 or 12 */
-
- /* Offset to the first byte of this compilation unit header in the
- * .debug_info section, for resolving relative reference dies. */
-
- unsigned int offset;
-
- /* Pointer to this compilation unit header in the .debug_info
- * section */
+{
+ unsigned long length;
+ short version;
+ unsigned int abbrev_offset;
+ unsigned char addr_size;
+ unsigned char signed_addr_p;
- char *cu_head_ptr;
+ /* Size of file offsets; either 4 or 8. */
+ unsigned int offset_size;
- /* Pointer to the first die of this compilatio unit. This will
- * be the first byte following the compilation unit header. */
+ /* Size of the length field; either 4 or 12. */
+ unsigned int initial_length_size;
- char *first_die_ptr;
+ /* Offset to the first byte of this compilation unit header in the
+ .debug_info section, for resolving relative reference dies. */
+ unsigned int offset;
- /* Pointer to the next compilation unit header in the program. */
+ /* Pointer to this compilation unit header in the .debug_info
+ section. */
+ char *cu_head_ptr;
- struct comp_unit_head *next;
+ /* Pointer to the first die of this compilation unit. This will be
+ the first byte following the compilation unit header. */
+ char *first_die_ptr;
- /* Base address of this compilation unit. */
+ /* Pointer to the next compilation unit header in the program. */
+ struct comp_unit_head *next;
- CORE_ADDR base_address;
+ /* Base address of this compilation unit. */
+ CORE_ADDR base_address;
- /* Non-zero if base_address has been set. */
+ /* Non-zero if base_address has been set. */
+ int base_known;
+};
- int base_known;
- };
+/* Fixed size for the DIE hash table. */
+#ifndef REF_HASH_SIZE
+#define REF_HASH_SIZE 1021
+#endif
/* Internal state when decoding a particular compilation unit. */
struct dwarf2_cu
unit, including partial DIEs. */
struct obstack comp_unit_obstack;
+ /* When multiple dwarf2_cu structures are living in memory, this field
+ chains them all together, so that they can be released efficiently.
+ We will probably also want a generation counter so that most-recently-used
+ compilation units are cached... */
+ struct dwarf2_per_cu_data *read_in_chain;
+
+ /* Backchain to our per_cu entry if the tree has been built. */
+ struct dwarf2_per_cu_data *per_cu;
+
+ /* How many compilation units ago was this CU last referenced? */
+ int last_used;
+
+ /* A hash table of die offsets for following references. */
+ struct die_info *die_ref_table[REF_HASH_SIZE];
+
+ /* Full DIEs if read in. */
+ struct die_info *dies;
+
+ /* A set of pointers to dwarf2_per_cu_data objects for compilation
+ units referenced by this one. Only set during full symbol processing;
+ partial symbol tables do not have dependencies. */
+ htab_t dependencies;
+
+ /* Mark used when releasing cached dies. */
+ unsigned int mark : 1;
+
+ /* This flag will be set if this compilation unit might include
+ inter-compilation-unit references. */
+ unsigned int has_form_ref_addr : 1;
+
/* This flag will be set if this compilation unit includes any
DW_TAG_namespace DIEs. If we know that there are explicit
DIEs for namespaces, we don't need to try to infer them
unsigned int has_namespace_info : 1;
};
+/* Persistent data held for a compilation unit, even when not
+ processing it. We put a pointer to this structure in the
+ read_symtab_private field of the psymtab. If we encounter
+ inter-compilation-unit references, we also maintain a sorted
+ list of all compilation units. */
+
+struct dwarf2_per_cu_data
+{
+ /* The start offset and length of this compilation unit. 2**31-1
+ bytes should suffice to store the length of any compilation unit
+ - if it doesn't, GDB will fall over anyway. */
+ unsigned long offset;
+ unsigned long length : 31;
+
+ /* Flag indicating this compilation unit will be read in before
+ any of the current compilation units are processed. */
+ unsigned long queued : 1;
+
+ /* Set iff currently read in. */
+ struct dwarf2_cu *cu;
+
+ /* If full symbols for this CU have been read in, then this field
+ holds a map of DIE offsets to types. It isn't always possible
+ to reconstruct this information later, so we have to preserve
+ it. */
+ htab_t type_hash;
+
+ /* The partial symbol table associated with this compilation unit. */
+ struct partial_symtab *psymtab;
+};
+
/* The line number information for a compilation unit (found in the
.debug_line section) begins with a "statement program header",
which contains the following information. */
#define ATTR_ALLOC_CHUNK 4
#endif
-/* A hash table of die offsets for following references. */
-#ifndef REF_HASH_SIZE
-#define REF_HASH_SIZE 1021
-#endif
-
-static struct die_info *die_ref_table[REF_HASH_SIZE];
-
/* Allocate fields for structs, unions and enums in this size. */
#ifndef DW_FIELD_ALLOC_CHUNK
#define DW_FIELD_ALLOC_CHUNK 4
decode_locdesc's return value is
the register number. */
-/* We put a pointer to this structure in the read_symtab_private field
- of the psymtab. */
-
-struct dwarf2_pinfo
- {
- /* Offset in .debug_info for this compilation unit. */
-
- unsigned long dwarf_info_offset;
- };
-
-#define PST_PRIVATE(p) ((struct dwarf2_pinfo *)(p)->read_symtab_private)
-#define DWARF_INFO_OFFSET(p) (PST_PRIVATE(p)->dwarf_info_offset)
-
/* FIXME: We might want to set this from BFD via bfd_arch_bits_per_byte,
but this would require a corresponding change in unpack_field_as_long
and friends. */
int nfnfields;
};
+/* One item on the queue of compilation units to read in full symbols
+ for. */
+struct dwarf2_queue_item
+{
+ struct dwarf2_per_cu_data *per_cu;
+ struct dwarf2_queue_item *next;
+};
+
+/* The current queue. */
+static struct dwarf2_queue_item *dwarf2_queue, *dwarf2_queue_tail;
+
+/* Loaded secondary compilation units are kept in memory until they
+ have not been referenced for the processing of this many
+ compilation units. Set this to zero to disable caching. Cache
+ sizes of up to at least twenty will improve startup time for
+ typical inter-CU-reference binaries, at an obvious memory cost. */
+static int dwarf2_max_cache_age = 5;
+static void
+show_dwarf2_max_cache_age (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("\
+The upper bound on the age of cached dwarf2 compilation units is %s.\n"),
+ value);
+}
+
+
/* Various complaints about symbol reading that don't abort the process */
static void
dwarf2_statement_list_fits_in_line_number_section_complaint (void)
{
complaint (&symfile_complaints,
- "statement list doesn't fit in .debug_line section");
+ _("statement list doesn't fit in .debug_line section"));
}
static void
dwarf2_complex_location_expr_complaint (void)
{
- complaint (&symfile_complaints, "location expression too complex");
+ complaint (&symfile_complaints, _("location expression too complex"));
}
static void
int arg3)
{
complaint (&symfile_complaints,
- "const value length mismatch for '%s', got %d, expected %d", arg1,
+ _("const value length mismatch for '%s', got %d, expected %d"), arg1,
arg2, arg3);
}
dwarf2_macros_too_long_complaint (void)
{
complaint (&symfile_complaints,
- "macro info runs off end of `.debug_macinfo' section");
+ _("macro info runs off end of `.debug_macinfo' section"));
}
static void
dwarf2_macro_malformed_definition_complaint (const char *arg1)
{
complaint (&symfile_complaints,
- "macro debug info contains a malformed macro definition:\n`%s'",
+ _("macro debug info contains a malformed macro definition:\n`%s'"),
arg1);
}
dwarf2_invalid_attrib_class_complaint (const char *arg1, const char *arg2)
{
complaint (&symfile_complaints,
- "invalid attribute class or form for '%s' in '%s'", arg1, arg2);
+ _("invalid attribute class or form for '%s' in '%s'"), arg1, arg2);
}
/* local function prototypes */
bfd *, char *, struct dwarf2_cu *);
static struct partial_die_info *find_partial_die (unsigned long,
- struct dwarf2_cu *,
- struct dwarf2_cu **);
+ struct dwarf2_cu *);
static void fixup_partial_die (struct partial_die_info *,
struct dwarf2_cu *);
static struct type *die_containing_type (struct die_info *,
struct dwarf2_cu *);
-#if 0
-static struct type *type_at_offset (unsigned int, struct objfile *);
-#endif
-
static struct type *tag_type_to_type (struct die_info *, struct dwarf2_cu *);
static void read_type_die (struct die_info *, struct dwarf2_cu *);
static char *determine_prefix (struct die_info *die, struct dwarf2_cu *);
-static char *typename_concat (const char *prefix, const char *suffix);
+static char *typename_concat (struct obstack *, const char *prefix, const char *suffix,
+ struct dwarf2_cu *);
static void read_typedef (struct die_info *, struct dwarf2_cu *);
static void read_array_type (struct die_info *, struct dwarf2_cu *);
+static enum dwarf_array_dim_ordering read_array_order (struct die_info *,
+ struct dwarf2_cu *);
+
static void read_tag_pointer_type (struct die_info *, struct dwarf2_cu *);
static void read_tag_ptr_to_member_type (struct die_info *,
static void free_die_list (struct die_info *);
-static struct cleanup *make_cleanup_free_die_list (struct die_info *);
-
static void process_die (struct die_info *, struct dwarf2_cu *);
static char *dwarf2_linkage_name (struct die_info *, struct dwarf2_cu *);
static void dump_die_list (struct die_info *);
-static void store_in_ref_table (unsigned int, struct die_info *);
-
-static void dwarf2_empty_hash_tables (void);
+static void store_in_ref_table (unsigned int, struct die_info *,
+ struct dwarf2_cu *);
static unsigned int dwarf2_get_ref_die_offset (struct attribute *,
struct dwarf2_cu *);
static int dwarf2_get_attr_constant_value (struct attribute *, int);
-static struct die_info *follow_die_ref (unsigned int);
+static struct die_info *follow_die_ref (struct die_info *,
+ struct attribute *,
+ struct dwarf2_cu *);
static struct type *dwarf2_fundamental_type (struct objfile *, int,
struct dwarf2_cu *);
static int partial_die_eq (const void *item_lhs, const void *item_rhs);
+static struct dwarf2_per_cu_data *dwarf2_find_containing_comp_unit
+ (unsigned long offset, struct objfile *objfile);
+
+static struct dwarf2_per_cu_data *dwarf2_find_comp_unit
+ (unsigned long offset, struct objfile *objfile);
+
+static void free_one_comp_unit (void *);
+
+static void free_cached_comp_units (void *);
+
+static void age_cached_comp_units (void);
+
+static void free_one_cached_comp_unit (void *);
+
+static void set_die_type (struct die_info *, struct type *,
+ struct dwarf2_cu *);
+
+static void reset_die_and_siblings_types (struct die_info *,
+ struct dwarf2_cu *);
+
+static void create_all_comp_units (struct objfile *);
+
+static struct dwarf2_cu *load_full_comp_unit (struct dwarf2_per_cu_data *);
+
+static void process_full_comp_unit (struct dwarf2_per_cu_data *);
+
+static void dwarf2_add_dependence (struct dwarf2_cu *,
+ struct dwarf2_per_cu_data *);
+
+static void dwarf2_mark (struct dwarf2_cu *);
+
+static void dwarf2_clear_marks (struct dwarf2_per_cu_data *);
+
/* Try to locate the sections we need for DWARF 2 debugging
information and return true if we have enough to do something. */
#endif
/* Read in the comp unit header information from the debug_info at
- info_ptr. */
+ info_ptr. */
static char *
read_comp_unit_head (struct comp_unit_head *cu_header,
signed_addr = bfd_get_sign_extend_vma (abfd);
if (signed_addr < 0)
internal_error (__FILE__, __LINE__,
- "read_comp_unit_head: dwarf from non elf file");
+ _("read_comp_unit_head: dwarf from non elf file"));
cu_header->signed_addr_p = signed_addr;
return info_ptr;
}
info_ptr = read_comp_unit_head (header, info_ptr, abfd);
if (header->version != 2)
- error ("Dwarf Error: wrong version in compilation unit header "
- "(is %d, should be %d) [in module %s]", header->version,
+ error (_("Dwarf Error: wrong version in compilation unit header "
+ "(is %d, should be %d) [in module %s]"), header->version,
2, bfd_get_filename (abfd));
if (header->abbrev_offset >= dwarf2_per_objfile->abbrev_size)
- error ("Dwarf Error: bad offset (0x%lx) in compilation unit header "
- "(offset 0x%lx + 6) [in module %s]",
+ error (_("Dwarf Error: bad offset (0x%lx) in compilation unit header "
+ "(offset 0x%lx + 6) [in module %s]"),
(long) header->abbrev_offset,
(long) (beg_of_comp_unit - dwarf2_per_objfile->info_buffer),
bfd_get_filename (abfd));
if (beg_of_comp_unit + header->length + header->initial_length_size
> dwarf2_per_objfile->info_buffer + dwarf2_per_objfile->info_size)
- error ("Dwarf Error: bad length (0x%lx) in compilation unit header "
- "(offset 0x%lx + 0) [in module %s]",
+ error (_("Dwarf Error: bad length (0x%lx) in compilation unit header "
+ "(offset 0x%lx + 0) [in module %s]"),
(long) header->length,
(long) (beg_of_comp_unit - dwarf2_per_objfile->info_buffer),
bfd_get_filename (abfd));
/* No private part is necessary for include psymtabs. This property
can be used to differentiate between such include psymtabs and
- the regular ones. If it ever happens that a regular psymtab can
- legitimally have a NULL private part, then we'll have to add a
- dedicated field for that in the dwarf2_pinfo structure. */
+ the regular ones. */
subpst->read_symtab_private = NULL;
}
char *beg_of_comp_unit;
struct partial_die_info comp_unit_die;
struct partial_symtab *pst;
+ struct cleanup *back_to;
CORE_ADDR lowpc, highpc, baseaddr;
info_ptr = dwarf2_per_objfile->info_buffer;
+ /* Any cached compilation units will be linked by the per-objfile
+ read_in_chain. Make sure to free them when we're done. */
+ back_to = make_cleanup (free_cached_comp_units, NULL);
+
+ create_all_comp_units (objfile);
+
/* Since the objects we're extracting from .debug_info vary in
length, only the individual functions to extract them (like
read_comp_unit_head and load_partial_die) can really know whether
cu.list_in_scope = &file_symbols;
- cu.partial_dies = NULL;
-
/* Read the abbrevs for this compilation unit into a table */
dwarf2_read_abbrevs (abfd, &cu);
make_cleanup (dwarf2_free_abbrev_table, &cu);
+ this_cu = dwarf2_find_comp_unit (cu.header.offset, objfile);
+
/* Read the compilation unit die */
abbrev = peek_die_abbrev (info_ptr, &bytes_read, &cu);
info_ptr = read_partial_die (&comp_unit_die, abbrev, bytes_read,
objfile->global_psymbols.next,
objfile->static_psymbols.next);
- if (comp_unit_die.dirname)
- pst->dirname = xstrdup (comp_unit_die.dirname);
+ if (comp_unit_die.dirname)
+ pst->dirname = xstrdup (comp_unit_die.dirname);
+
+ pst->read_symtab_private = (char *) this_cu;
- pst->read_symtab_private = (char *)
- obstack_alloc (&objfile->objfile_obstack, sizeof (struct dwarf2_pinfo));
- DWARF_INFO_OFFSET (pst) = beg_of_comp_unit - dwarf2_per_objfile->info_buffer;
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
/* Store the function that reads in the rest of the symbol table */
pst->read_symtab = dwarf2_psymtab_to_symtab;
+ /* If this compilation unit was already read in, free the
+ cached copy in order to read it in again. This is
+ necessary because we skipped some symbols when we first
+ read in the compilation unit (see load_partial_dies).
+ This problem could be avoided, but the benefit is
+ unclear. */
+ if (this_cu->cu != NULL)
+ free_one_cached_comp_unit (this_cu->cu);
+
+ cu.per_cu = this_cu;
+
+ /* Note that this is a pointer to our stack frame, being
+ added to a global data structure. It will be cleaned up
+ in free_stack_comp_unit when we finish with this
+ compilation unit. */
+ this_cu->cu = &cu;
+
+ this_cu->psymtab = pst;
+
/* Check if comp unit has_children.
If so, read the rest of the partial symbols from this comp unit.
If not, there's no more debug_info for this comp unit. */
also happen.) This happens in VxWorks. */
free_named_symtabs (pst->filename);
+ info_ptr = beg_of_comp_unit + cu.header.length
+ + cu.header.initial_length_size;
+
if (comp_unit_die.has_stmt_list)
{
/* Get the list of files included in the current compilation unit,
dwarf2_build_include_psymtabs (&cu, &comp_unit_die, pst);
}
- info_ptr = beg_of_comp_unit + cu.header.length
- + cu.header.initial_length_size;
-
do_cleanups (back_to_inner);
}
+ do_cleanups (back_to);
+}
+
+/* Load the DIEs for a secondary CU into memory. */
+
+static void
+load_comp_unit (struct dwarf2_per_cu_data *this_cu, struct objfile *objfile)
+{
+ bfd *abfd = objfile->obfd;
+ char *info_ptr, *beg_of_comp_unit;
+ struct partial_die_info comp_unit_die;
+ struct dwarf2_cu *cu;
+ struct abbrev_info *abbrev;
+ unsigned int bytes_read;
+ struct cleanup *back_to;
+
+ info_ptr = dwarf2_per_objfile->info_buffer + this_cu->offset;
+ beg_of_comp_unit = info_ptr;
+
+ cu = xmalloc (sizeof (struct dwarf2_cu));
+ memset (cu, 0, sizeof (struct dwarf2_cu));
+
+ obstack_init (&cu->comp_unit_obstack);
+
+ cu->objfile = objfile;
+ info_ptr = partial_read_comp_unit_head (&cu->header, info_ptr, abfd);
+
+ /* Complete the cu_header. */
+ cu->header.offset = beg_of_comp_unit - dwarf2_per_objfile->info_buffer;
+ cu->header.first_die_ptr = info_ptr;
+ cu->header.cu_head_ptr = beg_of_comp_unit;
+
+ /* Read the abbrevs for this compilation unit into a table. */
+ dwarf2_read_abbrevs (abfd, cu);
+ back_to = make_cleanup (dwarf2_free_abbrev_table, cu);
+
+ /* Read the compilation unit die. */
+ abbrev = peek_die_abbrev (info_ptr, &bytes_read, cu);
+ info_ptr = read_partial_die (&comp_unit_die, abbrev, bytes_read,
+ abfd, info_ptr, cu);
+
+ /* Set the language we're debugging. */
+ set_cu_language (comp_unit_die.language, cu);
+
+ /* Link this compilation unit into the compilation unit tree. */
+ this_cu->cu = cu;
+ cu->per_cu = this_cu;
+
+ /* Check if comp unit has_children.
+ If so, read the rest of the partial symbols from this comp unit.
+ If not, there's no more debug_info for this comp unit. */
+ if (comp_unit_die.has_children)
+ load_partial_dies (abfd, info_ptr, 0, cu);
+
+ do_cleanups (back_to);
+}
+
+/* Create a list of all compilation units in OBJFILE. We do this only
+ if an inter-comp-unit reference is found; presumably if there is one,
+ there will be many, and one will occur early in the .debug_info section.
+ So there's no point in building this list incrementally. */
+
+static void
+create_all_comp_units (struct objfile *objfile)
+{
+ int n_allocated;
+ int n_comp_units;
+ struct dwarf2_per_cu_data **all_comp_units;
+ char *info_ptr = dwarf2_per_objfile->info_buffer;
+
+ n_comp_units = 0;
+ n_allocated = 10;
+ all_comp_units = xmalloc (n_allocated
+ * sizeof (struct dwarf2_per_cu_data *));
+
+ while (info_ptr < dwarf2_per_objfile->info_buffer + dwarf2_per_objfile->info_size)
+ {
+ struct comp_unit_head cu_header;
+ char *beg_of_comp_unit;
+ struct dwarf2_per_cu_data *this_cu;
+ unsigned long offset;
+ int bytes_read;
+
+ offset = info_ptr - dwarf2_per_objfile->info_buffer;
+
+ /* Read just enough information to find out where the next
+ compilation unit is. */
+ cu_header.initial_length_size = 0;
+ cu_header.length = read_initial_length (objfile->obfd, info_ptr,
+ &cu_header, &bytes_read);
+
+ /* Save the compilation unit for later lookup. */
+ this_cu = obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct dwarf2_per_cu_data));
+ memset (this_cu, 0, sizeof (*this_cu));
+ this_cu->offset = offset;
+ this_cu->length = cu_header.length + cu_header.initial_length_size;
+
+ if (n_comp_units == n_allocated)
+ {
+ 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;
+
+ info_ptr = info_ptr + this_cu->length;
+ }
+
+ dwarf2_per_objfile->all_comp_units
+ = obstack_alloc (&objfile->objfile_obstack,
+ n_comp_units * sizeof (struct dwarf2_per_cu_data *));
+ memcpy (dwarf2_per_objfile->all_comp_units, all_comp_units,
+ n_comp_units * sizeof (struct dwarf2_per_cu_data *));
+ xfree (all_comp_units);
+ dwarf2_per_objfile->n_comp_units = n_comp_units;
}
/* Process all loaded DIEs for compilation unit CU, starting at FIRST_DIE.
/* Functions used to compute the fully scoped name of a partial DIE.
Normally, this is simple. For C++, the parent DIE's fully scoped
- name is concatenated with "::" and the partial DIE's name.
+ name is concatenated with "::" and the partial DIE's name. For
+ Java, the same thing occurs except that "." is used instead of "::".
Enumerators are an exception; they use the scope of their parent
enumeration type, i.e. the name of the enumeration type is not
prepended to the enumerator.
{
char *grandparent_scope;
struct partial_die_info *parent, *real_pdi;
- struct dwarf2_cu *spec_cu;
/* We need to look at our parent DIE; if we have a DW_AT_specification,
then this means the parent of the specification DIE. */
real_pdi = pdi;
- spec_cu = cu;
while (real_pdi->has_specification)
- real_pdi = find_partial_die (real_pdi->spec_offset, spec_cu, &spec_cu);
+ real_pdi = find_partial_die (real_pdi->spec_offset, cu);
parent = real_pdi->die_parent;
if (parent == NULL)
fixup_partial_die (parent, cu);
- grandparent_scope = partial_die_parent_scope (parent, spec_cu);
+ grandparent_scope = partial_die_parent_scope (parent, cu);
if (parent->tag == DW_TAG_namespace
|| parent->tag == DW_TAG_structure_type
if (grandparent_scope == NULL)
parent->scope = parent->name;
else
- parent->scope = obconcat (&cu->comp_unit_obstack, grandparent_scope,
- "::", parent->name);
+ parent->scope = typename_concat (&cu->comp_unit_obstack, grandparent_scope,
+ parent->name, cu);
}
else if (parent->tag == DW_TAG_enumeration_type)
/* Enumerators should not get the name of the enumeration as a prefix. */
function-local names? For partial symbols, we should probably be
ignoring them. */
complaint (&symfile_complaints,
- "unhandled containing DIE tag %d for DIE at %d",
+ _("unhandled containing DIE tag %d for DIE at %d"),
parent->tag, pdi->offset);
parent->scope = grandparent_scope;
}
if (parent_scope == NULL)
return NULL;
else
- return concat (parent_scope, "::", pdi->name, NULL);
+ return typename_concat (NULL, parent_scope, pdi->name, cu);
}
static void
return;
add_psymbol_to_list (actual_name, strlen (actual_name),
STRUCT_DOMAIN, LOC_TYPEDEF,
- cu->language == language_cplus
+ (cu->language == language_cplus
+ || cu->language == language_java)
? &objfile->global_psymbols
: &objfile->static_psymbols,
0, (CORE_ADDR) 0, cu->language, objfile);
- if (cu->language == language_cplus)
+ if (cu->language == language_cplus
+ || cu->language == language_java)
{
- /* For C++, these implicitly act as typedefs as well. */
+ /* For C++ and Java, these implicitly act as typedefs as well. */
add_psymbol_to_list (actual_name, strlen (actual_name),
VAR_DOMAIN, LOC_TYPEDEF,
&objfile->global_psymbols,
case DW_TAG_enumerator:
add_psymbol_to_list (actual_name, strlen (actual_name),
VAR_DOMAIN, LOC_CONST,
- cu->language == language_cplus
+ (cu->language == language_cplus
+ || cu->language == language_java)
? &objfile->global_psymbols
: &objfile->static_psymbols,
0, (CORE_ADDR) 0, cu->language, objfile);
guess_structure_name (struct partial_die_info *struct_pdi,
struct dwarf2_cu *cu)
{
- if (cu->language == language_cplus
+ if ((cu->language == language_cplus
+ || cu->language == language_java)
&& cu->has_namespace_info == 0
&& struct_pdi->has_children)
{
struct partial_die_info *child_pdi = struct_pdi->die_child;
struct partial_die_info *real_pdi;
- struct dwarf2_cu *spec_cu;
/* If this DIE (this DIE's specification, if any) has a parent, then
we should not do this. We'll prepend the parent's fully qualified
name when we create the partial symbol. */
real_pdi = struct_pdi;
- spec_cu = cu;
while (real_pdi->has_specification)
- real_pdi = find_partial_die (real_pdi->spec_offset, spec_cu, &spec_cu);
+ real_pdi = find_partial_die (real_pdi->spec_offset, cu);
if (real_pdi->die_parent != NULL)
return;
while (pdi)
{
if (pdi->tag != DW_TAG_enumerator || pdi->name == NULL)
- complaint (&symfile_complaints, "malformed enumerator DIE ignored");
+ complaint (&symfile_complaints, _("malformed enumerator DIE ignored"));
else
add_partial_symbol (pdi, cu);
pdi = pdi->die_sibling;
abbrev = dwarf2_lookup_abbrev (abbrev_number, cu);
if (!abbrev)
{
- error ("Dwarf Error: Could not find abbrev number %d [in module %s]", abbrev_number,
+ error (_("Dwarf Error: Could not find abbrev number %d [in module %s]"), abbrev_number,
bfd_get_filename (abfd));
}
read_attribute (&attr, &abbrev->attrs[i],
abfd, info_ptr, cu);
if (attr.form == DW_FORM_ref_addr)
- complaint (&symfile_complaints, "ignoring absolute DW_AT_sibling");
+ complaint (&symfile_complaints, _("ignoring absolute DW_AT_sibling"));
else
return dwarf2_per_objfile->info_buffer
+ dwarf2_get_ref_die_offset (&attr, cu);
goto skip_attribute;
default:
- error ("Dwarf Error: Cannot handle %s in DWARF reader [in module %s]",
+ error (_("Dwarf Error: Cannot handle %s in DWARF reader [in module %s]"),
dwarf_form_name (form),
bfd_get_filename (abfd));
}
{
if (pst->readin)
{
- warning ("bug: psymtab for %s is already read in.", pst->filename);
+ warning (_("bug: psymtab for %s is already read in."), pst->filename);
}
else
{
if (info_verbose)
{
- printf_filtered ("Reading in symbols for %s...", pst->filename);
+ printf_filtered (_("Reading in symbols for %s..."), pst->filename);
gdb_flush (gdb_stdout);
}
+ /* Restore our global data. */
+ dwarf2_per_objfile = objfile_data (pst->objfile,
+ dwarf2_objfile_data_key);
+
psymtab_to_symtab_1 (pst);
/* Finish up the debug error message. */
if (info_verbose)
- printf_filtered ("done.\n");
+ printf_filtered (_("done.\n"));
+ }
+ }
+}
+
+/* Add PER_CU to the queue. */
+
+static void
+queue_comp_unit (struct dwarf2_per_cu_data *per_cu)
+{
+ struct dwarf2_queue_item *item;
+
+ per_cu->queued = 1;
+ item = xmalloc (sizeof (*item));
+ item->per_cu = per_cu;
+ item->next = NULL;
+
+ if (dwarf2_queue == NULL)
+ dwarf2_queue = item;
+ else
+ dwarf2_queue_tail->next = item;
+
+ dwarf2_queue_tail = item;
+}
+
+/* Process the queue. */
+
+static void
+process_queue (struct objfile *objfile)
+{
+ struct dwarf2_queue_item *item, *next_item;
+
+ /* Initially, there is just one item on the queue. Load its DIEs,
+ and the DIEs of any other compilation units it requires,
+ transitively. */
+
+ for (item = dwarf2_queue; item != NULL; item = item->next)
+ {
+ /* Read in this compilation unit. This may add new items to
+ the end of the queue. */
+ load_full_comp_unit (item->per_cu);
+
+ item->per_cu->cu->read_in_chain = dwarf2_per_objfile->read_in_chain;
+ dwarf2_per_objfile->read_in_chain = item->per_cu;
+
+ /* If this compilation unit has already had full symbols created,
+ reset the TYPE fields in each DIE. */
+ if (item->per_cu->psymtab->readin)
+ reset_die_and_siblings_types (item->per_cu->cu->dies,
+ item->per_cu->cu);
+ }
+
+ /* Now everything left on the queue needs to be read in. Process
+ them, one at a time, removing from the queue as we finish. */
+ for (item = dwarf2_queue; item != NULL; dwarf2_queue = item = next_item)
+ {
+ if (!item->per_cu->psymtab->readin)
+ process_full_comp_unit (item->per_cu);
+
+ item->per_cu->queued = 0;
+ next_item = item->next;
+ xfree (item);
+ }
+
+ dwarf2_queue_tail = NULL;
+}
+
+/* Free all allocated queue entries. This function only releases anything if
+ an error was thrown; if the queue was processed then it would have been
+ freed as we went along. */
+
+static void
+dwarf2_release_queue (void *dummy)
+{
+ struct dwarf2_queue_item *item, *last;
+
+ item = dwarf2_queue;
+ while (item)
+ {
+ /* Anything still marked queued is likely to be in an
+ inconsistent state, so discard it. */
+ if (item->per_cu->queued)
+ {
+ if (item->per_cu->cu != NULL)
+ free_one_cached_comp_unit (item->per_cu->cu);
+ item->per_cu->queued = 0;
}
+
+ last = item;
+ item = item->next;
+ xfree (last);
}
+
+ dwarf2_queue = dwarf2_queue_tail = NULL;
}
+/* Read in full symbols for PST, and anything it depends on. */
+
static void
psymtab_to_symtab_1 (struct partial_symtab *pst)
{
- struct objfile *objfile = pst->objfile;
- bfd *abfd = objfile->obfd;
- struct dwarf2_cu cu;
- struct die_info *dies;
- unsigned long offset;
- CORE_ADDR lowpc, highpc;
- struct die_info *child_die;
- char *info_ptr;
- struct symtab *symtab;
+ struct dwarf2_per_cu_data *per_cu;
struct cleanup *back_to;
- struct attribute *attr;
- CORE_ADDR baseaddr;
int i;
for (i = 0; i < pst->number_of_dependencies; i++)
/* Inform about additional files that need to be read in. */
if (info_verbose)
{
+ /* FIXME: i18n: Need to make this a single string. */
fputs_filtered (" ", gdb_stdout);
wrap_here ("");
fputs_filtered ("and ", gdb_stdout);
psymtab_to_symtab_1 (pst->dependencies[i]);
}
- if (pst->read_symtab_private == NULL)
+ per_cu = (struct dwarf2_per_cu_data *) pst->read_symtab_private;
+
+ if (per_cu == NULL)
{
/* It's an include file, no symbols to read for it.
Everything is in the parent symtab. */
return;
}
- dwarf2_per_objfile = objfile_data (pst->objfile, dwarf2_objfile_data_key);
+ back_to = make_cleanup (dwarf2_release_queue, NULL);
+
+ queue_comp_unit (per_cu);
+
+ process_queue (pst->objfile);
+
+ /* Age the cache, releasing compilation units that have not
+ been used recently. */
+ age_cached_comp_units ();
+
+ do_cleanups (back_to);
+}
+
+/* Load the DIEs associated with PST and PER_CU into memory. */
+
+static struct dwarf2_cu *
+load_full_comp_unit (struct dwarf2_per_cu_data *per_cu)
+{
+ struct partial_symtab *pst = per_cu->psymtab;
+ bfd *abfd = pst->objfile->obfd;
+ struct dwarf2_cu *cu;
+ unsigned long offset;
+ char *info_ptr;
+ struct cleanup *back_to, *free_cu_cleanup;
+ struct attribute *attr;
+ CORE_ADDR baseaddr;
/* Set local variables from the partial symbol table info. */
- offset = DWARF_INFO_OFFSET (pst);
+ offset = per_cu->offset;
info_ptr = dwarf2_per_objfile->info_buffer + offset;
- baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
-
- /* We're in the global namespace. */
- processing_current_prefix = "";
- obstack_init (&cu.comp_unit_obstack);
- back_to = make_cleanup (free_stack_comp_unit, &cu);
+ cu = xmalloc (sizeof (struct dwarf2_cu));
+ memset (cu, 0, sizeof (struct dwarf2_cu));
- buildsym_init ();
- make_cleanup (really_free_pendings, NULL);
+ /* If an error occurs while loading, release our storage. */
+ free_cu_cleanup = make_cleanup (free_one_comp_unit, cu);
- cu.objfile = objfile;
+ cu->objfile = pst->objfile;
/* read in the comp_unit header */
- info_ptr = read_comp_unit_head (&cu.header, info_ptr, abfd);
+ info_ptr = read_comp_unit_head (&cu->header, info_ptr, abfd);
/* Read the abbrevs for this compilation unit */
- dwarf2_read_abbrevs (abfd, &cu);
- make_cleanup (dwarf2_free_abbrev_table, &cu);
+ dwarf2_read_abbrevs (abfd, cu);
+ back_to = make_cleanup (dwarf2_free_abbrev_table, cu);
+
+ cu->header.offset = offset;
+
+ cu->per_cu = per_cu;
+ per_cu->cu = cu;
+
+ /* We use this obstack for block values in dwarf_alloc_block. */
+ obstack_init (&cu->comp_unit_obstack);
+
+ cu->dies = read_comp_unit (info_ptr, abfd, cu);
+
+ /* We try not to read any attributes in this function, because not
+ all objfiles needed for references have been loaded yet, and symbol
+ table processing isn't initialized. But we have to set the CU language,
+ or we won't be able to build types correctly. */
+ attr = dwarf2_attr (cu->dies, DW_AT_language, cu);
+ if (attr)
+ set_cu_language (DW_UNSND (attr), cu);
+ else
+ set_cu_language (language_minimal, cu);
+
+ do_cleanups (back_to);
+
+ /* We've successfully allocated this compilation unit. Let our caller
+ clean it up when finished with it. */
+ discard_cleanups (free_cu_cleanup);
+
+ return cu;
+}
+
+/* Generate full symbol information for PST and CU, whose DIEs have
+ already been loaded into memory. */
+
+static void
+process_full_comp_unit (struct dwarf2_per_cu_data *per_cu)
+{
+ struct partial_symtab *pst = per_cu->psymtab;
+ struct dwarf2_cu *cu = per_cu->cu;
+ struct objfile *objfile = pst->objfile;
+ bfd *abfd = objfile->obfd;
+ CORE_ADDR lowpc, highpc;
+ struct symtab *symtab;
+ struct cleanup *back_to;
+ struct attribute *attr;
+ CORE_ADDR baseaddr;
- cu.header.offset = offset;
+ baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
- cu.list_in_scope = &file_symbols;
+ /* We're in the global namespace. */
+ processing_current_prefix = "";
- dies = read_comp_unit (info_ptr, abfd, &cu);
+ buildsym_init ();
+ back_to = make_cleanup (really_free_pendings, NULL);
- make_cleanup_free_die_list (dies);
+ cu->list_in_scope = &file_symbols;
/* Find the base address of the compilation unit for range lists and
location lists. It will normally be specified by DW_AT_low_pc.
DW_AT_entry_pc. It's been removed, but GCC still uses this for
compilation units with discontinuous ranges. */
- cu.header.base_known = 0;
- cu.header.base_address = 0;
+ cu->header.base_known = 0;
+ cu->header.base_address = 0;
- attr = dwarf2_attr (dies, DW_AT_entry_pc, &cu);
+ attr = dwarf2_attr (cu->dies, DW_AT_entry_pc, cu);
if (attr)
{
- cu.header.base_address = DW_ADDR (attr);
- cu.header.base_known = 1;
+ cu->header.base_address = DW_ADDR (attr);
+ cu->header.base_known = 1;
}
else
{
- attr = dwarf2_attr (dies, DW_AT_low_pc, &cu);
+ attr = dwarf2_attr (cu->dies, DW_AT_low_pc, cu);
if (attr)
{
- cu.header.base_address = DW_ADDR (attr);
- cu.header.base_known = 1;
+ cu->header.base_address = DW_ADDR (attr);
+ cu->header.base_known = 1;
}
}
/* Do line number decoding in read_file_scope () */
- process_die (dies, &cu);
+ process_die (cu->dies, cu);
/* Some compilers don't define a DW_AT_high_pc attribute for the
compilation unit. If the DW_AT_high_pc is missing, synthesize
it, by scanning the DIE's below the compilation unit. */
- get_scope_pc_bounds (dies, &lowpc, &highpc, &cu);
+ get_scope_pc_bounds (cu->dies, &lowpc, &highpc, cu);
symtab = end_symtab (highpc + baseaddr, objfile, SECT_OFF_TEXT (objfile));
If the compilation is from a C file generated by language preprocessors,
do not set the language if it was already deduced by start_subfile. */
if (symtab != NULL
- && !(cu.language == language_c && symtab->language != language_c))
+ && !(cu->language == language_c && symtab->language != language_c))
{
- symtab->language = cu.language;
+ symtab->language = cu->language;
}
pst->symtab = symtab;
pst->readin = 1;
if (name == NULL || !dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu))
return;
- if (cu->language == language_cplus)
+ if (cu->language == language_cplus
+ || cu->language == language_java)
{
struct die_info *spec_die = die_specification (die, cu);
if (offset >= dwarf2_per_objfile->ranges_size)
{
complaint (&symfile_complaints,
- "Offset %d out of bounds for DW_AT_ranges attribute",
+ _("Offset %d out of bounds for DW_AT_ranges attribute"),
offset);
return 0;
}
/* We have no valid base address for the ranges
data. */
complaint (&symfile_complaints,
- "Invalid .debug_ranges data (no base address)");
+ _("Invalid .debug_ranges data (no base address)"));
return 0;
}
default:
/* Unknown accessibility. Complain and treat it as public. */
{
- complaint (&symfile_complaints, "unsupported accessibility %d",
+ complaint (&symfile_complaints, _("unsupported accessibility %d"),
fip->fields->accessibility);
}
break;
fnp->voffset = VOFFSET_STATIC;
}
else
- complaint (&symfile_complaints, "member function type missing for '%s'",
+ complaint (&symfile_complaints, _("member function type missing for '%s'"),
physname);
/* Get fcontext from DW_AT_containing_type if present. */
TYPE_NFN_FIELDS_TOTAL (type) = total_length;
}
+
+/* Returns non-zero if NAME is the name of a vtable member in CU's
+ language, zero otherwise. */
+static int
+is_vtable_name (const char *name, struct dwarf2_cu *cu)
+{
+ static const char vptr[] = "_vptr";
+ static const char vtable[] = "vtable";
+
+ /* Look for the C++ and Java forms of the vtable. */
+ if ((cu->language == language_java
+ && strncmp (name, vtable, sizeof (vtable) - 1) == 0)
+ || (strncmp (name, vptr, sizeof (vptr) - 1) == 0
+ && is_cplus_marker (name[sizeof (vptr) - 1])))
+ return 1;
+
+ return 0;
+}
+
+
/* Called when we find the DIE that starts a structure or union scope
(definition) to process all dies that define the members of the
structure or union.
attr = dwarf2_attr (die, DW_AT_name, cu);
if (attr && DW_STRING (attr))
{
- if (cu->language == language_cplus)
+ if (cu->language == language_cplus
+ || cu->language == language_java)
{
char *new_prefix = determine_class_name (die, cu);
TYPE_TAG_NAME (type) = obsavestring (new_prefix,
/* We need to add the type field to the die immediately so we don't
infinitely recurse when dealing with pointers to the structure
type within the structure itself. */
- die->type = type;
+ set_die_type (die, type, cu);
if (die->child != NULL && ! die_is_declaration (die, cu))
{
TYPE_VPTR_BASETYPE (type) = t;
if (type == t)
{
- static const char vptr_name[] =
- {'_', 'v', 'p', 't', 'r', '\0'};
int i;
/* Our own class provides vtbl ptr. */
{
char *fieldname = TYPE_FIELD_NAME (t, i);
- if ((strncmp (fieldname, vptr_name,
- strlen (vptr_name) - 1)
- == 0)
- && is_cplus_marker (fieldname[strlen (vptr_name)]))
+ if (is_vtable_name (fieldname, cu))
{
TYPE_VPTR_FIELDNO (type) = i;
break;
/* Complain if virtual function table field not found. */
if (i < TYPE_N_BASECLASSES (t))
complaint (&symfile_complaints,
- "virtual function table pointer not found when defining class '%s'",
+ _("virtual function table pointer not found when defining class '%s'"),
TYPE_TAG_NAME (type) ? TYPE_TAG_NAME (type) :
"");
}
if (processing_has_namespace_info)
{
- TYPE_TAG_NAME (type) = obconcat (&objfile->objfile_obstack,
- processing_current_prefix,
- processing_current_prefix[0] == '\0'
- ? "" : "::",
- name);
+ TYPE_TAG_NAME (type) = typename_concat (&objfile->objfile_obstack,
+ processing_current_prefix,
+ name, cu);
}
else
{
TYPE_LENGTH (type) = 0;
}
- die->type = type;
+ set_die_type (die, type, cu);
}
/* Determine the name of the type represented by DIE, which should be
- a named C++ compound type. Return the name in question; the caller
+ a named C++ or Java compound type. Return the name in question; the caller
is responsible for xfree()'ing it. */
static char *
if (new_prefix == NULL)
{
const char *name = dwarf2_name (die, cu);
- new_prefix = typename_concat (processing_current_prefix,
- name ? name : "<<anonymous>>");
+ new_prefix = typename_concat (NULL, processing_current_prefix,
+ name ? name : "<<anonymous>>",
+ cu);
}
if (back_to != NULL)
{
index_type = dwarf2_fundamental_type (objfile, FT_INTEGER, cu);
range_type = create_range_type (NULL, index_type, 0, -1);
- die->type = create_array_type (NULL, element_type, range_type);
+ set_die_type (die, create_array_type (NULL, element_type, range_type),
+ cu);
return;
}
/* Dwarf2 dimensions are output from left to right, create the
necessary array types in backwards order. */
+
type = element_type;
- while (ndim-- > 0)
- type = create_array_type (NULL, type, range_types[ndim]);
+
+ if (read_array_order (die, cu) == DW_ORD_col_major)
+ {
+ int i = 0;
+ while (i < ndim)
+ type = create_array_type (NULL, type, range_types[i++]);
+ }
+ else
+ {
+ while (ndim-- > 0)
+ type = create_array_type (NULL, type, range_types[ndim]);
+ }
/* Understand Dwarf2 support for vector types (like they occur on
the PowerPC w/ AltiVec). Gcc just adds another attribute to the
do_cleanups (back_to);
/* Install the type in the die. */
- die->type = type;
+ set_die_type (die, type, cu);
}
-/* First cut: install each common block member as a global variable. */
+static enum dwarf_array_dim_ordering
+read_array_order (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct attribute *attr;
+
+ attr = dwarf2_attr (die, DW_AT_ordering, cu);
+
+ if (attr) return DW_SND (attr);
+
+ /*
+ GNU F77 is a special case, as at 08/2004 array type info is the
+ opposite order to the dwarf2 specification, but data is still
+ laid out as per normal fortran.
+
+ FIXME: dsl/2004-8-20: If G77 is ever fixed, this will also need
+ version checking.
+ */
+
+ if (cu->language == language_fortran &&
+ cu->producer && strstr (cu->producer, "GNU F77"))
+ {
+ return DW_ORD_row_major;
+ }
+
+ switch (cu->language_defn->la_array_ordering)
+ {
+ case array_column_major:
+ return DW_ORD_col_major;
+ case array_row_major:
+ default:
+ return DW_ORD_row_major;
+ };
+}
+
+
+/* First cut: install each common block member as a global variable. */
static void
read_common_block (struct die_info *die, struct dwarf2_cu *cu)
const char *name;
int is_anonymous;
struct die_info *current_die;
+ struct cleanup *back_to = make_cleanup (null_cleanup, 0);
name = namespace_name (die, &is_anonymous, cu);
}
else
{
- /* We need temp_name around because processing_current_prefix
- is a const char *. */
- char *temp_name = alloca (strlen (previous_prefix)
- + 2 + strlen(name) + 1);
- strcpy (temp_name, previous_prefix);
- strcat (temp_name, "::");
- strcat (temp_name, name);
-
+ char *temp_name = typename_concat (NULL, previous_prefix, name, cu);
+ make_cleanup (xfree, temp_name);
processing_current_prefix = temp_name;
}
TYPE_TAG_NAME (type) = TYPE_NAME (type);
new_symbol (die, type, cu);
- die->type = type;
+ set_die_type (die, type, cu);
if (is_anonymous)
cp_add_using_directive (processing_current_prefix,
}
processing_current_prefix = previous_prefix;
+ do_cleanups (back_to);
}
/* Return the name of the namespace represented by DIE. Set
}
else if (TYPE_LENGTH (type) != byte_size)
{
- complaint (&symfile_complaints, "invalid pointer size %d", byte_size);
+ complaint (&symfile_complaints, _("invalid pointer size %d"), byte_size);
}
else {
/* Should we also complain about unhandled address classes? */
}
TYPE_LENGTH (type) = byte_size;
- die->type = type;
+ set_die_type (die, type, cu);
}
/* Extract all information from a DW_TAG_ptr_to_member_type DIE and add to
domain = die_containing_type (die, cu);
smash_to_member_type (type, domain, to_type);
- die->type = type;
+ set_die_type (die, type, cu);
}
/* Extract all information from a DW_TAG_reference_type DIE and add to
{
TYPE_LENGTH (type) = cu_header->addr_size;
}
- die->type = type;
+ set_die_type (die, type, cu);
}
static void
}
base_type = die_type (die, cu);
- die->type = make_cv_type (1, TYPE_VOLATILE (base_type), base_type, 0);
+ set_die_type (die, make_cv_type (1, TYPE_VOLATILE (base_type), base_type, 0),
+ cu);
}
static void
}
base_type = die_type (die, cu);
- die->type = make_cv_type (TYPE_CONST (base_type), 1, base_type, 0);
+ set_die_type (die, make_cv_type (TYPE_CONST (base_type), 1, base_type, 0),
+ cu);
}
/* Extract all information from a DW_TAG_string_type DIE and add to
char_type = dwarf2_fundamental_type (objfile, FT_CHAR, cu);
type = create_string_type (char_type, range_type);
}
- die->type = type;
+ set_die_type (die, type, cu);
}
/* Handle DIES due to C code like:
return;
}
type = die_type (die, cu);
- ftype = lookup_function_type (type);
+ ftype = make_function_type (type, (struct type **) 0);
- /* All functions in C++ have prototypes. */
+ /* All functions in C++ and Java have prototypes. */
attr = dwarf2_attr (die, DW_AT_prototyped, cu);
if ((attr && (DW_UNSND (attr) != 0))
- || cu->language == language_cplus)
+ || cu->language == language_cplus
+ || cu->language == language_java)
TYPE_FLAGS (ftype) |= TYPE_FLAG_PROTOTYPED;
if (die->child != NULL)
}
}
- die->type = ftype;
+ set_die_type (die, ftype, cu);
}
static void
{
name = DW_STRING (attr);
}
- die->type = init_type (TYPE_CODE_TYPEDEF, 0, TYPE_FLAG_TARGET_STUB, name, objfile);
+ set_die_type (die, init_type (TYPE_CODE_TYPEDEF, 0,
+ TYPE_FLAG_TARGET_STUB, name, objfile),
+ cu);
TYPE_TARGET_TYPE (die->type) = die_type (die, cu);
}
}
type_flags |= TYPE_FLAG_UNSIGNED;
break;
default:
- complaint (&symfile_complaints, "unsupported DW_AT_encoding: '%s'",
+ complaint (&symfile_complaints, _("unsupported DW_AT_encoding: '%s'"),
dwarf_type_encoding_name (encoding));
break;
}
{
type = dwarf_base_type (encoding, size, cu);
}
- die->type = type;
+ set_die_type (die, type, cu);
}
/* Read the given DW_AT_subrange DIE. */
if (base_type == NULL)
{
complaint (&symfile_complaints,
- "DW_AT_type missing from DW_TAG_subrange_type");
+ _("DW_AT_type missing from DW_TAG_subrange_type"));
return;
}
low = 1;
}
+ /* FIXME: For variable sized arrays either of these could be
+ a variable rather than a constant value. We'll allow it,
+ but we don't know how to handle it. */
attr = dwarf2_attr (die, DW_AT_lower_bound, cu);
if (attr)
low = dwarf2_get_attr_constant_value (attr, 0);
if (attr)
TYPE_LENGTH (range_type) = DW_UNSND (attr);
- die->type = range_type;
+ set_die_type (die, range_type, cu);
}
static struct die_info *
read_comp_unit (char *info_ptr, bfd *abfd, struct dwarf2_cu *cu)
{
- /* Reset die reference table; we are
- building new ones now. */
- dwarf2_empty_hash_tables ();
-
return read_die_and_children (info_ptr, abfd, cu, &info_ptr, NULL);
}
int has_children;
cur_ptr = read_full_die (&die, abfd, info_ptr, cu, &has_children);
- store_in_ref_table (die->offset, die);
+ store_in_ref_table (die->offset, die, cu);
if (has_children)
{
}
}
-static void
-do_free_die_list_cleanup (void *dies)
-{
- free_die_list (dies);
-}
-
-static struct cleanup *
-make_cleanup_free_die_list (struct die_info *dies)
-{
- return make_cleanup (do_free_die_list_cleanup, dies);
-}
-
-
/* Read the contents of the section at OFFSET and of size SIZE from the
object file specified by OBJFILE into the objfile_obstack and return it. */
if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0
|| bfd_bread (buf, size, abfd) != size)
- error ("Dwarf Error: Can't read DWARF data from '%s'",
+ error (_("Dwarf Error: Can't read DWARF data from '%s'"),
bfd_get_filename (abfd));
return buf;
= xrealloc (cur_attrs, (allocated_attrs
* sizeof (struct attr_abbrev)));
}
+
+ /* Record whether this compilation unit might have
+ inter-compilation-unit references. If we don't know what form
+ this attribute will have, then it might potentially be a
+ DW_FORM_ref_addr, so we conservatively expect inter-CU
+ references. */
+
+ if (abbrev_form == DW_FORM_ref_addr
+ || abbrev_form == DW_FORM_indirect)
+ cu->has_form_ref_addr = 1;
+
cur_attrs[cur_abbrev->num_attrs].name = abbrev_name;
cur_attrs[cur_abbrev->num_attrs++].form = abbrev_form;
abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
&& parent_die->has_specification == 0)
{
if (part_die->name == NULL)
- complaint (&symfile_complaints, "malformed enumerator DIE ignored");
+ complaint (&symfile_complaints, _("malformed enumerator DIE ignored"));
else if (building_psymtab)
add_psymbol_to_list (part_die->name, strlen (part_die->name),
VAR_DOMAIN, LOC_CONST,
- cu->language == language_cplus
+ (cu->language == language_cplus
+ || cu->language == language_java)
? &cu->objfile->global_psymbols
: &cu->objfile->static_psymbols,
0, (CORE_ADDR) 0, cu->language, cu->objfile);
/* Ignore absolute siblings, they might point outside of
the current compile unit. */
if (attr.form == DW_FORM_ref_addr)
- complaint (&symfile_complaints, "ignoring absolute DW_AT_sibling");
+ complaint (&symfile_complaints, _("ignoring absolute DW_AT_sibling"));
else
part_die->sibling = dwarf2_per_objfile->info_buffer
+ dwarf2_get_ref_die_offset (&attr, cu);
if (lookup_die == NULL)
internal_error (__FILE__, __LINE__,
- "could not find partial DIE in cache\n");
+ _("could not find partial DIE in cache\n"));
return lookup_die;
}
/* Find a partial DIE at OFFSET, which may or may not be in CU. */
static struct partial_die_info *
-find_partial_die (unsigned long offset, struct dwarf2_cu *cu,
- struct dwarf2_cu **target_cu)
+find_partial_die (unsigned long offset, struct dwarf2_cu *cu)
{
struct dwarf2_per_cu_data *per_cu;
if (offset >= cu->header.offset
&& offset < cu->header.offset + cu->header.length)
+ return find_partial_die_in_comp_unit (offset, cu);
+
+ per_cu = dwarf2_find_containing_comp_unit (offset, cu->objfile);
+
+ if (per_cu->cu == NULL)
{
- *target_cu = cu;
- return find_partial_die_in_comp_unit (offset, cu);
+ load_comp_unit (per_cu, cu->objfile);
+ per_cu->cu->read_in_chain = dwarf2_per_objfile->read_in_chain;
+ dwarf2_per_objfile->read_in_chain = per_cu;
}
- internal_error (__FILE__, __LINE__,
- "unsupported inter-compilation-unit reference");
+ per_cu->cu->last_used = 0;
+ return find_partial_die_in_comp_unit (offset, per_cu->cu);
}
/* Adjust PART_DIE before generating a symbol for it. This function
if (part_die->name == NULL && part_die->has_specification)
{
struct partial_die_info *spec_die;
- struct dwarf2_cu *spec_cu;
- spec_die = find_partial_die (part_die->spec_offset, cu, &spec_cu);
+ spec_die = find_partial_die (part_die->spec_offset, cu);
- fixup_partial_die (spec_die, spec_cu);
+ fixup_partial_die (spec_die, cu);
if (spec_die->name)
{
abbrev = dwarf2_lookup_abbrev (abbrev_number, cu);
if (!abbrev)
{
- error ("Dwarf Error: could not find abbrev number %d [in module %s]",
+ error (_("Dwarf Error: could not find abbrev number %d [in module %s]"),
abbrev_number,
bfd_get_filename (abfd));
}
{
info_ptr = read_attribute (&die->attrs[i], &abbrev->attrs[i],
abfd, info_ptr, cu);
+
+ /* If this attribute is an absolute reference to a different
+ compilation unit, make sure that compilation unit is loaded
+ also. */
+ if (die->attrs[i].form == DW_FORM_ref_addr
+ && (DW_ADDR (&die->attrs[i]) < cu->header.offset
+ || (DW_ADDR (&die->attrs[i])
+ >= cu->header.offset + cu->header.length)))
+ {
+ struct dwarf2_per_cu_data *per_cu;
+ per_cu = dwarf2_find_containing_comp_unit (DW_ADDR (&die->attrs[i]),
+ cu->objfile);
+
+ /* Mark the dependence relation so that we don't flush PER_CU
+ too early. */
+ dwarf2_add_dependence (cu, per_cu);
+
+ /* If it's already on the queue, we have nothing to do. */
+ if (per_cu->queued)
+ continue;
+
+ /* If the compilation unit is already loaded, just mark it as
+ used. */
+ if (per_cu->cu != NULL)
+ {
+ per_cu->cu->last_used = 0;
+ continue;
+ }
+
+ /* Add it to the queue. */
+ queue_comp_unit (per_cu);
+ }
}
*diep = die;
info_ptr += bytes_read;
break;
case DW_FORM_ref1:
- DW_UNSND (attr) = read_1_byte (abfd, info_ptr);
+ DW_ADDR (attr) = cu->header.offset + read_1_byte (abfd, info_ptr);
info_ptr += 1;
break;
case DW_FORM_ref2:
- DW_UNSND (attr) = read_2_bytes (abfd, info_ptr);
+ DW_ADDR (attr) = cu->header.offset + read_2_bytes (abfd, info_ptr);
info_ptr += 2;
break;
case DW_FORM_ref4:
- DW_UNSND (attr) = read_4_bytes (abfd, info_ptr);
+ DW_ADDR (attr) = cu->header.offset + read_4_bytes (abfd, info_ptr);
info_ptr += 4;
break;
case DW_FORM_ref8:
- DW_UNSND (attr) = read_8_bytes (abfd, info_ptr);
+ DW_ADDR (attr) = cu->header.offset + read_8_bytes (abfd, info_ptr);
info_ptr += 8;
break;
case DW_FORM_ref_udata:
- DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+ DW_ADDR (attr) = (cu->header.offset
+ + read_unsigned_leb128 (abfd, info_ptr, &bytes_read));
info_ptr += bytes_read;
break;
case DW_FORM_indirect:
info_ptr = read_attribute_value (attr, form, abfd, info_ptr, cu);
break;
default:
- error ("Dwarf Error: Cannot handle %s in DWARF reader [in module %s]",
+ error (_("Dwarf Error: Cannot handle %s in DWARF reader [in module %s]"),
dwarf_form_name (form),
bfd_get_filename (abfd));
}
break;
default:
internal_error (__FILE__, __LINE__,
- "read_address: bad switch, signed [in module %s]",
+ _("read_address: bad switch, signed [in module %s]"),
bfd_get_filename (abfd));
}
}
break;
default:
internal_error (__FILE__, __LINE__,
- "read_address: bad switch, unsigned [in module %s]",
+ _("read_address: bad switch, unsigned [in module %s]"),
bfd_get_filename (abfd));
}
}
sense for the 32-bit format, this initial zero can be considered to
be an escape value which indicates the presence of the older 64-bit
format. As written, the code can't detect (old format) lengths
- greater than 4GB. If it becomes necessary to handle lengths somewhat
- larger than 4GB, we could allow other small values (such as the
- non-sensical values of 1, 2, and 3) to also be used as escape values
- indicating the presence of the old format.
+ greater than 4GB. If it becomes necessary to handle lengths
+ somewhat larger than 4GB, we could allow other small values (such
+ as the non-sensical values of 1, 2, and 3) to also be used as
+ escape values indicating the presence of the old format.
- The value returned via bytes_read should be used to increment
- the relevant pointer after calling read_initial_length().
+ The value returned via bytes_read should be used to increment the
+ relevant pointer after calling read_initial_length().
As a side effect, this function sets the fields initial_length_size
and offset_size in cu_header to the values appropriate for the
length field. (The format of the initial length field determines
- the width of file offsets to be fetched later with fetch_offset().)
+ the width of file offsets to be fetched later with read_offset().)
[ Note: read_initial_length() and read_offset() are based on the
document entitled "DWARF Debugging Information Format", revision
This document is only a draft and is subject to change. (So beware.)
Details regarding the older, non-standard 64-bit format were
- determined empirically by examining 64-bit ELF files produced
- by the SGI toolchain on an IRIX 6.5 machine.
+ determined empirically by examining 64-bit ELF files produced by
+ the SGI toolchain on an IRIX 6.5 machine.
- Kevin, July 16, 2002
] */
read_initial_length (bfd *abfd, char *buf, struct comp_unit_head *cu_header,
int *bytes_read)
{
- LONGEST retval = 0;
-
- retval = bfd_get_32 (abfd, (bfd_byte *) buf);
+ LONGEST length = bfd_get_32 (abfd, (bfd_byte *) buf);
- if (retval == 0xffffffff)
+ if (length == 0xffffffff)
{
- retval = bfd_get_64 (abfd, (bfd_byte *) buf + 4);
+ length = bfd_get_64 (abfd, (bfd_byte *) buf + 4);
*bytes_read = 12;
- if (cu_header != NULL)
- {
- cu_header->initial_length_size = 12;
- cu_header->offset_size = 8;
- }
}
- else if (retval == 0)
+ else if (length == 0)
{
- /* Handle (non-standard) 64-bit DWARF2 formats such as that used
- by IRIX. */
- retval = bfd_get_64 (abfd, (bfd_byte *) buf);
+ /* Handle the (non-standard) 64-bit DWARF2 format used by IRIX. */
+ length = bfd_get_64 (abfd, (bfd_byte *) buf);
*bytes_read = 8;
- if (cu_header != NULL)
- {
- cu_header->initial_length_size = 8;
- cu_header->offset_size = 8;
- }
}
else
{
*bytes_read = 4;
- if (cu_header != NULL)
- {
- cu_header->initial_length_size = 4;
- cu_header->offset_size = 4;
- }
}
- return retval;
+ if (cu_header)
+ {
+ gdb_assert (cu_header->initial_length_size == 0
+ || cu_header->initial_length_size == 4
+ || cu_header->initial_length_size == 8
+ || cu_header->initial_length_size == 12);
+
+ if (cu_header->initial_length_size != 0
+ && cu_header->initial_length_size != *bytes_read)
+ complaint (&symfile_complaints,
+ _("intermixed 32-bit and 64-bit DWARF sections"));
+
+ cu_header->initial_length_size = *bytes_read;
+ cu_header->offset_size = (*bytes_read == 4) ? 4 : 8;
+ }
+
+ return length;
}
/* Read an offset from the data stream. The size of the offset is
- given by cu_header->offset_size. */
+ given by cu_header->offset_size. */
static LONGEST
read_offset (bfd *abfd, char *buf, const struct comp_unit_head *cu_header,
break;
default:
internal_error (__FILE__, __LINE__,
- "read_offset: bad switch [in module %s]",
+ _("read_offset: bad switch [in module %s]"),
bfd_get_filename (abfd));
}
- return retval;
+ return retval;
}
static char *
if (dwarf2_per_objfile->str_buffer == NULL)
{
- error ("DW_FORM_strp used without .debug_str section [in module %s]",
+ error (_("DW_FORM_strp used without .debug_str section [in module %s]"),
bfd_get_filename (abfd));
return NULL;
}
if (str_offset >= dwarf2_per_objfile->str_size)
{
- error ("DW_FORM_strp pointing outside of .debug_str section [in module %s]",
+ error (_("DW_FORM_strp pointing outside of .debug_str section [in module %s]"),
bfd_get_filename (abfd));
return NULL;
}
break;
case DW_LANG_Ada83:
case DW_LANG_Ada95:
+ cu->language = language_ada;
+ break;
case DW_LANG_Cobol74:
case DW_LANG_Cobol85:
case DW_LANG_Pascal83:
for (i = 0; i < die->num_attrs; ++i)
{
if (die->attrs[i].name == name)
- {
- return &die->attrs[i];
- }
+ return &die->attrs[i];
if (die->attrs[i].name == DW_AT_specification
|| die->attrs[i].name == DW_AT_abstract_origin)
spec = &die->attrs[i];
}
- if (spec)
- {
- struct die_info *ref_die =
- follow_die_ref (dwarf2_get_ref_die_offset (spec, cu));
- if (ref_die)
- return dwarf2_attr (ref_die, name, cu);
- }
+ if (spec)
+ return dwarf2_attr (follow_die_ref (die, spec, cu), name, cu);
return NULL;
}
if (spec_attr == NULL)
return NULL;
else
- return follow_die_ref (dwarf2_get_ref_die_offset (spec_attr, cu));
+ return follow_die_ref (die, spec_attr, cu);
}
/* Free the line_header structure *LH, and any arrays and strings it
if (dwarf2_per_objfile->line_buffer == NULL)
{
- complaint (&symfile_complaints, "missing .debug_line section");
+ complaint (&symfile_complaints, _("missing .debug_line section"));
return 0;
}
- /* Make sure that at least there's room for the total_length field. That
- could be 12 bytes long, but we're just going to fudge that. */
+ /* Make sure that at least there's room for the total_length field.
+ That could be 12 bytes long, but we're just going to fudge that. */
if (offset + 4 >= dwarf2_per_objfile->line_size)
{
dwarf2_statement_list_fits_in_line_number_section_complaint ();
line_ptr = dwarf2_per_objfile->line_buffer + offset;
- /* read in the header */
- lh->total_length = read_initial_length (abfd, line_ptr, NULL, &bytes_read);
+ /* Read in the header. */
+ lh->total_length =
+ read_initial_length (abfd, line_ptr, &cu->header, &bytes_read);
line_ptr += bytes_read;
if (line_ptr + lh->total_length > (dwarf2_per_objfile->line_buffer
+ dwarf2_per_objfile->line_size))
line_ptr += 1;
}
- /* Read directory table */
+ /* Read directory table. */
while ((cur_dir = read_string (abfd, line_ptr, &bytes_read)) != NULL)
{
line_ptr += bytes_read;
}
line_ptr += bytes_read;
- /* Read file name table */
+ /* Read file name table. */
while ((cur_file = read_string (abfd, line_ptr, &bytes_read)) != NULL)
{
unsigned int dir_index, mod_time, length;
if (line_ptr > (dwarf2_per_objfile->line_buffer
+ dwarf2_per_objfile->line_size))
complaint (&symfile_complaints,
- "line number info header doesn't fit in `.debug_line' section");
+ _("line number info header doesn't fit in `.debug_line' section"));
discard_cleanups (back_to);
return lh;
return address;
if (address != fn->lowpc)
complaint (&symfile_complaints,
- "misplaced first line number at 0x%lx for '%s'",
+ _("misplaced first line number at 0x%lx for '%s'"),
(unsigned long) address, fn->name);
fn->seen_line = 1;
return fn->lowpc;
are 1-based. */
struct file_entry *fe = &lh->file_names[file - 1];
char *dir;
+
if (fe->dir_index)
dir = lh->include_dirs[fe->dir_index - 1];
else
dwarf2_start_subfile (fe->name, dir);
}
- /* Decode the table. */
+ /* Decode the table. */
while (!end_sequence)
{
op_code = read_1_byte (abfd, line_ptr);
line_ptr += 1;
if (op_code >= lh->opcode_base)
- { /* Special operand. */
+ {
+ /* Special operand. */
adj_opcode = op_code - lh->opcode_base;
address += (adj_opcode / lh->line_range)
* lh->minimum_instruction_length;
line += lh->line_base + (adj_opcode % lh->line_range);
+ lh->file_names[file - 1].included_p = 1;
if (!decode_for_pst_p)
{
- /* append row to matrix using current values */
+ /* Append row to matrix using current values. */
record_line (current_subfile, line,
check_cu_functions (address, cu));
}
{
case DW_LNE_end_sequence:
end_sequence = 1;
+ lh->file_names[file - 1].included_p = 1;
if (!decode_for_pst_p)
record_line (current_subfile, 0, address);
break;
break;
default:
complaint (&symfile_complaints,
- "mangled .debug_line section");
+ _("mangled .debug_line section"));
return;
}
break;
case DW_LNS_copy:
+ lh->file_names[file - 1].included_p = 1;
if (!decode_for_pst_p)
record_line (current_subfile, line,
check_cu_functions (address, cu));
break;
case DW_LNS_set_file:
{
- /* lh->include_dirs and lh->file_names are 0-based,
- but the directory and file name numbers in the
- statement program are 1-based. */
+ /* The arrays lh->include_dirs and lh->file_names are
+ 0-based, but the directory and file name numbers in
+ the statement program are 1-based. */
struct file_entry *fe;
char *dir;
+
file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
fe = &lh->file_names[file - 1];
- fe->included_p = 1;
if (fe->dir_index)
dir = lh->include_dirs[fe->dir_index - 1];
else
break;
/* Add to the address register of the state machine the
address increment value corresponding to special opcode
- 255. Ie, this value is scaled by the minimum instruction
- length since special opcode 255 would have scaled the
- the increment. */
+ 255. I.e., this value is scaled by the minimum
+ instruction length since special opcode 255 would have
+ scaled the the increment. */
case DW_LNS_const_add_pc:
address += (lh->minimum_instruction_length
* ((255 - lh->opcode_base) / lh->line_range));
line_ptr += 2;
break;
default:
- { /* Unknown standard opcode, ignore it. */
+ {
+ /* Unknown standard opcode, ignore it. */
int i;
+
for (i = 0; i < lh->standard_opcode_lengths[op_code]; i++)
{
(void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
for (file_index = 0; file_index < lh->num_file_names; file_index++)
if (lh->file_names[file_index].included_p == 1)
{
- char *include_name = lh->file_names [file_index].name;
-
- if (strcmp (include_name, pst->filename) != 0)
+ const struct file_entry fe = lh->file_names [file_index];
+ char *include_name = fe.name;
+ char *dir_name = NULL;
+ char *pst_filename = pst->filename;
+
+ if (fe.dir_index)
+ dir_name = lh->include_dirs[fe.dir_index - 1];
+
+ if (!IS_ABSOLUTE_PATH (include_name) && dir_name != NULL)
+ {
+ include_name =
+ concat (dir_name, SLASH_STRING, include_name, NULL);
+ make_cleanup (xfree, include_name);
+ }
+
+ if (!IS_ABSOLUTE_PATH (pst_filename) && pst->dirname != NULL)
+ {
+ pst_filename =
+ concat (pst->dirname, SLASH_STRING, pst_filename, NULL);
+ make_cleanup (xfree, pst_filename);
+ }
+
+ if (strcmp (include_name, pst_filename) != 0)
dwarf2_create_include_psymtab (include_name, pst, objfile);
}
}
read_structure_type, and the correct name is saved in
the type. */
- if (cu->language == language_cplus)
+ if (cu->language == language_cplus
+ || cu->language == language_java)
{
struct type *type = SYMBOL_TYPE (sym);
}
{
- /* NOTE: carlton/2003-11-10: C++ class symbols shouldn't
+ /* NOTE: carlton/2003-11-10: C++ and Java class symbols shouldn't
really ever be static objects: otherwise, if you try
to, say, break of a class's method and you're in a file
which doesn't mention that class, it won't work unless
struct pending **list_to_add;
list_to_add = (cu->list_in_scope == &file_symbols
- && cu->language == language_cplus
+ && (cu->language == language_cplus
+ || cu->language == language_java)
? &global_symbols : cu->list_in_scope);
add_symbol_to_list (sym, list_to_add);
/* The semantics of C++ state that "struct foo { ... }" also
- defines a typedef for "foo". Synthesize a typedef symbol so
- that "ptype foo" works as expected. */
- if (cu->language == language_cplus)
+ defines a typedef for "foo". A Java class declaration also
+ defines a typedef for the class. Synthesize a typedef symbol
+ so that "ptype foo" works as expected. */
+ if (cu->language == language_cplus
+ || cu->language == language_java)
{
struct symbol *typedef_sym = (struct symbol *)
obstack_alloc (&objfile->objfile_obstack,
this objfile, so we don't need to duplicate it for
the type. */
if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0)
- TYPE_NAME (SYMBOL_TYPE (sym)) = SYMBOL_NATURAL_NAME (sym);
+ TYPE_NAME (SYMBOL_TYPE (sym)) = SYMBOL_SEARCH_NAME (sym);
add_symbol_to_list (typedef_sym, list_to_add);
}
}
if (processing_has_namespace_info
&& processing_current_prefix[0] != '\0')
{
- SYMBOL_LINKAGE_NAME (sym) = obconcat (&objfile->objfile_obstack,
- processing_current_prefix,
- "::",
- name);
+ SYMBOL_LINKAGE_NAME (sym) = typename_concat (&objfile->objfile_obstack,
+ processing_current_prefix,
+ name, cu);
}
SYMBOL_CLASS (sym) = LOC_TYPEDEF;
SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
if (processing_has_namespace_info
&& processing_current_prefix[0] != '\0')
{
- SYMBOL_LINKAGE_NAME (sym) = obconcat (&objfile->objfile_obstack,
- processing_current_prefix,
- "::",
- name);
+ SYMBOL_LINKAGE_NAME (sym) = typename_concat (&objfile->objfile_obstack,
+ processing_current_prefix,
+ name, cu);
}
attr = dwarf2_attr (die, DW_AT_const_value, cu);
if (attr)
struct pending **list_to_add;
list_to_add = (cu->list_in_scope == &file_symbols
- && cu->language == language_cplus
+ && (cu->language == language_cplus
+ || cu->language == language_java)
? &global_symbols : cu->list_in_scope);
add_symbol_to_list (sym, list_to_add);
trash data, but since we must specifically ignore things
we don't recognize, there is nothing else we should do at
this point. */
- complaint (&symfile_complaints, "unsupported tag: '%s'",
+ complaint (&symfile_complaints, _("unsupported tag: '%s'"),
dwarf_tag_name (die->tag));
break;
}
default:
complaint (&symfile_complaints,
- "unsupported const value attribute form: '%s'",
+ _("unsupported const value attribute form: '%s'"),
dwarf_form_name (attr->form));
SYMBOL_VALUE (sym) = 0;
SYMBOL_CLASS (sym) = LOC_CONST;
struct type *type;
struct attribute *type_attr;
struct die_info *type_die;
- unsigned int ref;
type_attr = dwarf2_attr (die, DW_AT_type, cu);
if (!type_attr)
return dwarf2_fundamental_type (cu->objfile, FT_VOID, cu);
}
else
- {
- ref = dwarf2_get_ref_die_offset (type_attr, cu);
- type_die = follow_die_ref (ref);
- if (!type_die)
- {
- error ("Dwarf Error: Cannot find referent at offset %d [in module %s]",
- ref, cu->objfile->name);
- return NULL;
- }
- }
+ type_die = follow_die_ref (die, type_attr, cu);
+
type = tag_type_to_type (type_die, cu);
if (!type)
{
dump_die (type_die);
- error ("Dwarf Error: Problem turning type die at offset into gdb type [in module %s]",
+ error (_("Dwarf Error: Problem turning type die at offset into gdb type [in module %s]"),
cu->objfile->name);
}
return type;
struct type *type = NULL;
struct attribute *type_attr;
struct die_info *type_die = NULL;
- unsigned int ref;
type_attr = dwarf2_attr (die, DW_AT_containing_type, cu);
if (type_attr)
{
- ref = dwarf2_get_ref_die_offset (type_attr, cu);
- type_die = follow_die_ref (ref);
- if (!type_die)
- {
- error ("Dwarf Error: Cannot find referent at offset %d [in module %s]", ref,
- cu->objfile->name);
- return NULL;
- }
+ type_die = follow_die_ref (die, type_attr, cu);
type = tag_type_to_type (type_die, cu);
}
if (!type)
{
if (type_die)
dump_die (type_die);
- error ("Dwarf Error: Problem turning containing type into gdb type [in module %s]",
+ error (_("Dwarf Error: Problem turning containing type into gdb type [in module %s]"),
cu->objfile->name);
}
return type;
}
-#if 0
-static struct type *
-type_at_offset (unsigned int offset, struct dwarf2_cu *cu)
-{
- struct die_info *die;
- struct type *type;
-
- die = follow_die_ref (offset);
- if (!die)
- {
- error ("Dwarf Error: Cannot find type referent at offset %d.", offset);
- return NULL;
- }
- type = tag_type_to_type (die, cu);
- return type;
-}
-#endif
-
static struct type *
tag_type_to_type (struct die_info *die, struct dwarf2_cu *cu)
{
if (!die->type)
{
dump_die (die);
- error ("Dwarf Error: Cannot find type of die [in module %s]",
+ error (_("Dwarf Error: Cannot find type of die [in module %s]"),
cu->objfile->name);
}
return die->type;
read_base_type (die, cu);
break;
default:
- complaint (&symfile_complaints, "unexepected tag in read_type_die: '%s'",
+ complaint (&symfile_complaints, _("unexepected tag in read_type_die: '%s'"),
dwarf_tag_name (die->tag));
break;
}
{
struct die_info *parent;
- if (cu->language != language_cplus)
+ if (cu->language != language_cplus
+ && cu->language != language_java)
return NULL;
parent = die->parent;
{
int dummy;
char *parent_prefix = determine_prefix (parent, cu);
- char *retval = typename_concat (parent_prefix,
+ char *retval = typename_concat (NULL, parent_prefix,
namespace_name (parent, &dummy,
- cu));
+ cu),
+ cu);
xfree (parent_prefix);
return retval;
}
}
}
-/* Return a newly-allocated string formed by concatenating PREFIX,
- "::", and SUFFIX, except that if PREFIX is NULL or the empty
- string, just return a copy of SUFFIX. */
+/* Return a newly-allocated string formed by concatenating PREFIX and
+ SUFFIX with appropriate separator. If PREFIX or SUFFIX is NULL or empty, then
+ simply copy the SUFFIX or PREFIX, respectively. If OBS is non-null,
+ perform an obconcat, otherwise allocate storage for the result. The CU argument
+ is used to determine the language and hence, the appropriate separator. */
+
+#define MAX_SEP_LEN 2 /* sizeof ("::") */
static char *
-typename_concat (const char *prefix, const char *suffix)
+typename_concat (struct obstack *obs, const char *prefix, const char *suffix,
+ struct dwarf2_cu *cu)
{
- if (prefix == NULL || prefix[0] == '\0')
- return xstrdup (suffix);
- else
- {
- char *retval = xmalloc (strlen (prefix) + 2 + strlen (suffix) + 1);
+ char *sep;
- strcpy (retval, prefix);
- strcat (retval, "::");
- strcat (retval, suffix);
+ if (suffix == NULL || suffix[0] == '\0' || prefix == NULL || prefix[0] == '\0')
+ sep = "";
+ else if (cu->language == language_java)
+ sep = ".";
+ else
+ sep = "::";
+ if (obs == NULL)
+ {
+ char *retval = xmalloc (strlen (prefix) + MAX_SEP_LEN + strlen (suffix) + 1);
+ retval[0] = '\0';
+
+ if (prefix)
+ {
+ strcpy (retval, prefix);
+ strcat (retval, sep);
+ }
+ if (suffix)
+ strcat (retval, suffix);
+
return retval;
}
+ else
+ {
+ /* We have an obstack. */
+ return obconcat (obs, prefix, sep, suffix);
+ }
}
static struct type *
dwarf2_extension (struct die_info *die, struct dwarf2_cu *cu)
{
struct attribute *attr;
- struct die_info *extension_die;
- unsigned int ref;
attr = dwarf2_attr (die, DW_AT_extension, cu);
if (attr == NULL)
return NULL;
- ref = dwarf2_get_ref_die_offset (attr, cu);
- extension_die = follow_die_ref (ref);
- if (!extension_die)
- {
- error ("Dwarf Error: Cannot find referent at offset %d.", ref);
- }
-
- return extension_die;
+ return follow_die_ref (die, attr, cu);
}
/* Convert a DIE tag into its string name. */
case DW_FORM_ref_addr:
case DW_FORM_addr:
fprintf_unfiltered (gdb_stderr, "address: ");
- print_address_numeric (DW_ADDR (&die->attrs[i]), 1, gdb_stderr);
+ deprecated_print_address_numeric (DW_ADDR (&die->attrs[i]), 1, gdb_stderr);
break;
case DW_FORM_block2:
case DW_FORM_block4:
case DW_FORM_block1:
fprintf_unfiltered (gdb_stderr, "block: size %d", DW_BLOCK (&die->attrs[i])->size);
break;
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ fprintf_unfiltered (gdb_stderr, "constant ref: %ld (adjusted)",
+ (long) (DW_ADDR (&die->attrs[i])));
+ break;
case DW_FORM_data1:
case DW_FORM_data2:
case DW_FORM_data4:
case DW_FORM_data8:
- case DW_FORM_ref1:
- case DW_FORM_ref2:
- case DW_FORM_ref4:
case DW_FORM_udata:
case DW_FORM_sdata:
fprintf_unfiltered (gdb_stderr, "constant: %ld", DW_UNSND (&die->attrs[i]));
}
static void
-store_in_ref_table (unsigned int offset, struct die_info *die)
+store_in_ref_table (unsigned int offset, struct die_info *die,
+ struct dwarf2_cu *cu)
{
int h;
struct die_info *old;
h = (offset % REF_HASH_SIZE);
- old = die_ref_table[h];
+ old = cu->die_ref_table[h];
die->next_ref = old;
- die_ref_table[h] = die;
-}
-
-
-static void
-dwarf2_empty_hash_tables (void)
-{
- memset (die_ref_table, 0, sizeof (die_ref_table));
+ cu->die_ref_table[h] = die;
}
static unsigned int
switch (attr->form)
{
case DW_FORM_ref_addr:
- result = DW_ADDR (attr);
- break;
case DW_FORM_ref1:
case DW_FORM_ref2:
case DW_FORM_ref4:
case DW_FORM_ref8:
case DW_FORM_ref_udata:
- result = cu->header.offset + DW_UNSND (attr);
+ result = DW_ADDR (attr);
break;
default:
complaint (&symfile_complaints,
- "unsupported die ref attribute form: '%s'",
+ _("unsupported die ref attribute form: '%s'"),
dwarf_form_name (attr->form));
}
return result;
return DW_UNSND (attr);
else
{
- complaint (&symfile_complaints, "Attribute value is not a constant (%s)",
+ complaint (&symfile_complaints, _("Attribute value is not a constant (%s)"),
dwarf_form_name (attr->form));
return default_value;
}
}
static struct die_info *
-follow_die_ref (unsigned int offset)
+follow_die_ref (struct die_info *src_die, struct attribute *attr,
+ struct dwarf2_cu *cu)
{
struct die_info *die;
+ unsigned int offset;
int h;
+ struct die_info temp_die;
+ struct dwarf2_cu *target_cu;
+
+ offset = dwarf2_get_ref_die_offset (attr, cu);
+
+ if (DW_ADDR (attr) < cu->header.offset
+ || DW_ADDR (attr) >= cu->header.offset + cu->header.length)
+ {
+ struct dwarf2_per_cu_data *per_cu;
+ per_cu = dwarf2_find_containing_comp_unit (DW_ADDR (attr),
+ cu->objfile);
+ target_cu = per_cu->cu;
+ }
+ else
+ target_cu = cu;
h = (offset % REF_HASH_SIZE);
- die = die_ref_table[h];
+ die = target_cu->die_ref_table[h];
while (die)
{
if (die->offset == offset)
- {
- return die;
- }
+ return die;
die = die->next_ref;
}
+
+ error (_("Dwarf Error: Cannot find DIE at 0x%lx referenced from DIE "
+ "at 0x%lx [in module %s]"),
+ (long) src_die->offset, (long) offset, cu->objfile->name);
+
return NULL;
}
{
if (typeid < 0 || typeid >= FT_NUM_MEMBERS)
{
- error ("Dwarf Error: internal error - invalid fundamental type id %d [in module %s]",
+ error (_("Dwarf Error: internal error - invalid fundamental type id %d [in module %s]"),
typeid, objfile->name);
}
break;
default:
- complaint (&symfile_complaints, "unsupported stack op: '%s'",
+ complaint (&symfile_complaints, _("unsupported stack op: '%s'"),
dwarf_stack_op_name (op));
return (stack[stacki]);
}
if (*p == ' ')
{
complaint (&symfile_complaints,
- "macro definition contains spaces in formal argument list:\n`%s'",
+ _("macro definition contains spaces in formal argument list:\n`%s'"),
body);
while (*p == ' ')
if (dwarf2_per_objfile->macinfo_buffer == NULL)
{
- complaint (&symfile_complaints, "missing .debug_macinfo section");
+ complaint (&symfile_complaints, _("missing .debug_macinfo section"));
return;
}
if (! current_file)
complaint (&symfile_complaints,
- "debug info gives macro %s outside of any file: %s",
+ _("debug info gives macro %s outside of any file: %s"),
macinfo_type ==
DW_MACINFO_define ? "definition" : macinfo_type ==
DW_MACINFO_undef ? "undefinition" :
case DW_MACINFO_end_file:
if (! current_file)
complaint (&symfile_complaints,
- "macro debug info has an unmatched `close_file' directive");
+ _("macro debug info has an unmatched `close_file' directive"));
else
{
current_file = current_file->included_by;
next_type = read_1_byte (abfd, mac_ptr);
if (next_type != 0)
complaint (&symfile_complaints,
- "no terminating 0-type entry for macros in `.debug_macinfo' section");
+ _("no terminating 0-type entry for macros in `.debug_macinfo' section"));
return;
}
baton->base_address = cu->header.base_address;
if (cu->header.base_known == 0)
complaint (&symfile_complaints,
- "Location list used without specifying the CU base address.");
+ _("Location list used without specifying the CU base address."));
SYMBOL_OPS (sym) = &dwarf2_loclist_funcs;
SYMBOL_LOCATION_BATON (sym) = baton;
}
}
+/* Locate the compilation unit from CU's objfile which contains the
+ DIE at OFFSET. Raises an error on failure. */
+
+static struct dwarf2_per_cu_data *
+dwarf2_find_containing_comp_unit (unsigned long offset,
+ struct objfile *objfile)
+{
+ struct dwarf2_per_cu_data *this_cu;
+ int low, high;
+
+ low = 0;
+ high = dwarf2_per_objfile->n_comp_units - 1;
+ while (high > low)
+ {
+ int mid = low + (high - low) / 2;
+ if (dwarf2_per_objfile->all_comp_units[mid]->offset >= offset)
+ high = mid;
+ else
+ low = mid + 1;
+ }
+ gdb_assert (low == high);
+ if (dwarf2_per_objfile->all_comp_units[low]->offset > offset)
+ {
+ if (low == 0)
+ error (_("Dwarf Error: could not find partial DIE containing "
+ "offset 0x%lx [in module %s]"),
+ (long) offset, bfd_get_filename (objfile->obfd));
+
+ gdb_assert (dwarf2_per_objfile->all_comp_units[low-1]->offset <= offset);
+ return dwarf2_per_objfile->all_comp_units[low-1];
+ }
+ else
+ {
+ this_cu = dwarf2_per_objfile->all_comp_units[low];
+ if (low == dwarf2_per_objfile->n_comp_units - 1
+ && offset >= this_cu->offset + this_cu->length)
+ error (_("invalid dwarf2 offset %ld"), offset);
+ gdb_assert (offset < this_cu->offset + this_cu->length);
+ return this_cu;
+ }
+}
+
+/* Locate the compilation unit from OBJFILE which is located at exactly
+ OFFSET. Raises an error on failure. */
+
+static struct dwarf2_per_cu_data *
+dwarf2_find_comp_unit (unsigned long offset, struct objfile *objfile)
+{
+ struct dwarf2_per_cu_data *this_cu;
+ this_cu = dwarf2_find_containing_comp_unit (offset, objfile);
+ if (this_cu->offset != offset)
+ error (_("no compilation unit with offset %ld."), offset);
+ return this_cu;
+}
+
+/* Release one cached compilation unit, CU. We unlink it from the tree
+ of compilation units, but we don't remove it from the read_in_chain;
+ the caller is responsible for that. */
+
+static void
+free_one_comp_unit (void *data)
+{
+ struct dwarf2_cu *cu = data;
+
+ if (cu->per_cu != NULL)
+ cu->per_cu->cu = NULL;
+ cu->per_cu = NULL;
+
+ obstack_free (&cu->comp_unit_obstack, NULL);
+ if (cu->dies)
+ free_die_list (cu->dies);
+
+ xfree (cu);
+}
+
/* This cleanup function is passed the address of a dwarf2_cu on the stack
- when we're finished with it. We can't free the pointer itself, but
- release any associated storage.
+ when we're finished with it. We can't free the pointer itself, but be
+ sure to unlink it from the cache. Also release any associated storage
+ and perform cache maintenance.
Only used during partial symbol parsing. */
obstack_free (&cu->comp_unit_obstack, NULL);
cu->partial_dies = NULL;
+
+ if (cu->per_cu != NULL)
+ {
+ /* This compilation unit is on the stack in our caller, so we
+ should not xfree it. Just unlink it. */
+ cu->per_cu->cu = NULL;
+ cu->per_cu = NULL;
+
+ /* If we had a per-cu pointer, then we may have other compilation
+ units loaded, so age them now. */
+ age_cached_comp_units ();
+ }
+}
+
+/* Free all cached compilation units. */
+
+static void
+free_cached_comp_units (void *data)
+{
+ struct dwarf2_per_cu_data *per_cu, **last_chain;
+
+ per_cu = dwarf2_per_objfile->read_in_chain;
+ last_chain = &dwarf2_per_objfile->read_in_chain;
+ while (per_cu != NULL)
+ {
+ struct dwarf2_per_cu_data *next_cu;
+
+ next_cu = per_cu->cu->read_in_chain;
+
+ free_one_comp_unit (per_cu->cu);
+ *last_chain = next_cu;
+
+ per_cu = next_cu;
+ }
+}
+
+/* Increase the age counter on each cached compilation unit, and free
+ any that are too old. */
+
+static void
+age_cached_comp_units (void)
+{
+ struct dwarf2_per_cu_data *per_cu, **last_chain;
+
+ dwarf2_clear_marks (dwarf2_per_objfile->read_in_chain);
+ per_cu = dwarf2_per_objfile->read_in_chain;
+ while (per_cu != NULL)
+ {
+ per_cu->cu->last_used ++;
+ if (per_cu->cu->last_used <= dwarf2_max_cache_age)
+ dwarf2_mark (per_cu->cu);
+ per_cu = per_cu->cu->read_in_chain;
+ }
+
+ per_cu = dwarf2_per_objfile->read_in_chain;
+ last_chain = &dwarf2_per_objfile->read_in_chain;
+ while (per_cu != NULL)
+ {
+ struct dwarf2_per_cu_data *next_cu;
+
+ next_cu = per_cu->cu->read_in_chain;
+
+ if (!per_cu->cu->mark)
+ {
+ free_one_comp_unit (per_cu->cu);
+ *last_chain = next_cu;
+ }
+ else
+ last_chain = &per_cu->cu->read_in_chain;
+
+ per_cu = next_cu;
+ }
+}
+
+/* Remove a single compilation unit from the cache. */
+
+static void
+free_one_cached_comp_unit (void *target_cu)
+{
+ struct dwarf2_per_cu_data *per_cu, **last_chain;
+
+ per_cu = dwarf2_per_objfile->read_in_chain;
+ last_chain = &dwarf2_per_objfile->read_in_chain;
+ while (per_cu != NULL)
+ {
+ struct dwarf2_per_cu_data *next_cu;
+
+ next_cu = per_cu->cu->read_in_chain;
+
+ if (per_cu->cu == target_cu)
+ {
+ free_one_comp_unit (per_cu->cu);
+ *last_chain = next_cu;
+ break;
+ }
+ else
+ last_chain = &per_cu->cu->read_in_chain;
+
+ per_cu = next_cu;
+ }
+}
+
+/* A pair of DIE offset and GDB type pointer. We store these
+ in a hash table separate from the DIEs, and preserve them
+ when the DIEs are flushed out of cache. */
+
+struct dwarf2_offset_and_type
+{
+ unsigned int offset;
+ struct type *type;
+};
+
+/* Hash function for a dwarf2_offset_and_type. */
+
+static hashval_t
+offset_and_type_hash (const void *item)
+{
+ const struct dwarf2_offset_and_type *ofs = item;
+ return ofs->offset;
+}
+
+/* Equality function for a dwarf2_offset_and_type. */
+
+static int
+offset_and_type_eq (const void *item_lhs, const void *item_rhs)
+{
+ const struct dwarf2_offset_and_type *ofs_lhs = item_lhs;
+ const struct dwarf2_offset_and_type *ofs_rhs = item_rhs;
+ return ofs_lhs->offset == ofs_rhs->offset;
+}
+
+/* Set the type associated with DIE to TYPE. Save it in CU's hash
+ table if necessary. */
+
+static void
+set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu)
+{
+ struct dwarf2_offset_and_type **slot, ofs;
+
+ die->type = type;
+
+ if (cu->per_cu == NULL)
+ return;
+
+ if (cu->per_cu->type_hash == NULL)
+ cu->per_cu->type_hash
+ = htab_create_alloc_ex (cu->header.length / 24,
+ offset_and_type_hash,
+ offset_and_type_eq,
+ NULL,
+ &cu->objfile->objfile_obstack,
+ hashtab_obstack_allocate,
+ dummy_obstack_deallocate);
+
+ ofs.offset = die->offset;
+ ofs.type = type;
+ slot = (struct dwarf2_offset_and_type **)
+ htab_find_slot_with_hash (cu->per_cu->type_hash, &ofs, ofs.offset, INSERT);
+ *slot = obstack_alloc (&cu->objfile->objfile_obstack, sizeof (**slot));
+ **slot = ofs;
+}
+
+/* Find the type for DIE in TYPE_HASH, or return NULL if DIE does not
+ have a saved type. */
+
+static struct type *
+get_die_type (struct die_info *die, htab_t type_hash)
+{
+ struct dwarf2_offset_and_type *slot, ofs;
+
+ ofs.offset = die->offset;
+ slot = htab_find_with_hash (type_hash, &ofs, ofs.offset);
+ if (slot)
+ return slot->type;
+ else
+ return NULL;
+}
+
+/* Restore the types of the DIE tree starting at START_DIE from the hash
+ table saved in CU. */
+
+static void
+reset_die_and_siblings_types (struct die_info *start_die, struct dwarf2_cu *cu)
+{
+ struct die_info *die;
+
+ if (cu->per_cu->type_hash == NULL)
+ return;
+
+ for (die = start_die; die != NULL; die = die->sibling)
+ {
+ die->type = get_die_type (die, cu->per_cu->type_hash);
+ if (die->child != NULL)
+ reset_die_and_siblings_types (die->child, cu);
+ }
+}
+
+/* Set the mark field in CU and in every other compilation unit in the
+ cache that we must keep because we are keeping CU. */
+
+/* Add a dependence relationship from CU to REF_PER_CU. */
+
+static void
+dwarf2_add_dependence (struct dwarf2_cu *cu,
+ struct dwarf2_per_cu_data *ref_per_cu)
+{
+ void **slot;
+
+ if (cu->dependencies == NULL)
+ cu->dependencies
+ = htab_create_alloc_ex (5, htab_hash_pointer, htab_eq_pointer,
+ NULL, &cu->comp_unit_obstack,
+ hashtab_obstack_allocate,
+ dummy_obstack_deallocate);
+
+ slot = htab_find_slot (cu->dependencies, ref_per_cu, INSERT);
+ if (*slot == NULL)
+ *slot = ref_per_cu;
+}
+
+/* Set the mark field in CU and in every other compilation unit in the
+ cache that we must keep because we are keeping CU. */
+
+static int
+dwarf2_mark_helper (void **slot, void *data)
+{
+ struct dwarf2_per_cu_data *per_cu;
+
+ per_cu = (struct dwarf2_per_cu_data *) *slot;
+ if (per_cu->cu->mark)
+ return 1;
+ per_cu->cu->mark = 1;
+
+ if (per_cu->cu->dependencies != NULL)
+ htab_traverse (per_cu->cu->dependencies, dwarf2_mark_helper, NULL);
+
+ return 1;
+}
+
+static void
+dwarf2_mark (struct dwarf2_cu *cu)
+{
+ if (cu->mark)
+ return;
+ cu->mark = 1;
+ if (cu->dependencies != NULL)
+ htab_traverse (cu->dependencies, dwarf2_mark_helper, NULL);
+}
+
+static void
+dwarf2_clear_marks (struct dwarf2_per_cu_data *per_cu)
+{
+ while (per_cu)
+ {
+ per_cu->cu->mark = 0;
+ per_cu = per_cu->cu->read_in_chain;
+ }
}
/* Allocation function for the libiberty hash table which uses an
return part_die_lhs->offset == part_die_rhs->offset;
}
+static struct cmd_list_element *set_dwarf2_cmdlist;
+static struct cmd_list_element *show_dwarf2_cmdlist;
+
+static void
+set_dwarf2_cmd (char *args, int from_tty)
+{
+ help_list (set_dwarf2_cmdlist, "maintenance set dwarf2 ", -1, gdb_stdout);
+}
+
+static void
+show_dwarf2_cmd (char *args, int from_tty)
+{
+ cmd_show_list (show_dwarf2_cmdlist, from_tty, "");
+}
+
void _initialize_dwarf2_read (void);
void
_initialize_dwarf2_read (void)
{
dwarf2_objfile_data_key = register_objfile_data ();
+
+ add_prefix_cmd ("dwarf2", class_maintenance, set_dwarf2_cmd, _("\
+Set DWARF 2 specific variables.\n\
+Configure DWARF 2 variables such as the cache size"),
+ &set_dwarf2_cmdlist, "maintenance set dwarf2 ",
+ 0/*allow-unknown*/, &maintenance_set_cmdlist);
+
+ add_prefix_cmd ("dwarf2", class_maintenance, show_dwarf2_cmd, _("\
+Show DWARF 2 specific variables\n\
+Show DWARF 2 variables such as the cache size"),
+ &show_dwarf2_cmdlist, "maintenance show dwarf2 ",
+ 0/*allow-unknown*/, &maintenance_show_cmdlist);
+
+ add_setshow_zinteger_cmd ("max-cache-age", class_obscure,
+ &dwarf2_max_cache_age, _("\
+Set the upper bound on the age of cached dwarf2 compilation units."), _("\
+Show the upper bound on the age of cached dwarf2 compilation units."), _("\
+A higher limit means that cached compilation units will be stored\n\
+in memory longer, and more total memory will be used. Zero disables\n\
+caching, which can slow down startup."),
+ NULL,
+ show_dwarf2_max_cache_age,
+ &set_dwarf2_cmdlist,
+ &show_dwarf2_cmdlist);
}