#include "exceptions.h"
#include "gdb_stat.h"
#include "completer.h"
+#include "vec.h"
+#include "c-lang.h"
+#include "valprint.h"
#include <fcntl.h>
#include "gdb_string.h"
#endif
#endif
+typedef struct symbol *symbolp;
+DEF_VEC_P (symbolp);
+
#if 0
/* .debug_info header for a compilation unit
Because of alignment constraints, this structure has padding and cannot
/* The number of compilation units in ALL_COMP_UNITS. */
int n_comp_units;
+ /* The number of .debug_types-related CUs. */
+ int n_type_comp_units;
+
+ /* The .debug_types-related CUs. */
+ struct dwarf2_per_cu_data **type_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;
/* The mapped index. */
struct mapped_index *index_table;
+
+ /* Set during partial symbol reading, to prevent queueing of full
+ symbols. */
+ int reading_partial_symbols;
};
static struct dwarf2_per_objfile *dwarf2_per_objfile;
/* Flag set if the DIE has a byte_size attribute. */
unsigned int has_byte_size : 1;
+ /* Flag set if any of the DIE's children are template arguments. */
+ unsigned int has_template_arguments : 1;
+
/* The name of this DIE. Normally the value of DW_AT_name, but
sometimes a default name for unnamed DIEs. */
char *name;
ENUM_BITFIELD(dwarf_tag) tag : 16;
/* Number of attributes */
- unsigned short num_attrs;
+ unsigned char num_attrs;
+
+ /* True if we're presently building the full type name for the
+ type derived from this DIE. */
+ unsigned char building_fullname : 1;
/* Abbrev number */
unsigned int abbrev;
static gdb_byte *read_n_bytes (bfd *, gdb_byte *, unsigned int);
-static char *read_string (bfd *, gdb_byte *, unsigned int *);
+static char *read_direct_string (bfd *, gdb_byte *, unsigned int *);
static char *read_indirect_string (bfd *, gdb_byte *,
const struct comp_unit_head *,
static struct symbol *new_symbol (struct die_info *, struct type *,
struct dwarf2_cu *);
+static struct symbol *new_symbol_full (struct die_info *, struct type *,
+ struct dwarf2_cu *, struct symbol *);
+
static void dwarf2_const_value (struct attribute *, struct symbol *,
struct dwarf2_cu *);
-static void dwarf2_const_value_data (struct attribute *attr,
- struct symbol *sym,
- int bits);
+static void dwarf2_const_value_attr (struct attribute *attr,
+ struct type *type,
+ const char *name,
+ struct obstack *obstack,
+ struct dwarf2_cu *cu, long *value,
+ gdb_byte **bytes,
+ struct dwarf2_locexpr_baton **baton);
static struct type *die_type (struct die_info *, struct dwarf2_cu *);
static char *dwarf2_name (struct die_info *die, struct dwarf2_cu *);
+static const char *dwarf2_full_name (char *name,
+ struct die_info *die,
+ struct dwarf2_cu *cu);
+
static struct die_info *dwarf2_extension (struct die_info *die,
struct dwarf2_cu **);
static void create_all_comp_units (struct objfile *);
+static int create_debug_types_hash_table (struct objfile *objfile);
+
static void load_full_comp_unit (struct dwarf2_per_cu_data *,
struct objfile *);
static void init_cu_die_reader (struct die_reader_specs *reader,
struct dwarf2_cu *cu);
+static htab_t allocate_signatured_type_hash_table (struct objfile *objfile);
+
#if WORDS_BIGENDIAN
/* Convert VALUE between big- and little-endian. */
return per_cu->v.quick->symtab;
}
+/* Return the CU given its index. */
+static struct dwarf2_per_cu_data *
+dw2_get_cu (int index)
+{
+ if (index >= dwarf2_per_objfile->n_comp_units)
+ {
+ index -= dwarf2_per_objfile->n_comp_units;
+ return dwarf2_per_objfile->type_comp_units[index];
+ }
+ return dwarf2_per_objfile->all_comp_units[index];
+}
+
/* A helper function that knows how to read a 64-bit value in a way
that doesn't make gdb die. Returns 1 if the conversion went ok, 0
otherwise. */
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, struct mapped_index *index,
- const gdb_byte *cu_list, offset_type cu_list_elements)
+create_cus_from_index (struct objfile *objfile, const gdb_byte *cu_list,
+ offset_type cu_list_elements)
{
offset_type i;
- const char *entry;
dwarf2_per_objfile->n_comp_units = cu_list_elements / 2;
dwarf2_per_objfile->all_comp_units
return 1;
}
+/* Create the signatured type hash table from the index. */
+static int
+create_signatured_type_hash_from_index (struct objfile *objfile,
+ const gdb_byte *bytes,
+ offset_type elements)
+{
+ offset_type i;
+ htab_t type_hash;
+
+ dwarf2_per_objfile->n_type_comp_units = elements / 3;
+ dwarf2_per_objfile->type_comp_units
+ = obstack_alloc (&objfile->objfile_obstack,
+ dwarf2_per_objfile->n_type_comp_units
+ * sizeof (struct dwarf2_per_cu_data *));
+
+ type_hash = allocate_signatured_type_hash_table (objfile);
+
+ for (i = 0; i < elements; i += 3)
+ {
+ struct signatured_type *type_sig;
+ ULONGEST offset, type_offset, signature;
+ void **slot;
+
+ if (!extract_cu_value (bytes, &offset)
+ || !extract_cu_value (bytes + 8, &type_offset))
+ return 0;
+ signature = extract_unsigned_integer (bytes + 16, 8, BFD_ENDIAN_LITTLE);
+ bytes += 3 * 8;
+
+ type_sig = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+ struct signatured_type);
+ type_sig->signature = signature;
+ type_sig->offset = offset;
+ type_sig->type_offset = type_offset;
+ type_sig->per_cu.from_debug_types = 1;
+ type_sig->per_cu.offset = offset;
+ type_sig->per_cu.objfile = objfile;
+ type_sig->per_cu.v.quick
+ = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+ struct dwarf2_per_cu_quick_data);
+
+ slot = htab_find_slot (type_hash, type_sig, INSERT);
+ *slot = type_sig;
+
+ dwarf2_per_objfile->type_comp_units[i / 3] = &type_sig->per_cu;
+ }
+
+ dwarf2_per_objfile->signatured_types = type_hash;
+
+ return 1;
+}
+
/* Read the address map data from the mapped index, and use it to
populate the objfile's psymtabs_addrmap. */
static void
iter += 4;
addrmap_set_empty (mutable_map, lo + baseaddr, hi + baseaddr - 1,
- dwarf2_per_objfile->all_comp_units[cu_index]);
+ dw2_get_cu (cu_index));
}
objfile->psymtabs_addrmap = addrmap_create_fixed (mutable_map,
struct mapped_index *map;
offset_type *metadata;
const gdb_byte *cu_list;
- offset_type cu_list_elements;
+ const gdb_byte *types_list = NULL;
+ offset_type version, cu_list_elements;
+ offset_type types_list_elements = 0;
+ int i;
if (dwarf2_per_objfile->gdb_index.asection == NULL
|| dwarf2_per_objfile->gdb_index.size == 0)
addr = dwarf2_per_objfile->gdb_index.buffer;
/* Version check. */
- if (MAYBE_SWAP (*(offset_type *) addr) != 1)
+ version = MAYBE_SWAP (*(offset_type *) addr);
+ if (version == 1)
+ {
+ /* Index version 1 neglected to account for .debug_types. So,
+ if we see .debug_types, we cannot use this index. */
+ if (dwarf2_per_objfile->types.asection != NULL
+ && dwarf2_per_objfile->types.size != 0)
+ return 0;
+ }
+ else if (version != 2)
return 0;
map = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct mapped_index);
map->total_size = dwarf2_per_objfile->gdb_index.size;
metadata = (offset_type *) (addr + sizeof (offset_type));
- cu_list = addr + MAYBE_SWAP (metadata[0]);
- cu_list_elements = ((MAYBE_SWAP (metadata[1]) - MAYBE_SWAP (metadata[0]))
+
+ i = 0;
+ cu_list = addr + MAYBE_SWAP (metadata[i]);
+ cu_list_elements = ((MAYBE_SWAP (metadata[i + 1]) - MAYBE_SWAP (metadata[i]))
/ 8);
- map->address_table = addr + MAYBE_SWAP (metadata[1]);
- map->address_table_size = (MAYBE_SWAP (metadata[2])
- - MAYBE_SWAP (metadata[1]));
- map->index_table = (offset_type *) (addr + MAYBE_SWAP (metadata[2]));
- map->index_table_slots = ((MAYBE_SWAP (metadata[3])
- - MAYBE_SWAP (metadata[2]))
+ ++i;
+
+ if (version == 2)
+ {
+ 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->address_table_size = (MAYBE_SWAP (metadata[i + 1])
+ - MAYBE_SWAP (metadata[i]));
+ ++i;
+
+ map->index_table = (offset_type *) (addr + MAYBE_SWAP (metadata[i]));
+ map->index_table_slots = ((MAYBE_SWAP (metadata[i + 1])
+ - MAYBE_SWAP (metadata[i]))
/ (2 * sizeof (offset_type)));
- map->constant_pool = addr + MAYBE_SWAP (metadata[3]);
+ ++i;
- if (!create_cus_from_index (objfile, map, cu_list, cu_list_elements))
+ map->constant_pool = addr + MAYBE_SWAP (metadata[i]);
+
+ if (!create_cus_from_index (objfile, cu_list, cu_list_elements))
+ return 0;
+
+ if (version == 2
+ && types_list_elements
+ && !create_signatured_type_hash_from_index (objfile, types_list,
+ types_list_elements))
return 0;
create_addrmap_from_index (objfile, map);
int index;
dw2_setup (objfile);
index = dwarf2_per_objfile->n_comp_units - 1;
- return dw2_instantiate_symtab (objfile,
- dwarf2_per_objfile->all_comp_units[index]);
+ return dw2_instantiate_symtab (objfile, dw2_get_cu (index));
}
static void
int i;
dw2_setup (objfile);
- for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ for (i = 0; i < (dwarf2_per_objfile->n_comp_units
+ + dwarf2_per_objfile->n_type_comp_units); ++i)
{
- struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
+ struct dwarf2_per_cu_data *cu = dw2_get_cu (i);
if (cu->v.quick->full_names)
{
struct dwarf2_per_cu_data *base_cu = NULL;
dw2_setup (objfile);
- for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ for (i = 0; i < (dwarf2_per_objfile->n_comp_units
+ + dwarf2_per_objfile->n_type_comp_units); ++i)
{
int j;
- struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
+ struct dwarf2_per_cu_data *cu = dw2_get_cu (i);
if (cu->v.quick->symtab)
continue;
for (i = 0; i < len; ++i)
{
offset_type cu_index = MAYBE_SWAP (vec[i + 1]);
- struct dwarf2_per_cu_data *cu;
- cu = dwarf2_per_objfile->all_comp_units[cu_index];
+ struct dwarf2_per_cu_data *cu = dw2_get_cu (cu_index);
+
dw2_instantiate_symtab (objfile, cu);
}
}
dw2_setup (objfile);
count = 0;
- for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ for (i = 0; i < (dwarf2_per_objfile->n_comp_units
+ + dwarf2_per_objfile->n_type_comp_units); ++i)
{
- struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
+ struct dwarf2_per_cu_data *cu = dw2_get_cu (i);
if (!cu->v.quick->symtab)
++count;
int i;
dw2_setup (objfile);
- for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+
+ for (i = 0; i < (dwarf2_per_objfile->n_comp_units
+ + dwarf2_per_objfile->n_type_comp_units); ++i)
{
- struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
+ struct dwarf2_per_cu_data *cu = dw2_get_cu (i);
dw2_instantiate_symtab (objfile, cu);
}
int i;
dw2_setup (objfile);
- for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ for (i = 0; i < (dwarf2_per_objfile->n_comp_units
+ + dwarf2_per_objfile->n_type_comp_units); ++i)
{
int j;
- struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
+ struct dwarf2_per_cu_data *cu = dw2_get_cu (i);
if (cu->v.quick->symtab)
continue;
should be rewritten so that it doesn't require a custom hook. It
could just use the ordinary symbol tables. */
/* vec[0] is the length, which must always be >0. */
- cu = dwarf2_per_objfile->all_comp_units[MAYBE_SWAP (vec[1])];
+ cu = dw2_get_cu (MAYBE_SWAP (vec[1]));
dw2_require_line_header (objfile, cu);
if (!cu->v.quick->lines)
if (!dwarf2_per_objfile->index_table)
return;
- for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ for (i = 0; i < (dwarf2_per_objfile->n_comp_units
+ + dwarf2_per_objfile->n_type_comp_units); ++i)
{
int j;
- struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
+ struct dwarf2_per_cu_data *cu = dw2_get_cu (i);
cu->v.quick->mark = 0;
if (cu->v.quick->symtab)
vec_len = MAYBE_SWAP (vec[0]);
for (vec_idx = 0; vec_idx < vec_len; ++vec_idx)
{
- struct dwarf2_per_cu_data *cu
- = dwarf2_per_objfile->all_comp_units[MAYBE_SWAP (vec[vec_idx + 1])];
+ struct dwarf2_per_cu_data *cu;
+
+ cu = dw2_get_cu (MAYBE_SWAP (vec[vec_idx + 1]));
if (cu->v.quick->mark)
dw2_instantiate_symtab (objfile, cu);
}
return NULL;
if (warn_if_readin && data->v.quick->symtab)
- warning (_("(Internal error: pc %s in read in CU, but not in symtab.)\n"),
+ warning (_("(Internal error: pc %s in read in CU, but not in symtab.)"),
paddress (get_objfile_arch (objfile), pc));
return dw2_instantiate_symtab (objfile, data);
int i;
dw2_setup (objfile);
- for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ for (i = 0; i < (dwarf2_per_objfile->n_comp_units
+ + dwarf2_per_objfile->n_type_comp_units); ++i)
{
int j;
- struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
+ struct dwarf2_per_cu_data *cu = dw2_get_cu (i);
if (cu->v.quick->symtab)
continue;
dwarf2_per_objfile->using_index = 1;
create_all_comp_units (objfile);
+ create_debug_types_hash_table (objfile);
- for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ for (i = 0; i < (dwarf2_per_objfile->n_comp_units
+ + dwarf2_per_objfile->n_type_comp_units); ++i)
{
- struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
+ struct dwarf2_per_cu_data *cu = dw2_get_cu (i);
cu->v.quick = OBSTACK_ZALLOC (&objfile->objfile_obstack,
struct dwarf2_per_cu_quick_data);
return lhs->signature == rhs->signature;
}
+/* Allocate a hash table for signatured types. */
+
+static htab_t
+allocate_signatured_type_hash_table (struct objfile *objfile)
+{
+ return htab_create_alloc_ex (41,
+ hash_type_signature,
+ eq_type_signature,
+ NULL,
+ &objfile->objfile_obstack,
+ hashtab_obstack_allocate,
+ dummy_obstack_deallocate);
+}
+
+/* A helper function to add a signatured type CU to a list. */
+
+static int
+add_signatured_type_cu_to_list (void **slot, void *datum)
+{
+ struct signatured_type *sigt = *slot;
+ struct dwarf2_per_cu_data ***datap = datum;
+
+ **datap = &sigt->per_cu;
+ ++*datap;
+
+ return 1;
+}
+
/* Create the hash table of all entries in the .debug_types section.
The result is zero if there is an error (e.g. missing .debug_types section),
otherwise non-zero. */
{
gdb_byte *info_ptr;
htab_t types_htab;
+ struct dwarf2_per_cu_data **iter;
dwarf2_read_section (objfile, &dwarf2_per_objfile->types);
info_ptr = dwarf2_per_objfile->types.buffer;
return 0;
}
- types_htab = htab_create_alloc_ex (41,
- hash_type_signature,
- eq_type_signature,
- NULL,
- &objfile->objfile_obstack,
- hashtab_obstack_allocate,
- dummy_obstack_deallocate);
+ types_htab = allocate_signatured_type_hash_table (objfile);
if (dwarf2_die_debug)
fprintf_unfiltered (gdb_stdlog, "Signatured types:\n");
type_sig->offset = offset;
type_sig->type_offset = type_offset;
type_sig->per_cu.objfile = objfile;
+ type_sig->per_cu.from_debug_types = 1;
slot = htab_find_slot (types_htab, type_sig, INSERT);
gdb_assert (slot != NULL);
dwarf2_per_objfile->signatured_types = types_htab;
+ dwarf2_per_objfile->n_type_comp_units = htab_elements (types_htab);
+ dwarf2_per_objfile->type_comp_units
+ = obstack_alloc (&objfile->objfile_obstack,
+ dwarf2_per_objfile->n_type_comp_units
+ * sizeof (struct dwarf2_per_cu_data *));
+ iter = &dwarf2_per_objfile->type_comp_units[0];
+ htab_traverse_noresize (types_htab, add_signatured_type_cu_to_list, &iter);
+ gdb_assert (iter - &dwarf2_per_objfile->type_comp_units[0]
+ == dwarf2_per_objfile->n_type_comp_units);
+
return 1;
}
struct dwarf2_per_cu_data *this_cu;
this_cu = &entry->per_cu;
- this_cu->from_debug_types = 1;
gdb_assert (dwarf2_per_objfile->types.readin);
process_psymtab_comp_unit (objfile, this_cu,
struct cleanup *back_to, *addrmap_cleanup;
struct obstack temp_obstack;
+ dwarf2_per_objfile->reading_partial_symbols = 1;
+
dwarf2_read_section (objfile, &dwarf2_per_objfile->info);
info_ptr = dwarf2_per_objfile->info.buffer;
gdb_byte *info_ptr, *beg_of_comp_unit;
struct die_info *comp_unit_die;
struct dwarf2_cu *cu;
- struct cleanup *back_to;
+ struct cleanup *free_abbrevs_cleanup, *free_cu_cleanup;
struct attribute *attr;
int has_children;
struct die_reader_specs reader_specs;
+ int read_cu = 0;
gdb_assert (! this_cu->from_debug_types);
info_ptr = dwarf2_per_objfile->info.buffer + this_cu->offset;
beg_of_comp_unit = info_ptr;
- cu = alloc_one_comp_unit (objfile);
+ if (this_cu->cu == NULL)
+ {
+ cu = alloc_one_comp_unit (objfile);
- /* ??? Missing cleanup for CU? */
+ read_cu = 1;
- /* Link this compilation unit into the compilation unit tree. */
- this_cu->cu = cu;
- cu->per_cu = this_cu;
- cu->type_hash = this_cu->type_hash;
+ /* If an error occurs while loading, release our storage. */
+ free_cu_cleanup = make_cleanup (free_one_comp_unit, cu);
- info_ptr = partial_read_comp_unit_head (&cu->header, info_ptr,
- dwarf2_per_objfile->info.buffer,
- dwarf2_per_objfile->info.size,
- abfd);
+ info_ptr = partial_read_comp_unit_head (&cu->header, info_ptr,
+ dwarf2_per_objfile->info.buffer,
+ dwarf2_per_objfile->info.size,
+ abfd);
- /* Complete the cu_header. */
- cu->header.offset = this_cu->offset;
- cu->header.first_die_offset = info_ptr - beg_of_comp_unit;
+ /* Complete the cu_header. */
+ cu->header.offset = this_cu->offset;
+ cu->header.first_die_offset = info_ptr - beg_of_comp_unit;
+
+ /* Link this compilation unit into the compilation unit tree. */
+ this_cu->cu = cu;
+ cu->per_cu = this_cu;
+ cu->type_hash = this_cu->type_hash;
+
+ /* Link this CU into read_in_chain. */
+ this_cu->cu->read_in_chain = dwarf2_per_objfile->read_in_chain;
+ dwarf2_per_objfile->read_in_chain = this_cu;
+ }
+ else
+ {
+ cu = this_cu->cu;
+ info_ptr += cu->header.first_die_offset;
+ }
/* Read the abbrevs for this compilation unit into a table. */
+ gdb_assert (cu->dwarf2_abbrevs == NULL);
dwarf2_read_abbrevs (abfd, cu);
- back_to = make_cleanup (dwarf2_free_abbrev_table, cu);
+ free_abbrevs_cleanup = make_cleanup (dwarf2_free_abbrev_table, cu);
/* Read the compilation unit die. */
init_cu_die_reader (&reader_specs, cu);
if (has_children)
load_partial_dies (abfd, dwarf2_per_objfile->info.buffer, info_ptr, 0, cu);
- do_cleanups (back_to);
+ do_cleanups (free_abbrevs_cleanup);
+
+ if (read_cu)
+ {
+ /* We've successfully allocated this compilation unit. Let our
+ caller clean it up when finished with it. */
+ discard_cleanups (free_cu_cleanup);
+ }
}
/* Create a list of all compilation units in OBJFILE. We do this only
{
char *parent_scope;
+ /* If this is a template instantiation, we can not work out the
+ template arguments from partial DIEs. So, unfortunately, we have
+ to go through the full DIEs. At least any work we do building
+ types here will be reused if full symbols are loaded later. */
+ if (pdi->has_template_arguments)
+ {
+ fixup_partial_die (pdi, cu);
+
+ if (pdi->name != NULL && strchr (pdi->name, '<') == NULL)
+ {
+ struct die_info *die;
+ struct attribute attr;
+ struct dwarf2_cu *ref_cu = cu;
+
+ attr.name = 0;
+ attr.form = DW_FORM_ref_addr;
+ attr.u.addr = pdi->offset;
+ die = follow_die_ref (NULL, &attr, &ref_cu);
+
+ return xstrdup (dwarf2_full_name (NULL, die, ref_cu));
+ }
+ }
+
parent_scope = partial_die_parent_scope (pdi, cu);
if (parent_scope == NULL)
return NULL;
}
break;
case DW_TAG_variable:
- if (pdi->is_external)
+ if (pdi->locdesc)
+ addr = decode_locdesc (pdi->locdesc, cu);
+
+ if (pdi->locdesc
+ && addr == 0
+ && !dwarf2_per_objfile->has_section_at_zero)
+ {
+ /* A global or static variable may also have been stripped
+ out by the linker if unused, in which case its address
+ will be nullified; do not add such variables into partial
+ symbol table then. */
+ }
+ else if (pdi->is_external)
{
/* Global Variable.
Don't enter into the minimal symbol tables as there is
used by GDB, but it comes in handy for debugging partial symbol
table building. */
- if (pdi->locdesc)
- addr = decode_locdesc (pdi->locdesc, cu);
if (pdi->locdesc || pdi->has_type)
psym = add_psymbol_to_list (actual_name, strlen (actual_name),
built_actual_name,
xfree (actual_name);
return;
}
- addr = decode_locdesc (pdi->locdesc, cu);
/*prim_record_minimal_symbol (actual_name, addr + baseaddr,
mst_file_data, objfile); */
psym = add_psymbol_to_list (actual_name, strlen (actual_name),
info_ptr += 8;
break;
case DW_FORM_string:
- read_string (abfd, info_ptr, &bytes_read);
+ read_direct_string (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
break;
case DW_FORM_sec_offset:
= dpo_backlink->has_section_at_zero;
}
+ dwarf2_per_objfile->reading_partial_symbols = 0;
+
psymtab_to_symtab_1 (pst);
/* Finish up the debug error message. */
struct dwarf2_cu *cu;
unsigned int offset;
gdb_byte *info_ptr, *beg_of_comp_unit;
- struct cleanup *back_to, *free_cu_cleanup;
+ struct cleanup *free_abbrevs_cleanup = NULL, *free_cu_cleanup = NULL;
struct attribute *attr;
+ int read_cu = 0;
gdb_assert (! per_cu->from_debug_types);
info_ptr = dwarf2_per_objfile->info.buffer + offset;
beg_of_comp_unit = info_ptr;
- cu = alloc_one_comp_unit (objfile);
+ if (per_cu->cu == NULL)
+ {
+ cu = alloc_one_comp_unit (objfile);
- /* If an error occurs while loading, release our storage. */
- free_cu_cleanup = make_cleanup (free_one_comp_unit, cu);
+ read_cu = 1;
- /* Read in the comp_unit header. */
- info_ptr = read_comp_unit_head (&cu->header, info_ptr, abfd);
+ /* If an error occurs while loading, release our storage. */
+ free_cu_cleanup = make_cleanup (free_one_comp_unit, cu);
- /* Complete the cu_header. */
- cu->header.offset = offset;
- cu->header.first_die_offset = info_ptr - beg_of_comp_unit;
+ /* Read in the comp_unit header. */
+ info_ptr = read_comp_unit_head (&cu->header, info_ptr, abfd);
- /* Read the abbrevs for this compilation unit. */
- dwarf2_read_abbrevs (abfd, cu);
- back_to = make_cleanup (dwarf2_free_abbrev_table, cu);
+ /* Complete the cu_header. */
+ cu->header.offset = offset;
+ cu->header.first_die_offset = info_ptr - beg_of_comp_unit;
+
+ /* Read the abbrevs for this compilation unit. */
+ dwarf2_read_abbrevs (abfd, cu);
+ free_abbrevs_cleanup = make_cleanup (dwarf2_free_abbrev_table, cu);
- /* Link this compilation unit into the compilation unit tree. */
- per_cu->cu = cu;
- cu->per_cu = per_cu;
- cu->type_hash = per_cu->type_hash;
+ /* Link this compilation unit into the compilation unit tree. */
+ per_cu->cu = cu;
+ cu->per_cu = per_cu;
+ cu->type_hash = per_cu->type_hash;
+
+ /* Link this CU into read_in_chain. */
+ per_cu->cu->read_in_chain = dwarf2_per_objfile->read_in_chain;
+ dwarf2_per_objfile->read_in_chain = per_cu;
+ }
+ else
+ {
+ cu = per_cu->cu;
+ info_ptr += cu->header.first_die_offset;
+ }
cu->dies = read_comp_unit (info_ptr, cu);
if (attr)
cu->producer = DW_STRING (attr);
- /* Link this CU into read_in_chain. */
- per_cu->cu->read_in_chain = dwarf2_per_objfile->read_in_chain;
- dwarf2_per_objfile->read_in_chain = per_cu;
-
- do_cleanups (back_to);
+ if (read_cu)
+ {
+ do_cleanups (free_abbrevs_cleanup);
- /* We've successfully allocated this compilation unit. Let our caller
- clean it up when finished with it. */
- discard_cleanups (free_cu_cleanup);
+ /* We've successfully allocated this compilation unit. Let our
+ caller clean it up when finished with it. */
+ discard_cleanups (free_cu_cleanup);
+ }
}
/* Generate full symbol information for PST and CU, whose DIEs have
}
}
+/* Retrieve the last character from a mem_file. */
+
+static void
+do_ui_file_peek_last (void *object, const char *buffer, long length)
+{
+ char *last_char_p = (char *) object;
+
+ if (length > 0)
+ *last_char_p = buffer[length - 1];
+}
+
/* Compute the fully qualified name of DIE in CU. If PHYSNAME is nonzero,
compute the physname for the object, which include a method's
formal parameters (C++/Java) and return type (Java).
else
fputs_unfiltered (name ? name : "", buf);
+ /* Template parameters may be specified in the DIE's DW_AT_name, or
+ as children with DW_TAG_template_type_param or
+ DW_TAG_value_type_param. If the latter, add them to the name
+ here. If the name already has template parameters, then
+ skip this step; some versions of GCC emit both, and
+ it is more efficient to use the pre-computed name.
+
+ Something to keep in mind about this process: it is very
+ unlikely, or in some cases downright impossible, to produce
+ something that will match the mangled name of a function.
+ If the definition of the function has the same debug info,
+ we should be able to match up with it anyway. But fallbacks
+ using the minimal symbol, for instance to find a method
+ implemented in a stripped copy of libstdc++, will not work.
+ If we do not have debug info for the definition, we will have to
+ match them up some other way.
+
+ When we do name matching there is a related problem with function
+ templates; two instantiated function templates are allowed to
+ differ only by their return types, which we do not add here. */
+
+ if (cu->language == language_cplus && strchr (name, '<') == NULL)
+ {
+ struct attribute *attr;
+ struct die_info *child;
+ int first = 1;
+
+ die->building_fullname = 1;
+
+ for (child = die->child; child != NULL; child = child->sibling)
+ {
+ struct type *type;
+ long value;
+ gdb_byte *bytes;
+ struct dwarf2_locexpr_baton *baton;
+ struct value *v;
+
+ if (child->tag != DW_TAG_template_type_param
+ && child->tag != DW_TAG_template_value_param)
+ continue;
+
+ if (first)
+ {
+ fputs_unfiltered ("<", buf);
+ first = 0;
+ }
+ else
+ fputs_unfiltered (", ", buf);
+
+ attr = dwarf2_attr (child, DW_AT_type, cu);
+ if (attr == NULL)
+ {
+ complaint (&symfile_complaints,
+ _("template parameter missing DW_AT_type"));
+ fputs_unfiltered ("UNKNOWN_TYPE", buf);
+ continue;
+ }
+ type = die_type (child, cu);
+
+ if (child->tag == DW_TAG_template_type_param)
+ {
+ c_print_type (type, "", buf, -1, 0);
+ continue;
+ }
+
+ attr = dwarf2_attr (child, DW_AT_const_value, cu);
+ if (attr == NULL)
+ {
+ complaint (&symfile_complaints,
+ _("template parameter missing DW_AT_const_value"));
+ fputs_unfiltered ("UNKNOWN_VALUE", buf);
+ continue;
+ }
+
+ dwarf2_const_value_attr (attr, type, name,
+ &cu->comp_unit_obstack, cu,
+ &value, &bytes, &baton);
+
+ if (TYPE_NOSIGN (type))
+ /* GDB prints characters as NUMBER 'CHAR'. If that's
+ changed, this can use value_print instead. */
+ c_printchar (value, type, buf);
+ else
+ {
+ struct value_print_options opts;
+
+ if (baton != NULL)
+ v = dwarf2_evaluate_loc_desc (type, NULL,
+ baton->data,
+ baton->size,
+ baton->per_cu);
+ else if (bytes != NULL)
+ {
+ v = allocate_value (type);
+ memcpy (value_contents_writeable (v), bytes,
+ TYPE_LENGTH (type));
+ }
+ else
+ v = value_from_longest (type, value);
+
+ /* Specify decimal so that we do not depend on the radix. */
+ get_formatted_print_options (&opts, 'd');
+ opts.raw = 1;
+ value_print (v, buf, &opts);
+ release_value (v);
+ value_free (v);
+ }
+ }
+
+ die->building_fullname = 0;
+
+ if (!first)
+ {
+ /* Close the argument list, with a space if necessary
+ (nested templates). */
+ char last_char = '\0';
+ ui_file_put (buf, do_ui_file_peek_last, &last_char);
+ if (last_char == '>')
+ fputs_unfiltered (" >", buf);
+ else
+ fputs_unfiltered (">", buf);
+ }
+ }
+
/* For Java and C++ methods, append formal parameter type
information, if PHYSNAME. */
CORE_ADDR baseaddr;
struct block *block;
int inlined_func = (die->tag == DW_TAG_inlined_subroutine);
+ VEC (symbolp) *template_args = NULL;
+ struct template_symbol *templ_func = NULL;
if (inlined_func)
{
/* Record the function range for dwarf_decode_lines. */
add_to_cu_func_list (name, lowpc, highpc, cu);
+ /* If we have any template arguments, then we must allocate a
+ different sort of symbol. */
+ for (child_die = die->child; child_die; child_die = sibling_die (child_die))
+ {
+ if (child_die->tag == DW_TAG_template_type_param
+ || child_die->tag == DW_TAG_template_value_param)
+ {
+ templ_func = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+ struct template_symbol);
+ templ_func->base.is_cplus_template_function = 1;
+ break;
+ }
+ }
+
new = push_context (0, lowpc);
- new->name = new_symbol (die, read_type_die (die, cu), cu);
+ new->name = new_symbol_full (die, read_type_die (die, cu), cu,
+ (struct symbol *) templ_func);
/* If there is a location expression for DW_AT_frame_base, record
it. */
child_die = die->child;
while (child_die && child_die->tag)
{
- process_die (child_die, cu);
+ if (child_die->tag == DW_TAG_template_type_param
+ || child_die->tag == DW_TAG_template_value_param)
+ {
+ struct symbol *arg = new_symbol (child_die, NULL, cu);
+
+ VEC_safe_push (symbolp, template_args, arg);
+ }
+ else
+ process_die (child_die, cu);
child_die = sibling_die (child_die);
}
}
/* If we have address ranges, record them. */
dwarf2_record_block_ranges (die, block, baseaddr, cu);
+ /* Attach template arguments to function. */
+ if (! VEC_empty (symbolp, template_args))
+ {
+ gdb_assert (templ_func != NULL);
+
+ templ_func->n_template_arguments = VEC_length (symbolp, template_args);
+ templ_func->template_arguments
+ = obstack_alloc (&objfile->objfile_obstack,
+ (templ_func->n_template_arguments
+ * sizeof (struct symbol *)));
+ memcpy (templ_func->template_arguments,
+ VEC_address (symbolp, template_args),
+ (templ_func->n_template_arguments * sizeof (struct symbol *)));
+ VEC_free (symbolp, template_args);
+ }
+
/* In C++, we can have functions nested inside functions (e.g., when
a function declares a class that has methods). This means that
when we finish processing a function scope, we may need to go
{
struct field_info fi;
struct die_info *child_die;
+ VEC (symbolp) *template_args = NULL;
memset (&fi, 0, sizeof (struct field_info));
}
else if (child_die->tag == DW_TAG_typedef)
dwarf2_add_typedef (&fi, child_die, cu);
+ else if (child_die->tag == DW_TAG_template_type_param
+ || child_die->tag == DW_TAG_template_value_param)
+ {
+ struct symbol *arg = new_symbol (child_die, NULL, cu);
+
+ VEC_safe_push (symbolp, template_args, arg);
+ }
+
child_die = sibling_die (child_die);
}
+ /* Attach template arguments to type. */
+ if (! VEC_empty (symbolp, template_args))
+ {
+ ALLOCATE_CPLUS_STRUCT_TYPE (type);
+ TYPE_N_TEMPLATE_ARGUMENTS (type)
+ = VEC_length (symbolp, template_args);
+ TYPE_TEMPLATE_ARGUMENTS (type)
+ = obstack_alloc (&objfile->objfile_obstack,
+ (TYPE_N_TEMPLATE_ARGUMENTS (type)
+ * sizeof (struct symbol *)));
+ memcpy (TYPE_TEMPLATE_ARGUMENTS (type),
+ VEC_address (symbolp, template_args),
+ (TYPE_N_TEMPLATE_ARGUMENTS (type)
+ * sizeof (struct symbol *)));
+ VEC_free (symbolp, template_args);
+ }
+
/* Attach fields and member functions to the type. */
if (fi.nfields)
dwarf2_attach_fields_to_type (&fi, type, cu);
{
if (child_die->tag == DW_TAG_member
|| child_die->tag == DW_TAG_variable
- || child_die->tag == DW_TAG_inheritance)
+ || child_die->tag == DW_TAG_inheritance
+ || child_die->tag == DW_TAG_template_value_param
+ || child_die->tag == DW_TAG_template_type_param)
{
/* Do nothing. */
}
{
if (child_die->tag == DW_TAG_formal_parameter)
{
- /* Dwarf2 has no clean way to discern C++ static and non-static
- member functions. G++ helps GDB by marking the first
- parameter for non-static member functions (which is the
- this pointer) as artificial. We pass this information
- to dwarf2_add_member_fn via TYPE_FIELD_ARTIFICIAL. */
+ struct type *arg_type;
+
+ /* DWARF version 2 has no clean way to discern C++
+ static and non-static member functions. G++ helps
+ GDB by marking the first parameter for non-static
+ member functions (which is the this pointer) as
+ artificial. We pass this information to
+ dwarf2_add_member_fn via TYPE_FIELD_ARTIFICIAL.
+
+ DWARF version 3 added DW_AT_object_pointer, which GCC
+ 4.5 does not yet generate. */
attr = dwarf2_attr (child_die, DW_AT_artificial, cu);
if (attr)
TYPE_FIELD_ARTIFICIAL (ftype, iparams) = DW_UNSND (attr);
TYPE_FIELD_ARTIFICIAL (ftype, iparams) = 1;
}
}
- TYPE_FIELD_TYPE (ftype, iparams) = die_type (child_die, cu);
+ arg_type = die_type (child_die, cu);
+
+ /* RealView does not mark THIS as const, which the testsuite
+ expects. GCC marks THIS as const in method definitions,
+ but not in the class specifications (GCC PR 43053). */
+ if (cu->language == language_cplus && !TYPE_CONST (arg_type)
+ && TYPE_FIELD_ARTIFICIAL (ftype, iparams))
+ {
+ int is_this = 0;
+ struct dwarf2_cu *arg_cu = cu;
+ const char *name = dwarf2_name (child_die, cu);
+
+ attr = dwarf2_attr (die, DW_AT_object_pointer, cu);
+ if (attr)
+ {
+ /* If the compiler emits this, use it. */
+ if (follow_die_ref (die, attr, &arg_cu) == child_die)
+ is_this = 1;
+ }
+ else if (name && strcmp (name, "this") == 0)
+ /* Function definitions will have the argument names. */
+ is_this = 1;
+ else if (name == NULL && iparams == 0)
+ /* Declarations may not have the names, so like
+ elsewhere in GDB, assume an artificial first
+ argument is "this". */
+ is_this = 1;
+
+ if (is_this)
+ arg_type = make_cv_type (1, TYPE_VOLATILE (arg_type),
+ arg_type, 0);
+ }
+
+ TYPE_FIELD_TYPE (ftype, iparams) = arg_type;
iparams++;
}
child_die = sibling_die (child_die);
read_comp_unit (gdb_byte *info_ptr, struct dwarf2_cu *cu)
{
struct die_reader_specs reader_specs;
+ int read_abbrevs = 0;
+ struct cleanup *back_to;
+ struct die_info *die;
+
+ if (cu->dwarf2_abbrevs == NULL)
+ {
+ dwarf2_read_abbrevs (cu->objfile->obfd, cu);
+ back_to = make_cleanup (dwarf2_free_abbrev_table, cu);
+ read_abbrevs = 1;
+ }
gdb_assert (cu->die_hash == NULL);
cu->die_hash
init_cu_die_reader (&reader_specs, cu);
- return read_die_and_children (&reader_specs, info_ptr, &info_ptr, NULL);
+ die = read_die_and_children (&reader_specs, info_ptr, &info_ptr, NULL);
+
+ if (read_abbrevs)
+ do_cleanups (back_to);
+
+ return die;
}
/* Main entry point for reading a DIE and all children.
continue;
}
+ /* Check for template arguments. We never save these; if
+ they're seen, we just mark the parent, and go on our way. */
+ if (parent_die != NULL
+ && cu->language == language_cplus
+ && (abbrev->tag == DW_TAG_template_type_param
+ || abbrev->tag == DW_TAG_template_value_param))
+ {
+ parent_die->has_template_arguments = 1;
+
+ if (!load_all)
+ {
+ /* We don't need a partial DIE for the template argument. */
+ info_ptr = skip_one_die (buffer, info_ptr + bytes_read, abbrev,
+ cu);
+ continue;
+ }
+ }
+
+ /* We only recurse into subprograms looking for template arguments.
+ Skip their other children. */
+ if (!load_all
+ && cu->language == language_cplus
+ && parent_die != NULL
+ && parent_die->tag == DW_TAG_subprogram)
+ {
+ info_ptr = skip_one_die (buffer, info_ptr + bytes_read, abbrev, cu);
+ continue;
+ }
+
/* Check whether this DIE is interesting enough to save. Normally
we would not be interested in members here, but there may be
later variables referencing them via DW_AT_specification (for
/* For some DIEs we want to follow their children (if any). For C
we have no reason to follow the children of structures; for other
- languages we have to, both so that we can get at method physnames
- to infer fully qualified class names, and for DW_AT_specification.
+ languages we have to, so that we can get at method physnames
+ to infer fully qualified class names, for DW_AT_specification,
+ and for C++ template arguments. For C++, we also look one level
+ inside functions to find template arguments (if the name of the
+ function does not already contain the template arguments).
For Ada, we need to scan the children of subprograms and lexical
blocks as well because Ada allows the definition of nested
|| last_die->tag == DW_TAG_namespace
|| last_die->tag == DW_TAG_module
|| last_die->tag == DW_TAG_enumeration_type
+ || (cu->language == language_cplus
+ && last_die->tag == DW_TAG_subprogram
+ && (last_die->name == NULL
+ || strchr (last_die->name, '<') == NULL))
|| (cu->language != language_c
&& (last_die->tag == DW_TAG_class_type
|| last_die->tag == DW_TAG_interface_type
per_cu = dwarf2_find_containing_comp_unit (offset, cu->objfile);
- if (per_cu->cu == NULL)
- {
- load_partial_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;
- }
+ if (per_cu->cu == NULL || per_cu->cu->partial_dies == NULL)
+ load_partial_comp_unit (per_cu, cu->objfile);
per_cu->cu->last_used = 0;
pd = find_partial_die_in_comp_unit (offset, per_cu->cu);
info_ptr += bytes_read;
break;
case DW_FORM_string:
- DW_STRING (attr) = read_string (abfd, info_ptr, &bytes_read);
+ DW_STRING (attr) = read_direct_string (abfd, info_ptr, &bytes_read);
DW_STRING_IS_CANONICAL (attr) = 0;
info_ptr += bytes_read;
break;
}
static char *
-read_string (bfd *abfd, gdb_byte *buf, unsigned int *bytes_read_ptr)
+read_direct_string (bfd *abfd, gdb_byte *buf, unsigned int *bytes_read_ptr)
{
/* If the size of a host char is 8 bits, we can return a pointer
to the string, otherwise we have to copy the string to a buffer
}
/* Read directory table. */
- while ((cur_dir = read_string (abfd, line_ptr, &bytes_read)) != NULL)
+ while ((cur_dir = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL)
{
line_ptr += bytes_read;
add_include_dir (lh, cur_dir);
line_ptr += bytes_read;
/* Read file name table. */
- while ((cur_file = read_string (abfd, line_ptr, &bytes_read)) != NULL)
+ while ((cur_file = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL)
{
unsigned int dir_index, mod_time, length;
char *cur_file;
unsigned int dir_index, mod_time, length;
- cur_file = read_string (abfd, line_ptr, &bytes_read);
+ cur_file = read_direct_string (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
dir_index =
read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
to make a symbol table entry for it, and if so, create a new entry
and return a pointer to it.
If TYPE is NULL, determine symbol type from the die, otherwise
- used the passed type. */
+ used the passed type.
+ If SPACE is not NULL, use it to hold the new symbol. If it is
+ NULL, allocate a new symbol on the objfile's obstack. */
static struct symbol *
-new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu)
+new_symbol_full (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
+ struct symbol *space)
{
struct objfile *objfile = cu->objfile;
struct symbol *sym = NULL;
struct attribute *attr = NULL;
struct attribute *attr2 = NULL;
CORE_ADDR baseaddr;
+ struct pending **list_to_add = NULL;
+
int inlined_func = (die->tag == DW_TAG_inlined_subroutine);
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
if (name)
{
const char *linkagename;
+ int suppress_add = 0;
- sym = (struct symbol *) obstack_alloc (&objfile->objfile_obstack,
- sizeof (struct symbol));
+ if (space)
+ sym = space;
+ else
+ sym = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct symbol);
OBJSTAT (objfile, n_syms++);
- memset (sym, 0, sizeof (struct symbol));
/* Cache this symbol's name and the name's demangled form (if any). */
- SYMBOL_LANGUAGE (sym) = cu->language;
+ SYMBOL_SET_LANGUAGE (sym, cu->language);
linkagename = dwarf2_physname (name, die, cu);
SYMBOL_SET_NAMES (sym, linkagename, strlen (linkagename), 0, objfile);
access them globally. For instance, we want to be able
to break on a nested subprogram without having to
specify the context. */
- add_symbol_to_list (sym, &global_symbols);
+ list_to_add = &global_symbols;
}
else
{
- add_symbol_to_list (sym, cu->list_in_scope);
+ list_to_add = cu->list_in_scope;
}
break;
case DW_TAG_inlined_subroutine:
/* Do not add the symbol to any lists. It will be found via
BLOCK_FUNCTION from the blockvector. */
break;
+ case DW_TAG_template_value_param:
+ suppress_add = 1;
+ /* Fall through. */
case DW_TAG_variable:
case DW_TAG_member:
/* Compilation with minimal debug info may result in variables
{
dwarf2_const_value (attr, sym, cu);
attr2 = dwarf2_attr (die, DW_AT_external, cu);
- if (attr2 && (DW_UNSND (attr2) != 0))
- add_symbol_to_list (sym, &global_symbols);
- else
- add_symbol_to_list (sym, cu->list_in_scope);
+ if (!suppress_add)
+ {
+ if (attr2 && (DW_UNSND (attr2) != 0))
+ list_to_add = &global_symbols;
+ else
+ list_to_add = cu->list_in_scope;
+ }
break;
}
attr = dwarf2_attr (die, DW_AT_location, cu);
{
var_decode_location (attr, sym, cu);
attr2 = dwarf2_attr (die, DW_AT_external, cu);
- if (attr2 && (DW_UNSND (attr2) != 0))
+ if (SYMBOL_CLASS (sym) == LOC_STATIC
+ && SYMBOL_VALUE_ADDRESS (sym) == 0
+ && !dwarf2_per_objfile->has_section_at_zero)
+ {
+ /* When a static variable is eliminated by the linker,
+ the corresponding debug information is not stripped
+ out, but the variable address is set to null;
+ do not add such variables into symbol table. */
+ }
+ else if (attr2 && (DW_UNSND (attr2) != 0))
{
- struct pending **list_to_add;
-
/* Workaround gfortran PR debug/40040 - it uses
DW_AT_location for variables in -fPIC libraries which may
get overriden by other libraries/executable and get
but it may be block-scoped. */
list_to_add = (cu->list_in_scope == &file_symbols
? &global_symbols : cu->list_in_scope);
- add_symbol_to_list (sym, list_to_add);
}
else
- add_symbol_to_list (sym, cu->list_in_scope);
+ list_to_add = cu->list_in_scope;
}
else
{
if (attr2 && (DW_UNSND (attr2) != 0)
&& dwarf2_attr (die, DW_AT_type, cu) != NULL)
{
- struct pending **list_to_add;
-
/* A variable with DW_AT_external is never static, but it
may be block-scoped. */
list_to_add = (cu->list_in_scope == &file_symbols
? &global_symbols : cu->list_in_scope);
SYMBOL_CLASS (sym) = LOC_UNRESOLVED;
- add_symbol_to_list (sym, list_to_add);
}
else if (!die_is_declaration (die, cu))
{
/* Use the default LOC_OPTIMIZED_OUT class. */
gdb_assert (SYMBOL_CLASS (sym) == LOC_OPTIMIZED_OUT);
- add_symbol_to_list (sym, cu->list_in_scope);
+ if (!suppress_add)
+ list_to_add = cu->list_in_scope;
}
}
break;
SYMBOL_TYPE (sym) = ref_type;
}
- add_symbol_to_list (sym, cu->list_in_scope);
+ list_to_add = cu->list_in_scope;
break;
case DW_TAG_unspecified_parameters:
/* From varargs functions; gdb doesn't seem to have any
interest in this information, so just ignore it for now.
(FIXME?) */
break;
+ case DW_TAG_template_type_param:
+ suppress_add = 1;
+ /* Fall through. */
case DW_TAG_class_type:
case DW_TAG_interface_type:
case DW_TAG_structure_type:
saves you. See the OtherFileClass tests in
gdb.c++/namespace.exp. */
- struct pending **list_to_add;
-
- list_to_add = (cu->list_in_scope == &file_symbols
- && (cu->language == language_cplus
- || cu->language == language_java)
- ? &global_symbols : cu->list_in_scope);
-
- add_symbol_to_list (sym, list_to_add);
+ if (!suppress_add)
+ {
+ list_to_add = (cu->list_in_scope == &file_symbols
+ && (cu->language == language_cplus
+ || cu->language == language_java)
+ ? &global_symbols : cu->list_in_scope);
+ }
/* The semantics of C++ state that "struct foo { ... }" also
defines a typedef for "foo". A Java class declaration also
case DW_TAG_typedef:
SYMBOL_CLASS (sym) = LOC_TYPEDEF;
SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
- add_symbol_to_list (sym, cu->list_in_scope);
+ list_to_add = cu->list_in_scope;
break;
case DW_TAG_base_type:
case DW_TAG_subrange_type:
SYMBOL_CLASS (sym) = LOC_TYPEDEF;
SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
- add_symbol_to_list (sym, cu->list_in_scope);
+ list_to_add = cu->list_in_scope;
break;
case DW_TAG_enumerator:
attr = dwarf2_attr (die, DW_AT_const_value, cu);
/* NOTE: carlton/2003-11-10: See comment above in the
DW_TAG_class_type, etc. block. */
- struct pending **list_to_add;
-
list_to_add = (cu->list_in_scope == &file_symbols
&& (cu->language == language_cplus
|| cu->language == language_java)
? &global_symbols : cu->list_in_scope);
-
- add_symbol_to_list (sym, list_to_add);
}
break;
case DW_TAG_namespace:
SYMBOL_CLASS (sym) = LOC_TYPEDEF;
- add_symbol_to_list (sym, &global_symbols);
+ list_to_add = &global_symbols;
break;
default:
/* Not a tag we recognize. Hopefully we aren't processing
break;
}
+ if (suppress_add)
+ {
+ sym->hash_next = objfile->template_symbols;
+ objfile->template_symbols = sym;
+ list_to_add = NULL;
+ }
+
+ if (list_to_add != NULL)
+ add_symbol_to_list (sym, list_to_add);
+
/* For the benefit of old versions of GCC, check for anonymous
namespaces based on the demangled name. */
if (!processing_has_namespace_info
return (sym);
}
-/* Copy constant value from an attribute to a symbol. */
+/* A wrapper for new_symbol_full that always allocates a new symbol. */
-static void
-dwarf2_const_value (struct attribute *attr, struct symbol *sym,
- struct dwarf2_cu *cu)
+static struct symbol *
+new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu)
+{
+ return new_symbol_full (die, type, cu, NULL);
+}
+
+/* Given an attr with a DW_FORM_dataN value in host byte order,
+ zero-extend it as appropriate for the symbol's type. The DWARF
+ standard (v4) is not entirely clear about the meaning of using
+ DW_FORM_dataN for a constant with a signed type, where the type is
+ wider than the data. The conclusion of a discussion on the DWARF
+ list was that this is unspecified. We choose to always zero-extend
+ because that is the interpretation long in use by GCC. */
+
+static gdb_byte *
+dwarf2_const_value_data (struct attribute *attr, struct type *type,
+ const char *name, struct obstack *obstack,
+ struct dwarf2_cu *cu, long *value, int bits)
{
struct objfile *objfile = cu->objfile;
- struct comp_unit_head *cu_header = &cu->header;
enum bfd_endian byte_order = bfd_big_endian (objfile->obfd) ?
BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE;
+ LONGEST l = DW_UNSND (attr);
+
+ if (bits < sizeof (*value) * 8)
+ {
+ l &= ((LONGEST) 1 << bits) - 1;
+ *value = l;
+ }
+ else if (bits == sizeof (*value) * 8)
+ *value = l;
+ else
+ {
+ gdb_byte *bytes = obstack_alloc (obstack, bits / 8);
+ store_unsigned_integer (bytes, bits / 8, byte_order, l);
+ return bytes;
+ }
+
+ return NULL;
+}
+
+/* Read a constant value from an attribute. Either set *VALUE, or if
+ the value does not fit in *VALUE, set *BYTES - either already
+ allocated on the objfile obstack, or newly allocated on OBSTACK,
+ or, set *BATON, if we translated the constant to a location
+ expression. */
+
+static void
+dwarf2_const_value_attr (struct attribute *attr, struct type *type,
+ const char *name, struct obstack *obstack,
+ struct dwarf2_cu *cu,
+ long *value, gdb_byte **bytes,
+ struct dwarf2_locexpr_baton **baton)
+{
+ struct objfile *objfile = cu->objfile;
+ struct comp_unit_head *cu_header = &cu->header;
struct dwarf_block *blk;
+ enum bfd_endian byte_order = (bfd_big_endian (objfile->obfd) ?
+ BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE);
+
+ *value = 0;
+ *bytes = NULL;
+ *baton = NULL;
switch (attr->form)
{
case DW_FORM_addr:
{
- struct dwarf2_locexpr_baton *baton;
gdb_byte *data;
- if (TYPE_LENGTH (SYMBOL_TYPE (sym)) != cu_header->addr_size)
- dwarf2_const_value_length_mismatch_complaint (SYMBOL_PRINT_NAME (sym),
+ if (TYPE_LENGTH (type) != cu_header->addr_size)
+ dwarf2_const_value_length_mismatch_complaint (name,
cu_header->addr_size,
- TYPE_LENGTH (SYMBOL_TYPE
- (sym)));
+ TYPE_LENGTH (type));
/* Symbols of this form are reasonably rare, so we just
piggyback on the existing location code rather than writing
a new implementation of symbol_computed_ops. */
- baton = obstack_alloc (&objfile->objfile_obstack,
- sizeof (struct dwarf2_locexpr_baton));
- baton->per_cu = cu->per_cu;
- gdb_assert (baton->per_cu);
+ *baton = obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct dwarf2_locexpr_baton));
+ (*baton)->per_cu = cu->per_cu;
+ gdb_assert ((*baton)->per_cu);
- baton->size = 2 + cu_header->addr_size;
- data = obstack_alloc (&objfile->objfile_obstack, baton->size);
- baton->data = data;
+ (*baton)->size = 2 + cu_header->addr_size;
+ data = obstack_alloc (&objfile->objfile_obstack, (*baton)->size);
+ (*baton)->data = data;
data[0] = DW_OP_addr;
store_unsigned_integer (&data[1], cu_header->addr_size,
byte_order, DW_ADDR (attr));
data[cu_header->addr_size + 1] = DW_OP_stack_value;
-
- SYMBOL_COMPUTED_OPS (sym) = &dwarf2_locexpr_funcs;
- SYMBOL_LOCATION_BATON (sym) = baton;
- SYMBOL_CLASS (sym) = LOC_COMPUTED;
}
break;
case DW_FORM_string:
case DW_FORM_strp:
- /* DW_STRING is already allocated on the obstack, point directly
- to it. */
- SYMBOL_VALUE_BYTES (sym) = (gdb_byte *) DW_STRING (attr);
- SYMBOL_CLASS (sym) = LOC_CONST_BYTES;
+ /* DW_STRING is already allocated on the objfile obstack, point
+ directly to it. */
+ *bytes = (gdb_byte *) DW_STRING (attr);
break;
case DW_FORM_block1:
case DW_FORM_block2:
case DW_FORM_block:
case DW_FORM_exprloc:
blk = DW_BLOCK (attr);
- if (TYPE_LENGTH (SYMBOL_TYPE (sym)) != blk->size)
- dwarf2_const_value_length_mismatch_complaint (SYMBOL_PRINT_NAME (sym),
- blk->size,
- TYPE_LENGTH (SYMBOL_TYPE
- (sym)));
- SYMBOL_VALUE_BYTES (sym) =
- obstack_alloc (&objfile->objfile_obstack, blk->size);
- memcpy (SYMBOL_VALUE_BYTES (sym), blk->data, blk->size);
- SYMBOL_CLASS (sym) = LOC_CONST_BYTES;
+ if (TYPE_LENGTH (type) != blk->size)
+ dwarf2_const_value_length_mismatch_complaint (name, blk->size,
+ TYPE_LENGTH (type));
+ *bytes = blk->data;
break;
/* The DW_AT_const_value attributes are supposed to carry the
converted to host endianness, so we just need to sign- or
zero-extend it as appropriate. */
case DW_FORM_data1:
- dwarf2_const_value_data (attr, sym, 8);
+ *bytes = dwarf2_const_value_data (attr, type, name, obstack, cu, value, 8);
break;
case DW_FORM_data2:
- dwarf2_const_value_data (attr, sym, 16);
+ *bytes = dwarf2_const_value_data (attr, type, name, obstack, cu, value, 16);
break;
case DW_FORM_data4:
- dwarf2_const_value_data (attr, sym, 32);
+ *bytes = dwarf2_const_value_data (attr, type, name, obstack, cu, value, 32);
break;
case DW_FORM_data8:
- dwarf2_const_value_data (attr, sym, 64);
+ *bytes = dwarf2_const_value_data (attr, type, name, obstack, cu, value, 64);
break;
case DW_FORM_sdata:
- SYMBOL_VALUE (sym) = DW_SND (attr);
- SYMBOL_CLASS (sym) = LOC_CONST;
+ *value = DW_SND (attr);
break;
case DW_FORM_udata:
- SYMBOL_VALUE (sym) = DW_UNSND (attr);
- SYMBOL_CLASS (sym) = LOC_CONST;
+ *value = DW_UNSND (attr);
break;
default:
complaint (&symfile_complaints,
_("unsupported const value attribute form: '%s'"),
dwarf_form_name (attr->form));
- SYMBOL_VALUE (sym) = 0;
- SYMBOL_CLASS (sym) = LOC_CONST;
+ *value = 0;
break;
}
}
-/* Given an attr with a DW_FORM_dataN value in host byte order, sign-
- or zero-extend it as appropriate for the symbol's type. */
+/* Copy constant value from an attribute to a symbol. */
+
static void
-dwarf2_const_value_data (struct attribute *attr,
- struct symbol *sym,
- int bits)
+dwarf2_const_value (struct attribute *attr, struct symbol *sym,
+ struct dwarf2_cu *cu)
{
- LONGEST l = DW_UNSND (attr);
+ struct objfile *objfile = cu->objfile;
+ struct comp_unit_head *cu_header = &cu->header;
+ long value;
+ gdb_byte *bytes;
+ struct dwarf2_locexpr_baton *baton;
+
+ dwarf2_const_value_attr (attr, SYMBOL_TYPE (sym),
+ SYMBOL_PRINT_NAME (sym),
+ &objfile->objfile_obstack, cu,
+ &value, &bytes, &baton);
- if (bits < sizeof (l) * 8)
+ if (baton != NULL)
{
- if (TYPE_UNSIGNED (SYMBOL_TYPE (sym)))
- l &= ((LONGEST) 1 << bits) - 1;
- else
- l = (l << (sizeof (l) * 8 - bits)) >> (sizeof (l) * 8 - bits);
+ SYMBOL_COMPUTED_OPS (sym) = &dwarf2_locexpr_funcs;
+ SYMBOL_LOCATION_BATON (sym) = baton;
+ SYMBOL_CLASS (sym) = LOC_COMPUTED;
+ }
+ else if (bytes != NULL)
+ {
+ SYMBOL_VALUE_BYTES (sym) = bytes;
+ SYMBOL_CLASS (sym) = LOC_CONST_BYTES;
+ }
+ else
+ {
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_CLASS (sym) = LOC_CONST;
}
-
- SYMBOL_VALUE (sym) = l;
- SYMBOL_CLASS (sym) = LOC_CONST;
}
if (parent == NULL)
return "";
+ else if (parent->building_fullname)
+ {
+ const char *name;
+ const char *parent_name;
+
+ /* It has been seen on RealView 2.2 built binaries,
+ DW_TAG_template_type_param types actually _defined_ as
+ children of the parent class:
+
+ enum E {};
+ template class <class Enum> Class{};
+ Class<enum E> class_e;
+
+ 1: DW_TAG_class_type (Class)
+ 2: DW_TAG_enumeration_type (E)
+ 3: DW_TAG_enumerator (enum1:0)
+ 3: DW_TAG_enumerator (enum2:1)
+ ...
+ 2: DW_TAG_template_type_param
+ DW_AT_type DW_FORM_ref_udata (E)
+
+ Besides being broken debug info, it can put GDB into an
+ infinite loop. Consider:
+
+ When we're building the full name for Class<E>, we'll start
+ at Class, and go look over its template type parameters,
+ finding E. We'll then try to build the full name of E, and
+ reach here. We're now trying to build the full name of E,
+ and look over the parent DIE for containing scope. In the
+ broken case, if we followed the parent DIE of E, we'd again
+ find Class, and once again go look at its template type
+ arguments, etc., etc. Simply don't consider such parent die
+ as source-level parent of this die (it can't be, the language
+ doesn't allow it), and break the loop here. */
+ name = dwarf2_name (die, cu);
+ parent_name = dwarf2_name (parent, cu);
+ complaint (&symfile_complaints,
+ _("template param type '%s' defined within parent '%s'"),
+ name ? name : "<unknown>",
+ parent_name ? parent_name : "<unknown>");
+ return "";
+ }
else
switch (parent->tag)
{
return "DW_AT_body_end";
case DW_AT_GNU_vector:
return "DW_AT_GNU_vector";
+ case DW_AT_GNU_odr_signature:
+ return "DW_AT_GNU_odr_signature";
/* VMS extensions. */
case DW_AT_VMS_rtnbeg_pd_address:
return "DW_AT_VMS_rtnbeg_pd_address";
maybe_queue_comp_unit (struct dwarf2_cu *this_cu,
struct dwarf2_per_cu_data *per_cu)
{
+ /* We may arrive here during partial symbol reading, if we need full
+ DIEs to process an unusual case (e.g. template arguments). Do
+ not queue PER_CU, just tell our caller to load its DIEs. */
+ if (dwarf2_per_objfile->reading_partial_symbols)
+ {
+ if (per_cu->cu == NULL || per_cu->cu->dies == NULL)
+ return 1;
+ return 0;
+ }
+
/* Mark the dependence relation so that we don't flush PER_CU
too early. */
dwarf2_add_dependence (this_cu, per_cu);
gdb_assert (cu->per_cu != NULL);
+ target_cu = cu;
+
if (cu->per_cu->from_debug_types)
{
/* .debug_types CUs cannot reference anything outside their CU.
DW_FORM_sig8. */
if (! offset_in_cu_p (&cu->header, offset))
return NULL;
- target_cu = cu;
}
else if (! offset_in_cu_p (&cu->header, offset))
{
target_cu = per_cu->cu;
}
- else
- target_cu = cu;
+ else if (cu->dies == NULL)
+ {
+ /* We're loading full DIEs during partial symbol reading. */
+ gdb_assert (dwarf2_per_objfile->reading_partial_symbols);
+ load_full_comp_unit (cu->per_cu, cu->objfile);
+ }
*ref_cu = target_cu;
temp_die.offset = offset;
read_signatured_type (struct objfile *objfile,
struct signatured_type *type_sig)
{
- gdb_byte *types_ptr = dwarf2_per_objfile->types.buffer + type_sig->offset;
+ gdb_byte *types_ptr;
struct die_reader_specs reader_specs;
struct dwarf2_cu *cu;
ULONGEST signature;
struct cleanup *back_to, *free_cu_cleanup;
struct attribute *attr;
+ dwarf2_read_section (objfile, &dwarf2_per_objfile->types);
+ types_ptr = dwarf2_per_objfile->types.buffer + type_sig->offset;
+
gdb_assert (type_sig->per_cu.cu == NULL);
cu = xmalloc (sizeof (struct dwarf2_cu));
read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
mac_ptr += bytes_read;
- read_string (abfd, mac_ptr, &bytes_read);
+ read_direct_string (abfd, mac_ptr, &bytes_read);
mac_ptr += bytes_read;
}
break;
read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
mac_ptr += bytes_read;
- read_string (abfd, mac_ptr, &bytes_read);
+ read_direct_string (abfd, mac_ptr, &bytes_read);
mac_ptr += bytes_read;
}
break;
line = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
mac_ptr += bytes_read;
- body = read_string (abfd, mac_ptr, &bytes_read);
+ body = read_direct_string (abfd, mac_ptr, &bytes_read);
mac_ptr += bytes_read;
if (! current_file)
constant = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
mac_ptr += bytes_read;
- string = read_string (abfd, mac_ptr, &bytes_read);
+ string = read_direct_string (abfd, mac_ptr, &bytes_read);
mac_ptr += bytes_read;
/* We don't recognize any vendor extensions. */
char addr[8];
CORE_ADDR baseaddr;
+ /* Don't bother recording empty ranges. */
+ if (pst->textlow == pst->texthigh)
+ return;
+
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
store_unsigned_integer (addr, 8, BFD_ENDIAN_LITTLE, pst->textlow - baseaddr);
unlink (*filename);
}
+/* A helper struct used when iterating over debug_types. */
+struct signatured_type_index_data
+{
+ struct objfile *objfile;
+ struct mapped_symtab *symtab;
+ struct obstack *types_list;
+ int cu_index;
+};
+
+/* A helper function that writes a single signatured_type to an
+ obstack. */
+static int
+write_one_signatured_type (void **slot, void *d)
+{
+ struct signatured_type_index_data *info = d;
+ struct signatured_type *entry = (struct signatured_type *) *slot;
+ struct dwarf2_per_cu_data *cu = &entry->per_cu;
+ struct partial_symtab *psymtab = cu->v.psymtab;
+ gdb_byte val[8];
+
+ write_psymbols (info->symtab,
+ info->objfile->global_psymbols.list + psymtab->globals_offset,
+ psymtab->n_global_syms, info->cu_index);
+ write_psymbols (info->symtab,
+ info->objfile->static_psymbols.list + psymtab->statics_offset,
+ psymtab->n_static_syms, info->cu_index);
+
+ store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, entry->offset);
+ obstack_grow (info->types_list, val, 8);
+ store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, entry->type_offset);
+ obstack_grow (info->types_list, val, 8);
+ store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, entry->signature);
+ obstack_grow (info->types_list, val, 8);
+
+ ++info->cu_index;
+
+ return 1;
+}
+
/* Create an index file for OBJFILE in the directory DIR. */
static void
write_psymtabs_to_index (struct objfile *objfile, const char *dir)
{
struct cleanup *cleanup;
char *filename, *cleanup_filename;
- struct obstack contents, addr_obstack, constant_pool, symtab_obstack, cu_list;
+ struct obstack contents, addr_obstack, constant_pool, symtab_obstack;
+ struct obstack cu_list, types_cu_list;
int i;
FILE *out_file;
struct mapped_symtab *symtab;
obstack_init (&cu_list);
make_cleanup_obstack_free (&cu_list);
+ obstack_init (&types_cu_list);
+ make_cleanup_obstack_free (&types_cu_list);
+
+ /* The list is already sorted, so we don't need to do additional
+ work here. Also, the debug_types entries do not appear in
+ all_comp_units, but only in their own hash table. */
for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
{
struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
obstack_grow (&cu_list, val, 8);
}
+ /* Write out the .debug_type entries, if any. */
+ if (dwarf2_per_objfile->signatured_types)
+ {
+ struct signatured_type_index_data sig_data;
+
+ sig_data.objfile = objfile;
+ sig_data.symtab = symtab;
+ sig_data.types_list = &types_cu_list;
+ sig_data.cu_index = dwarf2_per_objfile->n_comp_units;
+ htab_traverse_noresize (dwarf2_per_objfile->signatured_types,
+ write_one_signatured_type, &sig_data);
+ }
+
obstack_init (&constant_pool);
make_cleanup_obstack_free (&constant_pool);
obstack_init (&symtab_obstack);
obstack_init (&contents);
make_cleanup_obstack_free (&contents);
- size_of_contents = 5 * sizeof (offset_type);
+ size_of_contents = 6 * sizeof (offset_type);
total_len = size_of_contents;
/* The version number. */
- val = MAYBE_SWAP (1);
+ val = MAYBE_SWAP (2);
obstack_grow (&contents, &val, sizeof (val));
/* The offset of the CU list from the start of the file. */
obstack_grow (&contents, &val, sizeof (val));
total_len += obstack_object_size (&cu_list);
+ /* The offset of the types CU list from the start of the file. */
+ val = MAYBE_SWAP (total_len);
+ obstack_grow (&contents, &val, sizeof (val));
+ total_len += obstack_object_size (&types_cu_list);
+
/* The offset of the address table from the start of the file. */
val = MAYBE_SWAP (total_len);
obstack_grow (&contents, &val, sizeof (val));
write_obstack (out_file, &contents);
write_obstack (out_file, &cu_list);
+ write_obstack (out_file, &types_cu_list);
write_obstack (out_file, &addr_obstack);
write_obstack (out_file, &symtab_obstack);
write_obstack (out_file, &constant_pool);
1. The file header. This is a sequence of values, of offset_type
unless otherwise noted:
- [0] The version number. Currently 1.
+ [0] The version number. Currently 1 or 2. The differences are
+ noted below. Version 1 did not account for .debug_types sections;
+ the presence of a .debug_types section invalidates any version 1
+ index that may exist.
[1] The offset, from the start of the file, of the CU list.
+ [1.5] In version 2, the offset, from the start of the file, of the
+ types CU list. This offset does not appear in version 1. Note
+ that this can be empty, in which case this offset will be equal to
+ the next offset.
[2] The offset, from the start of the file, of the address section.
[3] The offset, from the start of the file, of the symbol table.
[4] The offset, from the start of the file, of the constant pool.
2. The CU list. This is a sequence of pairs of 64-bit
- little-endian values. The first element in each pair is the offset
- of a CU in the .debug_info section. The second element in each
- pair is the length of that CU. References to a CU elsewhere in the
- map are done using a CU index, which is just the 0-based index into
- this table.
+ little-endian values, sorted by the CU offset. The first element
+ in each pair is the offset of a CU in the .debug_info section. The
+ second element in each pair is the length of that CU. References
+ to a CU elsewhere in the map are done using a CU index, which is
+ just the 0-based index into this table. Note that if there are
+ type CUs, then conceptually CUs and type CUs form a single list for
+ the purposes of CU indices.
+
+ 2.5 The types CU list. This does not appear in a version 1 index.
+ This is a sequence of triplets of 64-bit little-endian values. In
+ a triplet, the first value is the CU offset, the second value is
+ the type offset in the CU, and the third value is the type
+ signature. The types CU list is not sorted.
3. The address section. The address section consists of a sequence
of address entries. Each address entry has three elements.