X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fdwarf2read.c;h=55b335da9d9f47a335e6be810223317c6bc1b793;hb=4bb1dc5eb230ed5e566100dcb688492b77cde974;hp=484561c91485036b48687859b9ef0293712b619b;hpb=78b119cb5dbfe838fa6ecfedba96bd5c04064514;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 484561c914..55b335da9d 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -1,5 +1,5 @@ /* DWARF 2 debugging format support for GDB. - Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 + Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology, @@ -38,10 +38,13 @@ #include "expression.h" #include "filenames.h" /* for DOSish file names */ #include "macrotab.h" - #include "language.h" #include "complaints.h" #include "bcache.h" +#include "dwarf2expr.h" +#include "dwarf2loc.h" +#include "cp-support.h" + #include #include "gdb_string.h" #include "gdb_assert.h" @@ -133,6 +136,7 @@ static file_ptr dwarf_aranges_offset; static file_ptr dwarf_loc_offset; static file_ptr dwarf_macinfo_offset; static file_ptr dwarf_str_offset; +static file_ptr dwarf_ranges_offset; file_ptr dwarf_frame_offset; file_ptr dwarf_eh_frame_offset; @@ -144,9 +148,22 @@ static unsigned int dwarf_aranges_size; static unsigned int dwarf_loc_size; static unsigned int dwarf_macinfo_size; static unsigned int dwarf_str_size; +static unsigned int dwarf_ranges_size; unsigned int dwarf_frame_size; unsigned int dwarf_eh_frame_size; +static asection *dwarf_info_section; +static asection *dwarf_abbrev_section; +static asection *dwarf_line_section; +static asection *dwarf_pubnames_section; +static asection *dwarf_aranges_section; +static asection *dwarf_loc_section; +static asection *dwarf_macinfo_section; +static asection *dwarf_str_section; +static asection *dwarf_ranges_section; +asection *dwarf_frame_section; +asection *dwarf_eh_frame_section; + /* names of the debugging sections */ #define INFO_SECTION ".debug_info" @@ -157,11 +174,17 @@ unsigned int dwarf_eh_frame_size; #define LOC_SECTION ".debug_loc" #define MACINFO_SECTION ".debug_macinfo" #define STR_SECTION ".debug_str" +#define RANGES_SECTION ".debug_ranges" #define FRAME_SECTION ".debug_frame" #define EH_FRAME_SECTION ".eh_frame" /* local data types */ +/* We hold several abbreviation tables in memory at the same time. */ +#ifndef ABBREV_HASH_SIZE +#define ABBREV_HASH_SIZE 121 +#endif + /* The data in a compilation unit header, after target2host translation, looks like this. */ struct comp_unit_head @@ -174,6 +197,37 @@ struct comp_unit_head 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 */ + + char *cu_head_ptr; + + /* Pointer to the first die of this compilatio unit. This will + * be the first byte following the compilation unit header. */ + + char *first_die_ptr; + + /* Pointer to the next compilation unit header in the program. */ + + struct comp_unit_head *next; + + /* DWARF abbreviation table associated with this compilation unit */ + + struct abbrev_info *dwarf2_abbrevs[ABBREV_HASH_SIZE]; + + /* Base address of this compilation unit. */ + + CORE_ADDR base_address; + + /* Non-zero if base_address has been set. */ + + int base_known; }; /* The line number information for a compilation unit (found in the @@ -312,17 +366,10 @@ struct dwarf_block char *data; }; -/* We only hold one compilation unit's abbrevs in - memory at any one time. */ -#ifndef ABBREV_HASH_SIZE -#define ABBREV_HASH_SIZE 121 -#endif #ifndef ATTR_ALLOC_CHUNK #define ATTR_ALLOC_CHUNK 4 #endif -static struct abbrev_info *dwarf2_abbrevs[ABBREV_HASH_SIZE]; - /* A hash table of die offsets for following references. */ #ifndef REF_HASH_SIZE #define REF_HASH_SIZE 1021 @@ -352,6 +399,8 @@ static char *dwarf_abbrev_buffer; static char *dwarf_line_buffer; static char *dwarf_str_buffer; static char *dwarf_macinfo_buffer; +static char *dwarf_ranges_buffer; +static char *dwarf_loc_buffer; /* A zeroed version of a partial die for initialization purposes. */ static struct partial_die_info zeroed_partial_die; @@ -389,6 +438,12 @@ static int islocal; /* Variable is at the returned offset this function, so we can't say which register it's relative to; use LOC_LOCAL. */ +static int is_thread_local; /* Variable is at a constant offset in the + thread-local storage block for the + current thread and the dynamic linker + module containing this expression. + decode_locdesc returns the offset from + that base. */ /* DW_AT_frame_base values for the current function. frame_base_reg is -1 if DW_AT_frame_base is missing, otherwise it @@ -454,6 +509,21 @@ struct dwarf2_pinfo unsigned int dwarf_macinfo_size; + /* Pointer to start of dwarf ranges buffer for the objfile. */ + + char *dwarf_ranges_buffer; + + /* Size of dwarf ranges buffer for the objfile. */ + + unsigned int dwarf_ranges_size; + + /* Pointer to start of dwarf locations buffer for the objfile. */ + + char *dwarf_loc_buffer; + + /* Size of dwarf locations buffer for the objfile. */ + + unsigned int dwarf_loc_size; }; #define PST_PRIVATE(p) ((struct dwarf2_pinfo *)(p)->read_symtab_private) @@ -467,6 +537,10 @@ struct dwarf2_pinfo #define DWARF_STR_SIZE(p) (PST_PRIVATE(p)->dwarf_str_size) #define DWARF_MACINFO_BUFFER(p) (PST_PRIVATE(p)->dwarf_macinfo_buffer) #define DWARF_MACINFO_SIZE(p) (PST_PRIVATE(p)->dwarf_macinfo_size) +#define DWARF_RANGES_BUFFER(p) (PST_PRIVATE(p)->dwarf_ranges_buffer) +#define DWARF_RANGES_SIZE(p) (PST_PRIVATE(p)->dwarf_ranges_size) +#define DWARF_LOC_BUFFER(p) (PST_PRIVATE(p)->dwarf_loc_buffer) +#define DWARF_LOC_SIZE(p) (PST_PRIVATE(p)->dwarf_loc_size) /* Maintain an array of referenced fundamental types for the current compilation unit being read. For DWARF version 1, we have to construct @@ -534,134 +608,67 @@ struct field_info /* Various complaints about symbol reading that don't abort the process */ -static struct complaint dwarf2_const_ignored = -{ - "type qualifier 'const' ignored", 0, 0 -}; -static struct complaint dwarf2_volatile_ignored = -{ - "type qualifier 'volatile' ignored", 0, 0 -}; -static struct complaint dwarf2_non_const_array_bound_ignored = -{ - "non-constant array bounds form '%s' ignored", 0, 0 -}; -static struct complaint dwarf2_missing_line_number_section = -{ - "missing .debug_line section", 0, 0 -}; -static struct complaint dwarf2_statement_list_fits_in_line_number_section = -{ - "statement list doesn't fit in .debug_line section", 0, 0 -}; -static struct complaint dwarf2_mangled_line_number_section = -{ - "mangled .debug_line section", 0, 0 -}; -static struct complaint dwarf2_unsupported_die_ref_attr = -{ - "unsupported die ref attribute form: '%s'", 0, 0 -}; -static struct complaint dwarf2_unsupported_stack_op = -{ - "unsupported stack op: '%s'", 0, 0 -}; -static struct complaint dwarf2_complex_location_expr = -{ - "location expression too complex", 0, 0 -}; -static struct complaint dwarf2_unsupported_tag = -{ - "unsupported tag: '%s'", 0, 0 -}; -static struct complaint dwarf2_unsupported_at_encoding = -{ - "unsupported DW_AT_encoding: '%s'", 0, 0 -}; -static struct complaint dwarf2_unsupported_at_frame_base = -{ - "unsupported DW_AT_frame_base for function '%s'", 0, 0 -}; -static struct complaint dwarf2_unexpected_tag = -{ - "unexepected tag in read_type_die: '%s'", 0, 0 -}; -static struct complaint dwarf2_missing_at_frame_base = -{ - "DW_AT_frame_base missing for DW_OP_fbreg", 0, 0 -}; -static struct complaint dwarf2_bad_static_member_name = -{ - "unrecognized static data member name '%s'", 0, 0 -}; -static struct complaint dwarf2_unsupported_accessibility = -{ - "unsupported accessibility %d", 0, 0 -}; -static struct complaint dwarf2_bad_member_name_complaint = -{ - "cannot extract member name from '%s'", 0, 0 -}; -static struct complaint dwarf2_missing_member_fn_type_complaint = -{ - "member function type missing for '%s'", 0, 0 -}; -static struct complaint dwarf2_vtbl_not_found_complaint = -{ - "virtual function table pointer not found when defining class '%s'", 0, 0 -}; -static struct complaint dwarf2_absolute_sibling_complaint = -{ - "ignoring absolute DW_AT_sibling", 0, 0 -}; -static struct complaint dwarf2_const_value_length_mismatch = -{ - "const value length mismatch for '%s', got %d, expected %d", 0, 0 -}; -static struct complaint dwarf2_unsupported_const_value_attr = -{ - "unsupported const value attribute form: '%s'", 0, 0 -}; -static struct complaint dwarf2_misplaced_line_number = -{ - "misplaced first line number at 0x%lx for '%s'", 0, 0 -}; -static struct complaint dwarf2_line_header_too_long = +static void +dwarf2_non_const_array_bound_ignored_complaint (const char *arg1) { - "line number info header doesn't fit in `.debug_line' section", 0, 0 -}; -static struct complaint dwarf2_missing_macinfo_section = + complaint (&symfile_complaints, "non-constant array bounds form '%s' ignored", + arg1); +} + +static void +dwarf2_statement_list_fits_in_line_number_section_complaint (void) { - "missing .debug_macinfo section", 0, 0 -}; -static struct complaint dwarf2_macros_too_long = + complaint (&symfile_complaints, + "statement list doesn't fit in .debug_line section"); +} + +static void +dwarf2_complex_location_expr_complaint (void) { - "macro info runs off end of `.debug_macinfo' section", 0, 0 -}; -static struct complaint dwarf2_macros_not_terminated = + complaint (&symfile_complaints, "location expression too complex"); +} + +static void +dwarf2_unsupported_at_frame_base_complaint (const char *arg1) { - "no terminating 0-type entry for macros in `.debug_macinfo' section", 0, 0 -}; -static struct complaint dwarf2_macro_outside_file = + complaint (&symfile_complaints, + "unsupported DW_AT_frame_base for function '%s'", arg1); +} + +static void +dwarf2_const_value_length_mismatch_complaint (const char *arg1, int arg2, + int arg3) { - "debug info gives macro %s outside of any file: %s", 0, 0 -}; -static struct complaint dwarf2_macro_unmatched_end_file = + complaint (&symfile_complaints, + "const value length mismatch for '%s', got %d, expected %d", arg1, + arg2, arg3); +} + +static void +dwarf2_macros_too_long_complaint (void) { - "macro debug info has an unmatched `close_file' directive", 0, 0 -}; -static struct complaint dwarf2_macro_malformed_definition = + complaint (&symfile_complaints, + "macro info runs off end of `.debug_macinfo' section"); +} + +static void +dwarf2_macro_malformed_definition_complaint (const char *arg1) { - "macro debug info contains a malformed macro definition:\n`%s'", 0, 0 -}; -static struct complaint dwarf2_macro_spaces_in_definition = + complaint (&symfile_complaints, + "macro debug info contains a malformed macro definition:\n`%s'", + arg1); +} + +static void +dwarf2_invalid_attrib_class_complaint (const char *arg1, const char *arg2) { - "macro definition contains spaces in formal argument list:\n`%s'", 0, 0 -}; + complaint (&symfile_complaints, + "invalid attribute class or form for '%s' in '%s'", arg1, arg2); +} /* local function prototypes */ -static void dwarf2_locate_sections (bfd *, asection *, PTR); +static void dwarf2_locate_sections (bfd *, asection *, void *); #if 0 static void dwarf2_build_psymtabs_easy (struct objfile *, int); @@ -680,13 +687,15 @@ static void dwarf2_psymtab_to_symtab (struct partial_symtab *); static void psymtab_to_symtab_1 (struct partial_symtab *); -char *dwarf2_read_section (struct objfile *, file_ptr, unsigned int); +char *dwarf2_read_section (struct objfile *, file_ptr, unsigned int, + asection *); -static void dwarf2_read_abbrevs (bfd *, unsigned int); +static void dwarf2_read_abbrevs (bfd *abfd, struct comp_unit_head *cu_header); -static void dwarf2_empty_abbrev_table (PTR); +static void dwarf2_empty_abbrev_table (void *); -static struct abbrev_info *dwarf2_lookup_abbrev (unsigned int); +static struct abbrev_info *dwarf2_lookup_abbrev (unsigned int, + const struct comp_unit_head *cu_header); static char *read_partial_die (struct partial_die_info *, bfd *, char *, @@ -790,7 +799,8 @@ static void read_lexical_block_scope (struct die_info *, struct objfile *, const struct comp_unit_head *); static int dwarf2_get_pc_bounds (struct die_info *, - CORE_ADDR *, CORE_ADDR *, struct objfile *); + CORE_ADDR *, CORE_ADDR *, struct objfile *, + const struct comp_unit_head *); static void dwarf2_add_field (struct field_info *, struct die_info *, struct objfile *, const struct comp_unit_head *); @@ -799,7 +809,8 @@ static void dwarf2_attach_fields_to_type (struct field_info *, struct type *, struct objfile *); static void dwarf2_add_member_fn (struct field_info *, - struct die_info *, struct objfile *objfile, + struct die_info *, struct type *, + struct objfile *objfile, const struct comp_unit_head *); static void dwarf2_attach_fn_fields_to_type (struct field_info *, @@ -811,6 +822,9 @@ static void read_structure_scope (struct die_info *, struct objfile *, static void read_common_block (struct die_info *, struct objfile *, const struct comp_unit_head *); +static void read_namespace (struct die_info *die, struct objfile *objfile, + const struct comp_unit_head *cu_header); + static void read_enumeration (struct die_info *, struct objfile *, const struct comp_unit_head *); @@ -854,6 +868,10 @@ static void process_die (struct die_info *, struct objfile *, static char *dwarf2_linkage_name (struct die_info *); +static char *dwarf2_name (struct die_info *die); + +static struct die_info *dwarf2_extension (struct die_info *die); + static char *dwarf_tag_name (unsigned int); static char *dwarf_attr_name (unsigned int); @@ -890,7 +908,7 @@ static struct type *dwarf2_fundamental_type (struct objfile *, int); /* memory allocation interface */ -static void dwarf2_free_tmp_obstack (PTR); +static void dwarf2_free_tmp_obstack (void *); static struct dwarf_block *dwarf_alloc_block (void); @@ -906,6 +924,13 @@ static void dwarf_decode_macros (struct line_header *, unsigned int, char *, bfd *, const struct comp_unit_head *, struct objfile *); +static int attr_form_is_block (struct attribute *); + +static void +dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, + const struct comp_unit_head *, + struct objfile *objfile); + /* Try to locate the sections we need for DWARF 2 debugging information and return true if we have enough to do something. */ @@ -919,6 +944,9 @@ dwarf2_has_info (bfd *abfd) dwarf_macinfo_offset = 0; dwarf_frame_offset = 0; dwarf_eh_frame_offset = 0; + dwarf_ranges_offset = 0; + dwarf_loc_offset = 0; + bfd_map_over_sections (abfd, dwarf2_locate_sections, NULL); if (dwarf_info_offset && dwarf_abbrev_offset) { @@ -935,57 +963,73 @@ dwarf2_has_info (bfd *abfd) in. */ static void -dwarf2_locate_sections (bfd *ignore_abfd, asection *sectp, PTR ignore_ptr) +dwarf2_locate_sections (bfd *ignore_abfd, asection *sectp, void *ignore_ptr) { if (STREQ (sectp->name, INFO_SECTION)) { dwarf_info_offset = sectp->filepos; dwarf_info_size = bfd_get_section_size_before_reloc (sectp); + dwarf_info_section = sectp; } else if (STREQ (sectp->name, ABBREV_SECTION)) { dwarf_abbrev_offset = sectp->filepos; dwarf_abbrev_size = bfd_get_section_size_before_reloc (sectp); + dwarf_abbrev_section = sectp; } else if (STREQ (sectp->name, LINE_SECTION)) { dwarf_line_offset = sectp->filepos; dwarf_line_size = bfd_get_section_size_before_reloc (sectp); + dwarf_line_section = sectp; } else if (STREQ (sectp->name, PUBNAMES_SECTION)) { dwarf_pubnames_offset = sectp->filepos; dwarf_pubnames_size = bfd_get_section_size_before_reloc (sectp); + dwarf_pubnames_section = sectp; } else if (STREQ (sectp->name, ARANGES_SECTION)) { dwarf_aranges_offset = sectp->filepos; dwarf_aranges_size = bfd_get_section_size_before_reloc (sectp); + dwarf_aranges_section = sectp; } else if (STREQ (sectp->name, LOC_SECTION)) { dwarf_loc_offset = sectp->filepos; dwarf_loc_size = bfd_get_section_size_before_reloc (sectp); + dwarf_loc_section = sectp; } else if (STREQ (sectp->name, MACINFO_SECTION)) { dwarf_macinfo_offset = sectp->filepos; dwarf_macinfo_size = bfd_get_section_size_before_reloc (sectp); + dwarf_macinfo_section = sectp; } else if (STREQ (sectp->name, STR_SECTION)) { dwarf_str_offset = sectp->filepos; dwarf_str_size = bfd_get_section_size_before_reloc (sectp); + dwarf_str_section = sectp; } else if (STREQ (sectp->name, FRAME_SECTION)) { dwarf_frame_offset = sectp->filepos; dwarf_frame_size = bfd_get_section_size_before_reloc (sectp); + dwarf_frame_section = sectp; } else if (STREQ (sectp->name, EH_FRAME_SECTION)) { dwarf_eh_frame_offset = sectp->filepos; dwarf_eh_frame_size = bfd_get_section_size_before_reloc (sectp); + dwarf_eh_frame_section = sectp; + } + else if (STREQ (sectp->name, RANGES_SECTION)) + { + dwarf_ranges_offset = sectp->filepos; + dwarf_ranges_size = bfd_get_section_size_before_reloc (sectp); + dwarf_ranges_section = sectp; } } @@ -999,28 +1043,53 @@ dwarf2_build_psymtabs (struct objfile *objfile, int mainline) dwarf_info_buffer = dwarf2_read_section (objfile, dwarf_info_offset, - dwarf_info_size); + dwarf_info_size, + dwarf_info_section); dwarf_abbrev_buffer = dwarf2_read_section (objfile, dwarf_abbrev_offset, - dwarf_abbrev_size); - dwarf_line_buffer = dwarf2_read_section (objfile, - dwarf_line_offset, - dwarf_line_size); + dwarf_abbrev_size, + dwarf_abbrev_section); + + if (dwarf_line_offset) + dwarf_line_buffer = dwarf2_read_section (objfile, + dwarf_line_offset, + dwarf_line_size, + dwarf_line_section); + else + dwarf_line_buffer = NULL; if (dwarf_str_offset) dwarf_str_buffer = dwarf2_read_section (objfile, dwarf_str_offset, - dwarf_str_size); + dwarf_str_size, + dwarf_str_section); else dwarf_str_buffer = NULL; if (dwarf_macinfo_offset) dwarf_macinfo_buffer = dwarf2_read_section (objfile, dwarf_macinfo_offset, - dwarf_macinfo_size); + dwarf_macinfo_size, + dwarf_macinfo_section); else dwarf_macinfo_buffer = NULL; + if (dwarf_ranges_offset) + dwarf_ranges_buffer = dwarf2_read_section (objfile, + dwarf_ranges_offset, + dwarf_ranges_size, + dwarf_ranges_section); + else + dwarf_ranges_buffer = NULL; + + if (dwarf_loc_offset) + dwarf_loc_buffer = dwarf2_read_section (objfile, + dwarf_loc_offset, + dwarf_loc_size, + dwarf_loc_section); + else + dwarf_loc_buffer = NULL; + if (mainline || (objfile->global_psymbols.size == 0 && objfile->static_psymbols.size == 0)) @@ -1059,7 +1128,8 @@ dwarf2_build_psymtabs_easy (struct objfile *objfile, int mainline) pubnames_buffer = dwarf2_read_section (objfile, dwarf_pubnames_offset, - dwarf_pubnames_size); + dwarf_pubnames_size, + dwarf_pubnames_section); pubnames_ptr = pubnames_buffer; while ((pubnames_ptr - pubnames_buffer) < dwarf_pubnames_size) { @@ -1079,7 +1149,8 @@ dwarf2_build_psymtabs_easy (struct objfile *objfile, int mainline) aranges_buffer = dwarf2_read_section (objfile, dwarf_aranges_offset, - dwarf_aranges_size); + dwarf_aranges_size, + dwarf_aranges_section); } #endif @@ -1182,27 +1253,34 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) if (cu_header.version != 2) { - error ("Dwarf Error: wrong version in compilation unit header."); + error ("Dwarf Error: wrong version in compilation unit header (is %d, should be %d) [in module %s]", cu_header.version, 2, bfd_get_filename (abfd)); return; } if (cu_header.abbrev_offset >= dwarf_abbrev_size) { - error ("Dwarf Error: bad offset (0x%lx) in compilation unit header (offset 0x%lx + 6).", + error ("Dwarf Error: bad offset (0x%lx) in compilation unit header (offset 0x%lx + 6) [in module %s]", (long) cu_header.abbrev_offset, - (long) (beg_of_comp_unit - dwarf_info_buffer)); + (long) (beg_of_comp_unit - dwarf_info_buffer), + bfd_get_filename (abfd)); return; } if (beg_of_comp_unit + cu_header.length + cu_header.initial_length_size > dwarf_info_buffer + dwarf_info_size) { - error ("Dwarf Error: bad length (0x%lx) in compilation unit header (offset 0x%lx + 0).", + error ("Dwarf Error: bad length (0x%lx) in compilation unit header (offset 0x%lx + 0) [in module %s]", (long) cu_header.length, - (long) (beg_of_comp_unit - dwarf_info_buffer)); + (long) (beg_of_comp_unit - dwarf_info_buffer), + bfd_get_filename (abfd)); return; } + /* Complete the cu_header */ + cu_header.offset = beg_of_comp_unit - dwarf_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_header.abbrev_offset); - make_cleanup (dwarf2_empty_abbrev_table, NULL); + dwarf2_read_abbrevs (abfd, &cu_header); + make_cleanup (dwarf2_empty_abbrev_table, cu_header.dwarf2_abbrevs); /* Read the compilation unit die */ info_ptr = read_partial_die (&comp_unit_die, abfd, info_ptr, @@ -1231,6 +1309,10 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) DWARF_STR_SIZE (pst) = dwarf_str_size; DWARF_MACINFO_BUFFER (pst) = dwarf_macinfo_buffer; DWARF_MACINFO_SIZE (pst) = dwarf_macinfo_size; + DWARF_RANGES_BUFFER (pst) = dwarf_ranges_buffer; + DWARF_RANGES_SIZE (pst) = dwarf_ranges_size; + DWARF_LOC_BUFFER (pst) = dwarf_loc_buffer; + DWARF_LOC_SIZE (pst) = dwarf_loc_size; baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); /* Store the function that reads in the rest of the symbol table */ @@ -1290,6 +1372,17 @@ scan_partial_symbols (char *info_ptr, struct objfile *objfile, int nesting_level = 1; + /* We only want to read in symbols corresponding to variables or + other similar objects that are global or static. Normally, these + are all children of the DW_TAG_compile_unit die, so are all at + level 1. But C++ namespaces give ries to DW_TAG_namespace dies + whose children are global objects. So we keep track of what + level we currently think of as referring to file scope; this + should always equal 1 plus the number of namespaces that we are + currently nested within. */ + + int file_scope_level = 1; + *lowpc = ((CORE_ADDR) -1); *highpc = ((CORE_ADDR) 0); @@ -1297,7 +1390,9 @@ scan_partial_symbols (char *info_ptr, struct objfile *objfile, { info_ptr = read_partial_die (&pdi, abfd, info_ptr, cu_header); - if (pdi.name) + /* Anonymous namespaces have no name but are interesting. */ + + if (pdi.name != NULL || pdi.tag == DW_TAG_namespace) { switch (pdi.tag) { @@ -1312,7 +1407,7 @@ scan_partial_symbols (char *info_ptr, struct objfile *objfile, { *highpc = pdi.highpc; } - if ((pdi.is_external || nesting_level == 1) + if ((pdi.is_external || nesting_level == file_scope_level) && !pdi.is_declaration) { add_partial_symbol (&pdi, objfile, cu_header); @@ -1325,46 +1420,65 @@ scan_partial_symbols (char *info_ptr, struct objfile *objfile, case DW_TAG_structure_type: case DW_TAG_union_type: case DW_TAG_enumeration_type: - if ((pdi.is_external || nesting_level == 1) + if ((pdi.is_external || nesting_level == file_scope_level) && !pdi.is_declaration) { add_partial_symbol (&pdi, objfile, cu_header); } break; case DW_TAG_enumerator: - /* File scope enumerators are added to the partial symbol - table. */ - if (nesting_level == 2) + /* File scope enumerators are added to the partial + symbol table. They're children of the enumeration + type die, so they occur at a level one higher than we + normally look for. */ + if (nesting_level == file_scope_level + 1) add_partial_symbol (&pdi, objfile, cu_header); break; case DW_TAG_base_type: /* File scope base type definitions are added to the partial symbol table. */ - if (nesting_level == 1) + if (nesting_level == file_scope_level) add_partial_symbol (&pdi, objfile, cu_header); break; + case DW_TAG_namespace: + /* FIXME: carlton/2002-10-16: we're not yet doing + anything useful with this, but for now make sure that + these tags at least don't cause us to miss any + important symbols. */ + if (pdi.has_children) + file_scope_level++; default: break; } } - /* If the die has a sibling, skip to the sibling. - Do not skip enumeration types, we want to record their - enumerators. */ - if (pdi.sibling && pdi.tag != DW_TAG_enumeration_type) + /* If the die has a sibling, skip to the sibling. Do not skip + enumeration types, we want to record their enumerators. Do + not skip namespaces, we want to record symbols inside + them. */ + if (pdi.sibling + && pdi.tag != DW_TAG_enumeration_type + && pdi.tag != DW_TAG_namespace) { info_ptr = pdi.sibling; } else if (pdi.has_children) { - /* Die has children, but the optional DW_AT_sibling attribute - is missing. */ + /* Die has children, but either the optional DW_AT_sibling + attribute is missing or we want to look at them. */ nesting_level++; } if (pdi.tag == 0) { nesting_level--; + /* If this is the end of a DW_TAG_namespace entry, then + decrease the file_scope_level, too. */ + if (nesting_level < file_scope_level) + { + file_scope_level--; + gdb_assert (nesting_level == file_scope_level); + } } } @@ -1389,7 +1503,7 @@ add_partial_symbol (struct partial_die_info *pdi, struct objfile *objfile, /*prim_record_minimal_symbol (pdi->name, pdi->lowpc + baseaddr, mst_text, objfile); */ add_psymbol_to_list (pdi->name, strlen (pdi->name), - VAR_NAMESPACE, LOC_BLOCK, + VAR_DOMAIN, LOC_BLOCK, &objfile->global_psymbols, 0, pdi->lowpc + baseaddr, cu_language, objfile); } @@ -1398,7 +1512,7 @@ add_partial_symbol (struct partial_die_info *pdi, struct objfile *objfile, /*prim_record_minimal_symbol (pdi->name, pdi->lowpc + baseaddr, mst_file_text, objfile); */ add_psymbol_to_list (pdi->name, strlen (pdi->name), - VAR_NAMESPACE, LOC_BLOCK, + VAR_DOMAIN, LOC_BLOCK, &objfile->static_psymbols, 0, pdi->lowpc + baseaddr, cu_language, objfile); } @@ -1423,7 +1537,7 @@ add_partial_symbol (struct partial_die_info *pdi, struct objfile *objfile, addr = decode_locdesc (pdi->locdesc, objfile, cu_header); if (pdi->locdesc || pdi->has_type) add_psymbol_to_list (pdi->name, strlen (pdi->name), - VAR_NAMESPACE, LOC_STATIC, + VAR_DOMAIN, LOC_STATIC, &objfile->global_psymbols, 0, addr + baseaddr, cu_language, objfile); } @@ -1436,7 +1550,7 @@ add_partial_symbol (struct partial_die_info *pdi, struct objfile *objfile, /*prim_record_minimal_symbol (pdi->name, addr + baseaddr, mst_file_data, objfile); */ add_psymbol_to_list (pdi->name, strlen (pdi->name), - VAR_NAMESPACE, LOC_STATIC, + VAR_DOMAIN, LOC_STATIC, &objfile->static_psymbols, 0, addr + baseaddr, cu_language, objfile); } @@ -1444,7 +1558,7 @@ add_partial_symbol (struct partial_die_info *pdi, struct objfile *objfile, case DW_TAG_typedef: case DW_TAG_base_type: add_psymbol_to_list (pdi->name, strlen (pdi->name), - VAR_NAMESPACE, LOC_TYPEDEF, + VAR_DOMAIN, LOC_TYPEDEF, &objfile->static_psymbols, 0, (CORE_ADDR) 0, cu_language, objfile); break; @@ -1457,7 +1571,7 @@ add_partial_symbol (struct partial_die_info *pdi, struct objfile *objfile, if (pdi->has_children == 0) return; add_psymbol_to_list (pdi->name, strlen (pdi->name), - STRUCT_NAMESPACE, LOC_TYPEDEF, + STRUCT_DOMAIN, LOC_TYPEDEF, &objfile->static_psymbols, 0, (CORE_ADDR) 0, cu_language, objfile); @@ -1465,14 +1579,14 @@ add_partial_symbol (struct partial_die_info *pdi, struct objfile *objfile, { /* For C++, these implicitly act as typedefs as well. */ add_psymbol_to_list (pdi->name, strlen (pdi->name), - VAR_NAMESPACE, LOC_TYPEDEF, + VAR_DOMAIN, LOC_TYPEDEF, &objfile->static_psymbols, 0, (CORE_ADDR) 0, cu_language, objfile); } break; case DW_TAG_enumerator: add_psymbol_to_list (pdi->name, strlen (pdi->name), - VAR_NAMESPACE, LOC_CONST, + VAR_DOMAIN, LOC_CONST, &objfile->static_psymbols, 0, (CORE_ADDR) 0, cu_language, objfile); break; @@ -1523,6 +1637,7 @@ psymtab_to_symtab_1 (struct partial_symtab *pst) char *info_ptr; struct symtab *symtab; struct cleanup *back_to; + struct attribute *attr; /* Set local variables from the partial symbol table info. */ offset = DWARF_INFO_OFFSET (pst); @@ -1535,6 +1650,10 @@ psymtab_to_symtab_1 (struct partial_symtab *pst) dwarf_str_size = DWARF_STR_SIZE (pst); dwarf_macinfo_buffer = DWARF_MACINFO_BUFFER (pst); dwarf_macinfo_size = DWARF_MACINFO_SIZE (pst); + dwarf_ranges_buffer = DWARF_RANGES_BUFFER (pst); + dwarf_ranges_size = DWARF_RANGES_SIZE (pst); + dwarf_loc_buffer = DWARF_LOC_BUFFER (pst); + dwarf_loc_size = DWARF_LOC_SIZE (pst); baseaddr = ANOFFSET (pst->section_offsets, SECT_OFF_TEXT (objfile)); cu_header_offset = offset; info_ptr = dwarf_info_buffer + offset; @@ -1549,17 +1668,42 @@ psymtab_to_symtab_1 (struct partial_symtab *pst) info_ptr = read_comp_unit_head (&cu_header, info_ptr, abfd); /* Read the abbrevs for this compilation unit */ - dwarf2_read_abbrevs (abfd, cu_header.abbrev_offset); - make_cleanup (dwarf2_empty_abbrev_table, NULL); + dwarf2_read_abbrevs (abfd, &cu_header); + make_cleanup (dwarf2_empty_abbrev_table, cu_header.dwarf2_abbrevs); dies = read_comp_unit (info_ptr, abfd, &cu_header); make_cleanup_free_die_list (dies); + /* Find the base address of the compilation unit for range lists and + location lists. It will normally be specified by DW_AT_low_pc. + In DWARF-3 draft 4, the base address could be overridden by + 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; + + attr = dwarf_attr (dies, DW_AT_entry_pc); + if (attr) + { + cu_header.base_address = DW_ADDR (attr); + cu_header.base_known = 1; + } + else + { + attr = dwarf_attr (dies, DW_AT_low_pc); + if (attr) + { + cu_header.base_address = DW_ADDR (attr); + cu_header.base_known = 1; + } + } + /* Do line number decoding in read_file_scope () */ process_die (dies, objfile, &cu_header); - if (!dwarf2_get_pc_bounds (dies, &lowpc, &highpc, objfile)) + if (!dwarf2_get_pc_bounds (dies, &lowpc, &highpc, objfile, &cu_header)) { /* Some compilers don't define a DW_AT_high_pc attribute for the compilation unit. If the DW_AT_high_pc is missing, @@ -1574,7 +1718,8 @@ psymtab_to_symtab_1 (struct partial_symtab *pst) { CORE_ADDR low, high; - if (dwarf2_get_pc_bounds (child_die, &low, &high, objfile)) + if (dwarf2_get_pc_bounds (child_die, &low, &high, + objfile, &cu_header)) { highpc = max (highpc, high); } @@ -1595,7 +1740,6 @@ psymtab_to_symtab_1 (struct partial_symtab *pst) } pst->symtab = symtab; pst->readin = 1; - sort_symtab_syms (pst->symtab); do_cleanups (back_to); } @@ -1623,6 +1767,8 @@ process_die (struct die_info *die, struct objfile *objfile, of a function and make GDB `next' properly over inlined functions. */ break; case DW_TAG_lexical_block: + case DW_TAG_try_block: + case DW_TAG_catch_block: read_lexical_block_scope (die, objfile, cu_header); break; case DW_TAG_class_type: @@ -1664,6 +1810,29 @@ process_die (struct die_info *die, struct objfile *objfile, break; case DW_TAG_common_inclusion: break; + case DW_TAG_namespace: + if (!processing_has_namespace_info) + { + processing_has_namespace_info = 1; + processing_current_namespace = ""; + } + read_namespace (die, objfile, cu_header); + break; + case DW_TAG_imported_declaration: + case DW_TAG_imported_module: + /* FIXME: carlton/2002-10-16: Eventually, we should use the + information contained in these. DW_TAG_imported_declaration + dies shouldn't have children; DW_TAG_imported_module dies + shouldn't in the C++ case, but conceivably could in the + Fortran case, so we'll have to replace this gdb_assert if + Fortran compilers start generating that info. */ + if (!processing_has_namespace_info) + { + processing_has_namespace_info = 1; + processing_current_namespace = ""; + } + gdb_assert (!die->has_children); + break; default: new_symbol (die, NULL, objfile, cu_header); break; @@ -1690,7 +1859,7 @@ read_file_scope (struct die_info *die, struct objfile *objfile, bfd *abfd = objfile->obfd; struct line_header *line_header = 0; - if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, objfile)) + if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, objfile, cu_header)) { if (die->has_children) { @@ -1701,7 +1870,8 @@ read_file_scope (struct die_info *die, struct objfile *objfile, { CORE_ADDR low, high; - if (dwarf2_get_pc_bounds (child_die, &low, &high, objfile)) + if (dwarf2_get_pc_bounds (child_die, &low, &high, + objfile, cu_header)) { lowpc = min (lowpc, low); highpc = max (highpc, high); @@ -1802,7 +1972,7 @@ read_file_scope (struct die_info *die, struct objfile *objfile, header, so we can only read it if we've read the header successfully. */ attr = dwarf_attr (die, DW_AT_macro_info); - if (attr) + if (attr && line_header) { unsigned int macro_offset = DW_UNSND (attr); dwarf_decode_macros (line_header, macro_offset, @@ -1847,7 +2017,7 @@ read_func_scope (struct die_info *die, struct objfile *objfile, /* Ignore functions with missing or empty names and functions with missing or invalid low and high pc attributes. */ - if (name == NULL || !dwarf2_get_pc_bounds (die, &lowpc, &highpc, objfile)) + if (name == NULL || !dwarf2_get_pc_bounds (die, &lowpc, &highpc, objfile, cu_header)) return; lowpc += baseaddr; @@ -1870,9 +2040,26 @@ read_func_scope (struct die_info *die, struct objfile *objfile, attr = dwarf_attr (die, DW_AT_frame_base); if (attr) { - CORE_ADDR addr = decode_locdesc (DW_BLOCK (attr), objfile, cu_header); + CORE_ADDR addr; + + /* Support the .debug_loc offsets */ + if (attr_form_is_block (attr)) + { + addr = decode_locdesc (DW_BLOCK (attr), objfile, cu_header); + } + else if (attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8) + { + dwarf2_complex_location_expr_complaint (); + addr = 0; + } + else + { + dwarf2_invalid_attrib_class_complaint ("DW_AT_frame_base", name); + addr = 0; + } + if (isderef) - complain (&dwarf2_unsupported_at_frame_base, name); + dwarf2_unsupported_at_frame_base_complaint (name); else if (isreg) frame_base_reg = addr; else if (offreg) @@ -1881,11 +2068,18 @@ read_func_scope (struct die_info *die, struct objfile *objfile, frame_base_offset = addr; } else - complain (&dwarf2_unsupported_at_frame_base, name); + dwarf2_unsupported_at_frame_base_complaint (name); } new = push_context (0, lowpc); new->name = new_symbol (die, die->type, objfile, cu_header); + + /* If there was a location expression for DW_AT_frame_base above, + record it. We still need to decode it above because not all + symbols use location expressions exclusively. */ + if (attr) + dwarf2_symbol_mark_computed (attr, new->name, cu_header, objfile); + list_in_scope = &local_symbols; if (die->has_children) @@ -1902,7 +2096,18 @@ read_func_scope (struct die_info *die, struct objfile *objfile, /* Make a block for the local symbols within. */ finish_block (new->name, &local_symbols, new->old_blocks, lowpc, highpc, objfile); - list_in_scope = &file_symbols; + + /* 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 + back to building a containing block's symbol lists. */ + local_symbols = new->locals; + param_symbols = new->params; + + /* If we've finished processing a top-level function, subsequent + symbols go in the file symbol list. */ + if (outermost_context_p ()) + list_in_scope = &file_symbols; } /* Process all the DIES contained within a lexical block scope. Start @@ -1917,7 +2122,11 @@ read_lexical_block_scope (struct die_info *die, struct objfile *objfile, struct die_info *child_die; /* Ignore blocks with missing or invalid low and high pc attributes. */ - if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, objfile)) + /* ??? Perhaps consider discontiguous blocks defined by DW_AT_ranges + as multiple lexical blocks? Handling children in a sane way would + be nasty. Might be easier to properly extend generic blocks to + describe ranges. */ + if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, objfile, cu_header)) return; lowpc += baseaddr; highpc += baseaddr; @@ -1942,27 +2151,140 @@ read_lexical_block_scope (struct die_info *die, struct objfile *objfile, local_symbols = new->locals; } -/* Get low and high pc attributes from a die. - Return 1 if the attributes are present and valid, otherwise, return 0. */ - +/* Get low and high pc attributes from a die. Return 1 if the attributes + are present and valid, otherwise, return 0. Return -1 if the range is + discontinuous, i.e. derived from DW_AT_ranges information. */ static int -dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc, CORE_ADDR *highpc, - struct objfile *objfile) +dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc, + CORE_ADDR *highpc, struct objfile *objfile, + const struct comp_unit_head *cu_header) { struct attribute *attr; - CORE_ADDR low; - CORE_ADDR high; + bfd *obfd = objfile->obfd; + CORE_ADDR low = 0; + CORE_ADDR high = 0; + int ret = 0; - attr = dwarf_attr (die, DW_AT_low_pc); - if (attr) - low = DW_ADDR (attr); - else - return 0; attr = dwarf_attr (die, DW_AT_high_pc); if (attr) - high = DW_ADDR (attr); + { + high = DW_ADDR (attr); + attr = dwarf_attr (die, DW_AT_low_pc); + if (attr) + low = DW_ADDR (attr); + else + /* Found high w/o low attribute. */ + return 0; + + /* Found consecutive range of addresses. */ + ret = 1; + } else - return 0; + { + attr = dwarf_attr (die, DW_AT_ranges); + if (attr != NULL) + { + unsigned int addr_size = cu_header->addr_size; + CORE_ADDR mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1)); + /* Value of the DW_AT_ranges attribute is the offset in the + .debug_renges section. */ + unsigned int offset = DW_UNSND (attr); + /* Base address selection entry. */ + CORE_ADDR base; + int found_base; + int dummy; + unsigned int i; + char *buffer; + CORE_ADDR marker; + int low_set; + + found_base = cu_header->base_known; + base = cu_header->base_address; + buffer = dwarf_ranges_buffer + offset; + + /* Read in the largest possible address. */ + marker = read_address (obfd, buffer, cu_header, &dummy); + if ((marker & mask) == mask) + { + /* If we found the largest possible address, then + read the base address. */ + base = read_address (obfd, buffer + addr_size, + cu_header, &dummy); + buffer += 2 * addr_size; + offset += 2 * addr_size; + found_base = 1; + } + + low_set = 0; + + while (1) + { + CORE_ADDR range_beginning, range_end; + + range_beginning = read_address (obfd, buffer, + cu_header, &dummy); + buffer += addr_size; + range_end = read_address (obfd, buffer, cu_header, &dummy); + buffer += addr_size; + offset += 2 * addr_size; + + /* An end of list marker is a pair of zero addresses. */ + if (range_beginning == 0 && range_end == 0) + /* Found the end of list entry. */ + break; + + /* Each base address selection entry is a pair of 2 values. + The first is the largest possible address, the second is + the base address. Check for a base address here. */ + if ((range_beginning & mask) == mask) + { + /* If we found the largest possible address, then + read the base address. */ + base = read_address (obfd, buffer + addr_size, + cu_header, &dummy); + found_base = 1; + continue; + } + + if (!found_base) + { + /* We have no valid base address for the ranges + data. */ + complaint (&symfile_complaints, + "Invalid .debug_ranges data (no base address)"); + return 0; + } + + range_beginning += base; + range_end += base; + + /* FIXME: This is recording everything as a low-high + segment of consecutive addresses. We should have a + data structure for discontiguous block ranges + instead. */ + if (! low_set) + { + low = range_beginning; + high = range_end; + low_set = 1; + } + else + { + if (range_beginning < low) + low = range_beginning; + if (range_end > high) + high = range_end; + } + } + + if (! low_set) + /* If the first entry is an end-of-list marker, the range + describes an empty scope, i.e. no instructions. */ + return 0; + + ret = -1; + } + } if (high < low) return 0; @@ -1975,12 +2297,12 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc, CORE_ADDR *highpc, labels are not in the output, so the relocs get a value of 0. If this is a discarded function, mark the pc bounds as invalid, so that GDB will ignore it. */ - if (low == 0 && (bfd_get_file_flags (objfile->obfd) & HAS_RELOC) == 0) + if (low == 0 && (bfd_get_file_flags (obfd) & HAS_RELOC) == 0) return 0; *lowpc = low; *highpc = high; - return 1; + return ret; } /* Add an aggregate field to the field list. */ @@ -2022,11 +2344,16 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die, new_field->virtuality = DW_UNSND (attr); fp = &new_field->field; - if (die->tag == DW_TAG_member) + + if (die->tag == DW_TAG_member && ! die_is_declaration (die)) { + /* Data member other than a C++ static data member. */ + /* Get type of field. */ fp->type = die_type (die, objfile, cu_header); + FIELD_STATIC_KIND (*fp) = 0; + /* Get bit size of field (zero if none). */ attr = dwarf_attr (die, DW_AT_bit_size); if (attr) @@ -2106,12 +2433,18 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die, fip->non_public_fields = 1; } } - else if (die->tag == DW_TAG_variable) + else if (die->tag == DW_TAG_member || die->tag == DW_TAG_variable) { + /* C++ static member. */ + + /* NOTE: carlton/2002-11-05: It should be a DW_TAG_member that + is a declaration, but all versions of G++ as of this writing + (so through at least 3.2.1) incorrectly generate + DW_TAG_variable tags. */ + char *physname; - /* C++ static member. - Get name of field. */ + /* Get name of field. */ attr = dwarf_attr (die, DW_AT_name); if (attr && DW_STRING (attr)) fieldname = DW_STRING (attr); @@ -2135,6 +2468,7 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die, FIELD_BITPOS (*fp) = (decode_locdesc (DW_BLOCK (attr), objfile, cu_header) * bits_per_byte); FIELD_BITSIZE (*fp) = 0; + FIELD_STATIC_KIND (*fp) = 0; FIELD_TYPE (*fp) = die_type (die, objfile, cu_header); FIELD_NAME (*fp) = type_name_no_tag (fp->type); fip->nbaseclasses++; @@ -2209,8 +2543,8 @@ dwarf2_attach_fields_to_type (struct field_info *fip, struct type *type, default: /* Unknown accessibility. Complain and treat it as public. */ { - complain (&dwarf2_unsupported_accessibility, - fip->fields->accessibility); + complaint (&symfile_complaints, "unsupported accessibility %d", + fip->fields->accessibility); } break; } @@ -2232,7 +2566,7 @@ dwarf2_attach_fields_to_type (struct field_info *fip, struct type *type, static void dwarf2_add_member_fn (struct field_info *fip, struct die_info *die, - struct objfile *objfile, + struct type *type, struct objfile *objfile, const struct comp_unit_head *cu_header) { struct attribute *attr; @@ -2300,7 +2634,9 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die, struct type *return_type = TYPE_TARGET_TYPE (die->type); int nparams = TYPE_NFIELDS (die->type); - smash_to_method_type (fnp->type, die->type, + /* TYPE is the domain of this method, and DIE->TYPE is the type + of the method itself (TYPE_CODE_METHOD). */ + smash_to_method_type (fnp->type, type, TYPE_TARGET_TYPE (die->type), TYPE_FIELDS (die->type), TYPE_NFIELDS (die->type), @@ -2316,7 +2652,8 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die, fnp->voffset = VOFFSET_STATIC; } else - complain (&dwarf2_missing_member_fn_type_complaint, physname); + complaint (&symfile_complaints, "member function type missing for '%s'", + physname); /* Get fcontext from DW_AT_containing_type if present. */ if (dwarf_attr (die, DW_AT_containing_type) != NULL) @@ -2348,7 +2685,22 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die, /* Get index in virtual function table if it is a virtual member function. */ attr = dwarf_attr (die, DW_AT_vtable_elem_location); if (attr) - fnp->voffset = decode_locdesc (DW_BLOCK (attr), objfile, cu_header) + 2; + { + /* Support the .debug_loc offsets */ + if (attr_form_is_block (attr)) + { + fnp->voffset = decode_locdesc (DW_BLOCK (attr), objfile, cu_header) + 2; + } + else if (attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8) + { + dwarf2_complex_location_expr_complaint (); + } + else + { + dwarf2_invalid_attrib_class_complaint ("DW_AT_vtable_elem_location", + fieldname); + } + } } /* Create the vector of member function fields, and attach it to the type. */ @@ -2461,20 +2813,21 @@ read_structure_scope (struct die_info *die, struct objfile *objfile, while (child_die && child_die->tag) { - if (child_die->tag == DW_TAG_member) - { - dwarf2_add_field (&fi, child_die, objfile, cu_header); - } - else if (child_die->tag == DW_TAG_variable) + if (child_die->tag == DW_TAG_member + || child_die->tag == DW_TAG_variable) { - /* C++ static member. */ + /* NOTE: carlton/2002-11-05: A C++ static data member + should be a DW_TAG_member that is a declaration, but + all versions of G++ as of this writing (so through at + least 3.2.1) incorrectly generate DW_TAG_variable + tags for them instead. */ dwarf2_add_field (&fi, child_die, objfile, cu_header); } else if (child_die->tag == DW_TAG_subprogram) { /* C++ member function. */ process_die (child_die, objfile, cu_header); - dwarf2_add_member_fn (&fi, child_die, objfile, cu_header); + dwarf2_add_member_fn (&fi, child_die, type, objfile, cu_header); } else if (child_die->tag == DW_TAG_inheritance) { @@ -2527,8 +2880,10 @@ read_structure_scope (struct die_info *die, struct objfile *objfile, /* Complain if virtual function table field not found. */ if (i < TYPE_N_BASECLASSES (t)) - complain (&dwarf2_vtbl_not_found_complaint, - TYPE_TAG_NAME (type) ? TYPE_TAG_NAME (type) : ""); + complaint (&symfile_complaints, + "virtual function table pointer not found when defining class '%s'", + TYPE_TAG_NAME (type) ? TYPE_TAG_NAME (type) : + ""); } else { @@ -2618,10 +2973,11 @@ read_enumeration (struct die_info *die, struct objfile *objfile, * sizeof (struct field)); } - FIELD_NAME (fields[num_fields]) = SYMBOL_NAME (sym); + FIELD_NAME (fields[num_fields]) = DEPRECATED_SYMBOL_NAME (sym); FIELD_TYPE (fields[num_fields]) = NULL; FIELD_BITPOS (fields[num_fields]) = SYMBOL_VALUE (sym); FIELD_BITSIZE (fields[num_fields]) = 0; + FIELD_STATIC_KIND (fields[num_fields]) = 0; num_fields++; } @@ -2715,8 +3071,8 @@ read_array_type (struct die_info *die, struct objfile *objfile, } else { - complain (&dwarf2_non_const_array_bound_ignored, - dwarf_form_name (attr->form)); + dwarf2_non_const_array_bound_ignored_complaint + (dwarf_form_name (attr->form)); #ifdef FORTRAN_HACK die->type = lookup_pointer_type (element_type); return; @@ -2751,8 +3107,8 @@ read_array_type (struct die_info *die, struct objfile *objfile, } else { - complain (&dwarf2_non_const_array_bound_ignored, - dwarf_form_name (attr->form)); + dwarf2_non_const_array_bound_ignored_complaint + (dwarf_form_name (attr->form)); #ifdef FORTRAN_HACK die->type = lookup_pointer_type (element_type); return; @@ -2812,7 +3168,20 @@ read_common_block (struct die_info *die, struct objfile *objfile, attr = dwarf_attr (die, DW_AT_location); if (attr) { - base = decode_locdesc (DW_BLOCK (attr), objfile, cu_header); + /* Support the .debug_loc offsets */ + if (attr_form_is_block (attr)) + { + base = decode_locdesc (DW_BLOCK (attr), objfile, cu_header); + } + else if (attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8) + { + dwarf2_complex_location_expr_complaint (); + } + else + { + dwarf2_invalid_attrib_class_complaint ("DW_AT_location", + "common block member"); + } } if (die->has_children) { @@ -2832,6 +3201,75 @@ read_common_block (struct die_info *die, struct objfile *objfile, } } +/* Read a C++ namespace. */ + +static void +read_namespace (struct die_info *die, struct objfile *objfile, + const struct comp_unit_head *cu_header) +{ + const char *previous_namespace = processing_current_namespace; + const char *name = NULL; + int is_anonymous; + struct die_info *current_die; + + /* Loop through the extensions until we find a name. */ + + for (current_die = die; + current_die != NULL; + current_die = dwarf2_extension (die)) + { + name = dwarf2_name (current_die); + if (name != NULL) + break; + } + + /* Is it an anonymous namespace? */ + + is_anonymous = (name == NULL); + if (is_anonymous) + name = "(anonymous namespace)"; + + /* Now build the name of the current namespace. */ + + if (previous_namespace[0] == '\0') + { + processing_current_namespace = name; + } + else + { + /* We need temp_name around because processing_current_namespace + is a const char *. */ + char *temp_name = alloca (strlen (previous_namespace) + + 2 + strlen(name) + 1); + strcpy (temp_name, previous_namespace); + strcat (temp_name, "::"); + strcat (temp_name, name); + + processing_current_namespace = temp_name; + } + + /* If it's an anonymous namespace that we're seeing for the first + time, add a using directive. */ + + if (is_anonymous && dwarf_attr (die, DW_AT_extension) == NULL) + cp_add_using_directive (processing_current_namespace, + strlen (previous_namespace), + strlen (processing_current_namespace)); + + if (die->has_children) + { + struct die_info *child_die = die->next; + + while (child_die && child_die->tag) + { + process_die (child_die, objfile, cu_header); + child_die = sibling_die (child_die); + } + } + + processing_current_namespace = previous_namespace; +} + /* Extract all information from a DW_TAG_pointer_type DIE and add to the user defined type vector. */ @@ -2840,7 +3278,9 @@ read_tag_pointer_type (struct die_info *die, struct objfile *objfile, const struct comp_unit_head *cu_header) { struct type *type; - struct attribute *attr; + struct attribute *attr_byte_size; + struct attribute *attr_address_class; + int byte_size, addr_class; if (die->type) { @@ -2848,15 +3288,42 @@ read_tag_pointer_type (struct die_info *die, struct objfile *objfile, } type = lookup_pointer_type (die_type (die, objfile, cu_header)); - attr = dwarf_attr (die, DW_AT_byte_size); - if (attr) - { - TYPE_LENGTH (type) = DW_UNSND (attr); - } + + attr_byte_size = dwarf_attr (die, DW_AT_byte_size); + if (attr_byte_size) + byte_size = DW_UNSND (attr_byte_size); + else + byte_size = cu_header->addr_size; + + attr_address_class = dwarf_attr (die, DW_AT_address_class); + if (attr_address_class) + addr_class = DW_UNSND (attr_address_class); else + addr_class = DW_ADDR_none; + + /* If the pointer size or address class is different than the + default, create a type variant marked as such and set the + length accordingly. */ + if (TYPE_LENGTH (type) != byte_size || addr_class != DW_ADDR_none) { - TYPE_LENGTH (type) = cu_header->addr_size; + if (ADDRESS_CLASS_TYPE_FLAGS_P ()) + { + int type_flags; + + type_flags = ADDRESS_CLASS_TYPE_FLAGS (byte_size, addr_class); + gdb_assert ((type_flags & ~TYPE_FLAG_ADDRESS_CLASS_ALL) == 0); + type = make_type_with_address_space (type, type_flags); + } + else if (TYPE_LENGTH (type) != 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; } @@ -3152,8 +3619,8 @@ read_base_type (struct die_info *die, struct objfile *objfile) type_flags |= TYPE_FLAG_UNSIGNED; break; default: - complain (&dwarf2_unsupported_at_encoding, - dwarf_type_encoding_name (encoding)); + complaint (&symfile_complaints, "unsupported DW_AT_encoding: '%s'", + dwarf_type_encoding_name (encoding)); break; } type = init_type (code, size, type_flags, DW_STRING (attr), objfile); @@ -3262,15 +3729,20 @@ make_cleanup_free_die_list (struct die_info *dies) char * dwarf2_read_section (struct objfile *objfile, file_ptr offset, - unsigned int size) + unsigned int size, asection *sectp) { bfd *abfd = objfile->obfd; - char *buf; + char *buf, *retbuf; if (size == 0) return NULL; buf = (char *) obstack_alloc (&objfile->psymbol_obstack, size); + retbuf + = (char *) symfile_relocate_debug_section (abfd, sectp, (bfd_byte *) buf); + if (retbuf != NULL) + return retbuf; + if ((bfd_seek (abfd, offset, SEEK_SET) != 0) || (bfd_bread (buf, size, abfd) != size)) { @@ -3287,17 +3759,18 @@ dwarf2_read_section (struct objfile *objfile, file_ptr offset, in a hash table. */ static void -dwarf2_read_abbrevs (bfd *abfd, unsigned int offset) +dwarf2_read_abbrevs (bfd *abfd, struct comp_unit_head *cu_header) { char *abbrev_ptr; struct abbrev_info *cur_abbrev; unsigned int abbrev_number, bytes_read, abbrev_name; unsigned int abbrev_form, hash_number; - /* empty the table */ - dwarf2_empty_abbrev_table (NULL); + /* Initialize dwarf2 abbrevs */ + memset (cu_header->dwarf2_abbrevs, 0, + ABBREV_HASH_SIZE*sizeof (struct abbrev_info *)); - abbrev_ptr = dwarf_abbrev_buffer + offset; + abbrev_ptr = dwarf_abbrev_buffer + cu_header->abbrev_offset; abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); abbrev_ptr += bytes_read; @@ -3336,8 +3809,8 @@ dwarf2_read_abbrevs (bfd *abfd, unsigned int offset) } hash_number = abbrev_number % ABBREV_HASH_SIZE; - cur_abbrev->next = dwarf2_abbrevs[hash_number]; - dwarf2_abbrevs[hash_number] = cur_abbrev; + cur_abbrev->next = cu_header->dwarf2_abbrevs[hash_number]; + cu_header->dwarf2_abbrevs[hash_number] = cur_abbrev; /* Get next abbreviation. Under Irix6 the abbreviations for a compilation unit are not @@ -3351,7 +3824,7 @@ dwarf2_read_abbrevs (bfd *abfd, unsigned int offset) break; abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); abbrev_ptr += bytes_read; - if (dwarf2_lookup_abbrev (abbrev_number) != NULL) + if (dwarf2_lookup_abbrev (abbrev_number, cu_header) != NULL) break; } } @@ -3360,15 +3833,18 @@ dwarf2_read_abbrevs (bfd *abfd, unsigned int offset) /* ARGSUSED */ static void -dwarf2_empty_abbrev_table (PTR ignore) +dwarf2_empty_abbrev_table (void *ptr_to_abbrevs_table) { int i; struct abbrev_info *abbrev, *next; + struct abbrev_info **abbrevs; + + abbrevs = (struct abbrev_info **)ptr_to_abbrevs_table; for (i = 0; i < ABBREV_HASH_SIZE; ++i) { next = NULL; - abbrev = dwarf2_abbrevs[i]; + abbrev = abbrevs[i]; while (abbrev) { next = abbrev->next; @@ -3376,20 +3852,20 @@ dwarf2_empty_abbrev_table (PTR ignore) xfree (abbrev); abbrev = next; } - dwarf2_abbrevs[i] = NULL; + abbrevs[i] = NULL; } } /* Lookup an abbrev_info structure in the abbrev hash table. */ static struct abbrev_info * -dwarf2_lookup_abbrev (unsigned int number) +dwarf2_lookup_abbrev (unsigned int number, const struct comp_unit_head *cu_header) { unsigned int hash_number; struct abbrev_info *abbrev; hash_number = number % ABBREV_HASH_SIZE; - abbrev = dwarf2_abbrevs[hash_number]; + abbrev = cu_header->dwarf2_abbrevs[hash_number]; while (abbrev) { @@ -3421,10 +3897,11 @@ read_partial_die (struct partial_die_info *part_die, bfd *abfd, if (!abbrev_number) return info_ptr; - abbrev = dwarf2_lookup_abbrev (abbrev_number); + abbrev = dwarf2_lookup_abbrev (abbrev_number, cu_header); if (!abbrev) { - error ("Dwarf Error: Could not find abbrev number %d.", abbrev_number); + error ("Dwarf Error: Could not find abbrev number %d [in module %s]", abbrev_number, + bfd_get_filename (abfd)); } part_die->offset = info_ptr - dwarf_info_buffer; part_die->tag = abbrev->tag; @@ -3458,7 +3935,20 @@ read_partial_die (struct partial_die_info *part_die, bfd *abfd, part_die->highpc = DW_ADDR (&attr); break; case DW_AT_location: - part_die->locdesc = DW_BLOCK (&attr); + /* Support the .debug_loc offsets */ + if (attr_form_is_block (&attr)) + { + part_die->locdesc = DW_BLOCK (&attr); + } + else if (attr.form == DW_FORM_data4 || attr.form == DW_FORM_data8) + { + dwarf2_complex_location_expr_complaint (); + } + else + { + dwarf2_invalid_attrib_class_complaint ("DW_AT_location", + "partial symbol information"); + } break; case DW_AT_language: part_die->language = DW_UNSND (&attr); @@ -3481,7 +3971,7 @@ read_partial_die (struct partial_die_info *part_die, bfd *abfd, /* Ignore absolute siblings, they might point outside of the current compile unit. */ if (attr.form == DW_FORM_ref_addr) - complain (&dwarf2_absolute_sibling_complaint); + complaint (&symfile_complaints, "ignoring absolute DW_AT_sibling"); else part_die->sibling = dwarf_info_buffer + dwarf2_get_ref_die_offset (&attr); @@ -3552,10 +4042,11 @@ read_full_die (struct die_info **diep, bfd *abfd, char *info_ptr, return info_ptr; } - abbrev = dwarf2_lookup_abbrev (abbrev_number); + abbrev = dwarf2_lookup_abbrev (abbrev_number, cu_header); if (!abbrev) { - error ("Dwarf Error: could not find abbrev number %d.", abbrev_number); + error ("Dwarf Error: could not find abbrev number %d [in module %s]", abbrev_number, + bfd_get_filename (abfd)); } die = dwarf_alloc_die (); die->offset = offset; @@ -3691,8 +4182,9 @@ read_attribute_value (struct attribute *attr, unsigned form, info_ptr = read_attribute_value (attr, form, abfd, info_ptr, cu_header); break; default: - error ("Dwarf Error: Cannot handle %s in DWARF reader.", - dwarf_form_name (form)); + error ("Dwarf Error: Cannot handle %s in DWARF reader [in module %s]", + dwarf_form_name (form), + bfd_get_filename (abfd)); } return info_ptr; } @@ -3773,7 +4265,8 @@ read_address (bfd *abfd, char *buf, const struct comp_unit_head *cu_header, break; default: internal_error (__FILE__, __LINE__, - "read_address: bad switch, signed"); + "read_address: bad switch, signed [in module %s]", + bfd_get_filename (abfd)); } } else @@ -3791,7 +4284,8 @@ read_address (bfd *abfd, char *buf, const struct comp_unit_head *cu_header, break; default: internal_error (__FILE__, __LINE__, - "read_address: bad switch, unsigned"); + "read_address: bad switch, unsigned [in module %s]", + bfd_get_filename (abfd)); } } @@ -3799,12 +4293,25 @@ read_address (bfd *abfd, char *buf, const struct comp_unit_head *cu_header, return retval; } -/* Reads the initial length from a section. The (draft) DWARF 2.1 +/* Read the initial length from a section. The (draft) DWARF 3 specification allows the initial length to take up either 4 bytes or 12 bytes. If the first 4 bytes are 0xffffffff, then the next 8 bytes describe the length and all offsets will be 8 bytes in length instead of 4. + An older, non-standard 64-bit format is also handled by this + function. The older format in question stores the initial length + as an 8-byte quantity without an escape value. Lengths greater + than 2^32 aren't very common which means that the initial 4 bytes + is almost always zero. Since a length value of zero doesn't make + 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. + The value returned via bytes_read should be used to increment the relevant pointer after calling read_initial_length(). @@ -3815,14 +4322,18 @@ read_address (bfd *abfd, char *buf, const struct comp_unit_head *cu_header, [ Note: read_initial_length() and read_offset() are based on the document entitled "DWARF Debugging Information Format", revision - 2.1, draft 4, dated July 20, 2000. This document was obtained + 3, draft 8, dated November 19, 2001. This document was obtained from: - http://reality.sgi.com/dehnert_engr/dwarf/dwarf2p1-draft4-000720.pdf + http://reality.sgiweb.org/davea/dwarf3-draft8-011125.pdf This document is only a draft and is subject to change. (So beware.) - - Kevin, Aug 4, 2000 + 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. + + - Kevin, July 16, 2002 ] */ static LONGEST @@ -3843,6 +4354,18 @@ read_initial_length (bfd *abfd, char *buf, struct comp_unit_head *cu_header, cu_header->offset_size = 8; } } + else if (retval == 0) + { + /* Handle (non-standard) 64-bit DWARF2 formats such as that used + by IRIX. */ + retval = 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; @@ -3877,7 +4400,8 @@ read_offset (bfd *abfd, char *buf, const struct comp_unit_head *cu_header, break; default: internal_error (__FILE__, __LINE__, - "read_offset: bad switch"); + "read_offset: bad switch [in module %s]", + bfd_get_filename (abfd)); } return retval; @@ -3919,12 +4443,14 @@ read_indirect_string (bfd *abfd, char *buf, if (dwarf_str_buffer == NULL) { - error ("DW_FORM_strp used without .debug_str section"); + error ("DW_FORM_strp used without .debug_str section [in module %s]", + bfd_get_filename (abfd)); return NULL; } if (str_offset >= dwarf_str_size) { - error ("DW_FORM_strp pointing outside of .debug_str section"); + error ("DW_FORM_strp pointing outside of .debug_str section [in module %s]", + bfd_get_filename (abfd)); return NULL; } gdb_assert (HOST_CHAR_BIT == 8); @@ -4017,12 +4543,13 @@ set_cu_language (unsigned int lang) cu_language = language_java; break; case DW_LANG_Ada83: + case DW_LANG_Ada95: case DW_LANG_Cobol74: case DW_LANG_Cobol85: case DW_LANG_Pascal83: case DW_LANG_Modula2: default: - cu_language = language_unknown; + cu_language = language_minimal; break; } cu_language_defn = language_def (cu_language); @@ -4163,7 +4690,7 @@ dwarf_decode_line_header (unsigned int offset, bfd *abfd, if (dwarf_line_buffer == NULL) { - complain (&dwarf2_missing_line_number_section); + complaint (&symfile_complaints, "missing .debug_line section"); return 0; } @@ -4171,7 +4698,7 @@ dwarf_decode_line_header (unsigned int offset, bfd *abfd, could be 12 bytes long, but we're just going to fudge that. */ if (offset + 4 >= dwarf_line_size) { - complain (&dwarf2_statement_list_fits_in_line_number_section); + dwarf2_statement_list_fits_in_line_number_section_complaint (); return 0; } @@ -4187,7 +4714,7 @@ dwarf_decode_line_header (unsigned int offset, bfd *abfd, line_ptr += bytes_read; if (line_ptr + lh->total_length > dwarf_line_buffer + dwarf_line_size) { - complain (&dwarf2_statement_list_fits_in_line_number_section); + dwarf2_statement_list_fits_in_line_number_section_complaint (); return 0; } lh->statement_program_end = line_ptr + lh->total_length; @@ -4242,7 +4769,8 @@ dwarf_decode_line_header (unsigned int offset, bfd *abfd, lh->statement_program_start = line_ptr; if (line_ptr > dwarf_line_buffer + dwarf_line_size) - complain (&dwarf2_line_header_too_long); + complaint (&symfile_complaints, + "line number info header doesn't fit in `.debug_line' section"); discard_cleanups (back_to); return lh; @@ -4287,8 +4815,9 @@ check_cu_functions (CORE_ADDR address) if (fn->seen_line) return address; if (address != fn->lowpc) - complain (&dwarf2_misplaced_line_number, - (unsigned long) address, fn->name); + complaint (&symfile_complaints, + "misplaced first line number at 0x%lx for '%s'", + (unsigned long) address, fn->name); fn->seen_line = 1; return fn->lowpc; } @@ -4350,8 +4879,8 @@ dwarf_decode_lines (struct line_header *lh, char *comp_dir, bfd *abfd, * lh->minimum_instruction_length; line += lh->line_base + (adj_opcode % lh->line_range); /* append row to matrix using current values */ - address = check_cu_functions (address); - record_line (current_subfile, line, address); + record_line (current_subfile, line, + check_cu_functions (address)); basic_block = 1; } else switch (op_code) @@ -4391,13 +4920,14 @@ dwarf_decode_lines (struct line_header *lh, char *comp_dir, bfd *abfd, } break; default: - complain (&dwarf2_mangled_line_number_section); + complaint (&symfile_complaints, + "mangled .debug_line section"); return; } break; case DW_LNS_copy: - address = check_cu_functions (address); - record_line (current_subfile, line, address); + record_line (current_subfile, line, + check_cu_functions (address)); basic_block = 0; break; case DW_LNS_advance_pc: @@ -4508,6 +5038,61 @@ dwarf2_start_subfile (char *filename, char *dirname) start_subfile (filename, dirname); } +static void +var_decode_location (struct attribute *attr, struct symbol *sym, + struct objfile *objfile, + const struct comp_unit_head *cu_header) +{ + /* NOTE drow/2003-01-30: There used to be a comment and some special + code here to turn a symbol with DW_AT_external and a + SYMBOL_VALUE_ADDRESS of 0 into a LOC_UNRESOLVED symbol. This was + necessary for platforms (maybe Alpha, certainly PowerPC GNU/Linux + with some versions of binutils) where shared libraries could have + relocations against symbols in their debug information - the + minimal symbol would have the right address, but the debug info + would not. It's no longer necessary, because we will explicitly + apply relocations when we read in the debug information now. */ + + /* A DW_AT_location attribute with no contents indicates that a + variable has been optimized away. */ + if (attr_form_is_block (attr) && DW_BLOCK (attr)->size == 0) + { + SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT; + return; + } + + /* Handle one degenerate form of location expression specially, to + preserve GDB's previous behavior when section offsets are + specified. If this is just a DW_OP_addr then mark this symbol + as LOC_STATIC. */ + + if (attr_form_is_block (attr) + && DW_BLOCK (attr)->size == 1 + cu_header->addr_size + && DW_BLOCK (attr)->data[0] == DW_OP_addr) + { + int dummy; + + SYMBOL_VALUE_ADDRESS (sym) = + read_address (objfile->obfd, DW_BLOCK (attr)->data + 1, cu_header, + &dummy); + fixup_symbol_section (sym, objfile); + SYMBOL_VALUE_ADDRESS (sym) += ANOFFSET (objfile->section_offsets, + SYMBOL_SECTION (sym)); + SYMBOL_CLASS (sym) = LOC_STATIC; + return; + } + + /* NOTE drow/2002-01-30: It might be worthwhile to have a static + expression evaluator, and use LOC_COMPUTED only when necessary + (i.e. when the value of a register or memory location is + referenced, or a thread-local block, etc.). Then again, it might + not be worthwhile. I'm assuming that it isn't unless performance + or memory numbers show me otherwise. */ + + dwarf2_symbol_mark_computed (attr, sym, cu_header, objfile); + SYMBOL_CLASS (sym) = LOC_COMPUTED; +} + /* Given a pointer to a DWARF information entry, figure out if we need to make a symbol table entry for it, and if so, create a new entry and return a pointer to it. @@ -4522,7 +5107,7 @@ new_symbol (struct die_info *die, struct type *type, struct objfile *objfile, char *name; struct attribute *attr = NULL; struct attribute *attr2 = NULL; - CORE_ADDR addr; + CORE_ADDR addr = 0; name = dwarf2_linkage_name (die); if (name) @@ -4531,12 +5116,14 @@ new_symbol (struct die_info *die, struct type *type, struct objfile *objfile, sizeof (struct symbol)); OBJSTAT (objfile, n_syms++); memset (sym, 0, sizeof (struct symbol)); - SYMBOL_NAME (sym) = obsavestring (name, strlen (name), - &objfile->symbol_obstack); + + /* Cache this symbol's name and the name's demangled form (if any). */ + SYMBOL_LANGUAGE (sym) = cu_language; + SYMBOL_SET_NAMES (sym, name, strlen (name), objfile); /* Default assumptions. Use the passed type or decode it from the die. */ - SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_DOMAIN (sym) = VAR_DOMAIN; SYMBOL_CLASS (sym) = LOC_STATIC; if (type != NULL) SYMBOL_TYPE (sym) = type; @@ -4547,15 +5134,6 @@ new_symbol (struct die_info *die, struct type *type, struct objfile *objfile, { SYMBOL_LINE (sym) = DW_UNSND (attr); } - - /* If this symbol is from a C++ compilation, then attempt to - cache the demangled form for future reference. This is a - typical time versus space tradeoff, that was decided in favor - of time because it sped up C++ symbol lookups by a factor of - about 20. */ - - SYMBOL_LANGUAGE (sym) = cu_language; - SYMBOL_INIT_DEMANGLED_NAME (sym, &objfile->symbol_obstack); switch (die->tag) { case DW_TAG_label: @@ -4603,64 +5181,12 @@ new_symbol (struct die_info *die, struct type *type, struct objfile *objfile, attr = dwarf_attr (die, DW_AT_location); if (attr) { + var_decode_location (attr, sym, objfile, cu_header); attr2 = dwarf_attr (die, DW_AT_external); if (attr2 && (DW_UNSND (attr2) != 0)) - { - SYMBOL_VALUE_ADDRESS (sym) = - decode_locdesc (DW_BLOCK (attr), objfile, cu_header); - add_symbol_to_list (sym, &global_symbols); - - /* In shared libraries the address of the variable - in the location descriptor might still be relocatable, - so its value could be zero. - Enter the symbol as a LOC_UNRESOLVED symbol, if its - value is zero, the address of the variable will then - be determined from the minimal symbol table whenever - the variable is referenced. */ - if (SYMBOL_VALUE_ADDRESS (sym)) - { - fixup_symbol_section (sym, objfile); - SYMBOL_VALUE_ADDRESS (sym) += - ANOFFSET (objfile->section_offsets, - SYMBOL_SECTION (sym)); - SYMBOL_CLASS (sym) = LOC_STATIC; - } - else - SYMBOL_CLASS (sym) = LOC_UNRESOLVED; - } + add_symbol_to_list (sym, &global_symbols); else - { - SYMBOL_VALUE (sym) = addr = - decode_locdesc (DW_BLOCK (attr), objfile, cu_header); - add_symbol_to_list (sym, list_in_scope); - if (optimized_out) - { - SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT; - } - else if (isreg) - { - SYMBOL_CLASS (sym) = LOC_REGISTER; - SYMBOL_VALUE (sym) = - DWARF2_REG_TO_REGNUM (SYMBOL_VALUE (sym)); - } - else if (offreg) - { - SYMBOL_CLASS (sym) = LOC_BASEREG; - SYMBOL_BASEREG (sym) = DWARF2_REG_TO_REGNUM (basereg); - } - else if (islocal) - { - SYMBOL_CLASS (sym) = LOC_LOCAL; - } - else - { - fixup_symbol_section (sym, objfile); - SYMBOL_VALUE_ADDRESS (sym) = - addr + ANOFFSET (objfile->section_offsets, - SYMBOL_SECTION (sym)); - SYMBOL_CLASS (sym) = LOC_STATIC; - } - } + add_symbol_to_list (sym, list_in_scope); } else { @@ -4696,7 +5222,7 @@ new_symbol (struct die_info *die, struct type *type, struct objfile *objfile, if (isderef) { if (basereg != frame_base_reg) - complain (&dwarf2_complex_location_expr); + dwarf2_complex_location_expr_complaint (); SYMBOL_CLASS (sym) = LOC_REF_ARG; } else @@ -4727,7 +5253,7 @@ new_symbol (struct die_info *die, struct type *type, struct objfile *objfile, case DW_TAG_union_type: case DW_TAG_enumeration_type: SYMBOL_CLASS (sym) = LOC_TYPEDEF; - SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE; + SYMBOL_DOMAIN (sym) = STRUCT_DOMAIN; add_symbol_to_list (sym, list_in_scope); /* The semantics of C++ state that "struct foo { ... }" also @@ -4739,11 +5265,11 @@ new_symbol (struct die_info *die, struct type *type, struct objfile *objfile, obstack_alloc (&objfile->symbol_obstack, sizeof (struct symbol)); *typedef_sym = *sym; - SYMBOL_NAMESPACE (typedef_sym) = VAR_NAMESPACE; + SYMBOL_DOMAIN (typedef_sym) = VAR_DOMAIN; if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0) TYPE_NAME (SYMBOL_TYPE (sym)) = - obsavestring (SYMBOL_NAME (sym), - strlen (SYMBOL_NAME (sym)), + obsavestring (DEPRECATED_SYMBOL_NAME (sym), + strlen (DEPRECATED_SYMBOL_NAME (sym)), &objfile->type_obstack); add_symbol_to_list (typedef_sym, list_in_scope); } @@ -4751,7 +5277,7 @@ new_symbol (struct die_info *die, struct type *type, struct objfile *objfile, case DW_TAG_typedef: case DW_TAG_base_type: SYMBOL_CLASS (sym) = LOC_TYPEDEF; - SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_DOMAIN (sym) = VAR_DOMAIN; add_symbol_to_list (sym, list_in_scope); break; case DW_TAG_enumerator: @@ -4767,7 +5293,8 @@ new_symbol (struct die_info *die, struct type *type, struct objfile *objfile, trash data, but since we must specifically ignore things we don't recognize, there is nothing else we should do at this point. */ - complain (&dwarf2_unsupported_tag, dwarf_tag_name (die->tag)); + complaint (&symfile_complaints, "unsupported tag: '%s'", + dwarf_tag_name (die->tag)); break; } } @@ -4787,12 +5314,16 @@ dwarf2_const_value (struct attribute *attr, struct symbol *sym, { case DW_FORM_addr: if (TYPE_LENGTH (SYMBOL_TYPE (sym)) != cu_header->addr_size) - complain (&dwarf2_const_value_length_mismatch, SYMBOL_NAME (sym), - cu_header->addr_size, TYPE_LENGTH (SYMBOL_TYPE (sym))); + dwarf2_const_value_length_mismatch_complaint (DEPRECATED_SYMBOL_NAME (sym), + cu_header->addr_size, + TYPE_LENGTH (SYMBOL_TYPE + (sym))); SYMBOL_VALUE_BYTES (sym) = (char *) obstack_alloc (&objfile->symbol_obstack, cu_header->addr_size); - store_address (SYMBOL_VALUE_BYTES (sym), cu_header->addr_size, - DW_ADDR (attr)); + /* NOTE: cagney/2003-05-09: In-lined store_address call with + it's body - store_unsigned_integer. */ + store_unsigned_integer (SYMBOL_VALUE_BYTES (sym), cu_header->addr_size, + DW_ADDR (attr)); SYMBOL_CLASS (sym) = LOC_CONST_BYTES; break; case DW_FORM_block1: @@ -4801,8 +5332,10 @@ dwarf2_const_value (struct attribute *attr, struct symbol *sym, case DW_FORM_block: blk = DW_BLOCK (attr); if (TYPE_LENGTH (SYMBOL_TYPE (sym)) != blk->size) - complain (&dwarf2_const_value_length_mismatch, SYMBOL_NAME (sym), - blk->size, TYPE_LENGTH (SYMBOL_TYPE (sym))); + dwarf2_const_value_length_mismatch_complaint (DEPRECATED_SYMBOL_NAME (sym), + blk->size, + TYPE_LENGTH (SYMBOL_TYPE + (sym))); SYMBOL_VALUE_BYTES (sym) = (char *) obstack_alloc (&objfile->symbol_obstack, blk->size); memcpy (SYMBOL_VALUE_BYTES (sym), blk->data, blk->size); @@ -4838,8 +5371,9 @@ dwarf2_const_value (struct attribute *attr, struct symbol *sym, break; default: - complain (&dwarf2_unsupported_const_value_attr, - dwarf_form_name (attr->form)); + complaint (&symfile_complaints, + "unsupported const value attribute form: '%s'", + dwarf_form_name (attr->form)); SYMBOL_VALUE (sym) = 0; SYMBOL_CLASS (sym) = LOC_CONST; break; @@ -4892,7 +5426,8 @@ die_type (struct die_info *die, struct objfile *objfile, type_die = follow_die_ref (ref); if (!type_die) { - error ("Dwarf Error: Cannot find referent at offset %d.", ref); + error ("Dwarf Error: Cannot find referent at offset %d [in module %s]", + ref, objfile->name); return NULL; } } @@ -4900,7 +5435,8 @@ die_type (struct die_info *die, struct objfile *objfile, if (!type) { dump_die (type_die); - error ("Dwarf Error: Problem turning type die at offset into gdb type."); + error ("Dwarf Error: Problem turning type die at offset into gdb type [in module %s]", + objfile->name); } return type; } @@ -4924,7 +5460,8 @@ die_containing_type (struct die_info *die, struct objfile *objfile, type_die = follow_die_ref (ref); if (!type_die) { - error ("Dwarf Error: Cannot find referent at offset %d.", ref); + error ("Dwarf Error: Cannot find referent at offset %d [in module %s]", ref, + objfile->name); return NULL; } type = tag_type_to_type (type_die, objfile, cu_header); @@ -4933,7 +5470,8 @@ die_containing_type (struct die_info *die, struct objfile *objfile, { if (type_die) dump_die (type_die); - error ("Dwarf Error: Problem turning containing type into gdb type."); + error ("Dwarf Error: Problem turning containing type into gdb type [in module %s]", + objfile->name); } return type; } @@ -4970,7 +5508,8 @@ tag_type_to_type (struct die_info *die, struct objfile *objfile, if (!die->type) { dump_die (die); - error ("Dwarf Error: Cannot find type of die."); + error ("Dwarf Error: Cannot find type of die [in module %s]", + objfile->name); } return die->type; } @@ -5022,7 +5561,8 @@ read_type_die (struct die_info *die, struct objfile *objfile, read_base_type (die, objfile); break; default: - complain (&dwarf2_unexpected_tag, dwarf_tag_name (die->tag)); + complaint (&symfile_complaints, "unexepected tag in read_type_die: '%s'", + dwarf_tag_name (die->tag)); break; } } @@ -5196,6 +5736,43 @@ dwarf2_linkage_name (struct die_info *die) return NULL; } +/* Get name of a die, return NULL if not found. */ + +static char * +dwarf2_name (struct die_info *die) +{ + struct attribute *attr; + + attr = dwarf_attr (die, DW_AT_name); + if (attr && DW_STRING (attr)) + return DW_STRING (attr); + return NULL; +} + +/* Return the die that this die in an extension of, or NULL if there + is none. */ + +static struct die_info * +dwarf2_extension (struct die_info *die) +{ + struct attribute *attr; + struct die_info *extension_die; + unsigned int ref; + + attr = dwarf_attr (die, DW_AT_extension); + if (attr == NULL) + return NULL; + + ref = dwarf2_get_ref_die_offset (attr); + extension_die = follow_die_ref (ref); + if (!extension_die) + { + error ("Dwarf Error: Cannot find referent at offset %d.", ref); + } + + return extension_die; +} + /* Convert a DIE tag into its string name. */ static char * @@ -5299,6 +5876,22 @@ dwarf_tag_name (register unsigned tag) return "DW_TAG_variable"; case DW_TAG_volatile_type: return "DW_TAG_volatile_type"; + case DW_TAG_dwarf_procedure: + return "DW_TAG_dwarf_procedure"; + case DW_TAG_restrict_type: + return "DW_TAG_restrict_type"; + case DW_TAG_interface_type: + return "DW_TAG_interface_type"; + case DW_TAG_namespace: + return "DW_TAG_namespace"; + case DW_TAG_imported_module: + return "DW_TAG_imported_module"; + case DW_TAG_unspecified_type: + return "DW_TAG_unspecified_type"; + case DW_TAG_partial_unit: + return "DW_TAG_partial_unit"; + case DW_TAG_imported_unit: + return "DW_TAG_imported_unit"; case DW_TAG_MIPS_loop: return "DW_TAG_MIPS_loop"; case DW_TAG_format_label: @@ -5443,7 +6036,30 @@ dwarf_attr_name (register unsigned attr) return "DW_AT_virtuality"; case DW_AT_vtable_elem_location: return "DW_AT_vtable_elem_location"; - + case DW_AT_allocated: + return "DW_AT_allocated"; + case DW_AT_associated: + return "DW_AT_associated"; + case DW_AT_data_location: + return "DW_AT_data_location"; + case DW_AT_stride: + return "DW_AT_stride"; + case DW_AT_entry_pc: + return "DW_AT_entry_pc"; + case DW_AT_use_UTF8: + return "DW_AT_use_UTF8"; + case DW_AT_extension: + return "DW_AT_extension"; + case DW_AT_ranges: + return "DW_AT_ranges"; + case DW_AT_trampoline: + return "DW_AT_trampoline"; + case DW_AT_call_column: + return "DW_AT_call_column"; + case DW_AT_call_file: + return "DW_AT_call_file"; + case DW_AT_call_line: + return "DW_AT_call_line"; #ifdef MIPS case DW_AT_MIPS_fde: return "DW_AT_MIPS_fde"; @@ -5831,6 +6447,18 @@ dwarf_stack_op_name (register unsigned op) return "DW_OP_xderef_size"; case DW_OP_nop: return "DW_OP_nop"; + /* DWARF 3 extensions. */ + case DW_OP_push_object_address: + return "DW_OP_push_object_address"; + case DW_OP_call2: + return "DW_OP_call2"; + case DW_OP_call4: + return "DW_OP_call4"; + case DW_OP_call_ref: + return "DW_OP_call_ref"; + /* GNU extensions. */ + case DW_OP_GNU_push_tls_address: + return "DW_OP_GNU_push_tls_address"; default: return "OP_"; } @@ -5868,6 +6496,8 @@ dwarf_type_encoding_name (register unsigned enc) return "DW_ATE_unsigned"; case DW_ATE_unsigned_char: return "DW_ATE_unsigned_char"; + case DW_ATE_imaginary_float: + return "DW_ATE_imaginary_float"; default: return "DW_ATE_"; } @@ -6060,7 +6690,9 @@ dwarf2_get_ref_die_offset (struct attribute *attr) result = cu_header_offset + DW_UNSND (attr); break; default: - complain (&dwarf2_unsupported_die_ref_attr, dwarf_form_name (attr->form)); + complaint (&symfile_complaints, + "unsupported die ref attribute form: '%s'", + dwarf_form_name (attr->form)); } return result; } @@ -6089,8 +6721,8 @@ dwarf2_fundamental_type (struct objfile *objfile, int typeid) { if (typeid < 0 || typeid >= FT_NUM_MEMBERS) { - error ("Dwarf Error: internal error - invalid fundamental type id %d.", - typeid); + error ("Dwarf Error: internal error - invalid fundamental type id %d [in module %s]", + typeid, objfile->name); } /* Look for this particular type in the fundamental type vector. If @@ -6152,6 +6784,7 @@ decode_locdesc (struct dwarf_block *blk, struct objfile *objfile, offreg = 0; isderef = 0; islocal = 0; + is_thread_local = 0; optimized_out = 1; while (i < size) @@ -6295,7 +6928,8 @@ decode_locdesc (struct dwarf_block *blk, struct objfile *objfile, } else { - complain (&dwarf2_missing_at_frame_base); + complaint (&symfile_complaints, + "DW_AT_frame_base missing for DW_OP_fbreg"); islocal = 1; } break; @@ -6372,11 +7006,22 @@ decode_locdesc (struct dwarf_block *blk, struct objfile *objfile, /* If we're not the last op, then we definitely can't encode this using GDB's address_class enum. */ if (i < size) - complain (&dwarf2_complex_location_expr); + dwarf2_complex_location_expr_complaint (); break; + case DW_OP_GNU_push_tls_address: + is_thread_local = 1; + /* The top of the stack has the offset from the beginning + of the thread control block at which the variable is located. */ + /* Nothing should follow this operator, so the top of stack would + be returned. */ + if (i < size) + dwarf2_complex_location_expr_complaint (); + break; + default: - complain (&dwarf2_unsupported_stack_op, dwarf_stack_op_name (op)); + complaint (&symfile_complaints, "unsupported stack op: '%s'", + dwarf_stack_op_name (op)); return (stack[stacki]); } } @@ -6387,7 +7032,7 @@ decode_locdesc (struct dwarf_block *blk, struct objfile *objfile, /* ARGSUSED */ static void -dwarf2_free_tmp_obstack (PTR ignore) +dwarf2_free_tmp_obstack (void *ignore) { obstack_free (&dwarf2_tmp_obstack, NULL); } @@ -6476,7 +7121,7 @@ macro_start_file (int file, int line, at all until we actually get a filename. */ if (! pending_macros) pending_macros = new_macro_table (&objfile->symbol_obstack, - &objfile->macro_cache); + objfile->macro_cache); if (! current_file) /* If we have no current file, then this must be the start_file @@ -6509,7 +7154,9 @@ consume_improper_spaces (const char *p, const char *body) { if (*p == ' ') { - complain (&dwarf2_macro_spaces_in_definition, body); + complaint (&symfile_complaints, + "macro definition contains spaces in formal argument list:\n`%s'", + body); while (*p == ' ') p++; @@ -6567,7 +7214,7 @@ parse_macro_definition (struct macro_source_file *file, int line, replacement = body + name_len + 1; else { - complain (&dwarf2_macro_malformed_definition, body); + dwarf2_macro_malformed_definition_complaint (body); replacement = body + name_len; } @@ -6597,8 +7244,7 @@ parse_macro_definition (struct macro_source_file *file, int line, p++; if (! *p || p == arg_start) - complain (&dwarf2_macro_malformed_definition, - body); + dwarf2_macro_malformed_definition_complaint (body); else { /* Make sure argv has room for the new argument. */ @@ -6634,18 +7280,18 @@ parse_macro_definition (struct macro_source_file *file, int line, else if (*p == '\0') { /* Complain, but do define it. */ - complain (&dwarf2_macro_malformed_definition, body); + dwarf2_macro_malformed_definition_complaint (body); macro_define_function (file, line, name, argc, (const char **) argv, p); } else /* Just complain. */ - complain (&dwarf2_macro_malformed_definition, body); + dwarf2_macro_malformed_definition_complaint (body); } else /* Just complain. */ - complain (&dwarf2_macro_malformed_definition, body); + dwarf2_macro_malformed_definition_complaint (body); xfree (name); { @@ -6657,7 +7303,7 @@ parse_macro_definition (struct macro_source_file *file, int line, xfree (argv); } else - complain (&dwarf2_macro_malformed_definition, body); + dwarf2_macro_malformed_definition_complaint (body); } @@ -6672,7 +7318,7 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, if (dwarf_macinfo_buffer == NULL) { - complain (&dwarf2_missing_macinfo_section); + complaint (&symfile_complaints, "missing .debug_macinfo section"); return; } @@ -6686,7 +7332,7 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, /* Do we at least have room for a macinfo type byte? */ if (mac_ptr >= mac_end) { - complain (&dwarf2_macros_too_long); + dwarf2_macros_too_long_complaint (); return; } @@ -6713,11 +7359,12 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, mac_ptr += bytes_read; if (! current_file) - complain (&dwarf2_macro_outside_file, - macinfo_type == DW_MACINFO_define ? "definition" : - macinfo_type == DW_MACINFO_undef ? "undefinition" : - "something-or-other", - body); + complaint (&symfile_complaints, + "debug info gives macro %s outside of any file: %s", + macinfo_type == + DW_MACINFO_define ? "definition" : macinfo_type == + DW_MACINFO_undef ? "undefinition" : + "something-or-other", body); else { if (macinfo_type == DW_MACINFO_define) @@ -6746,7 +7393,8 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, case DW_MACINFO_end_file: if (! current_file) - complain (&dwarf2_macro_unmatched_end_file); + complaint (&symfile_complaints, + "macro debug info has an unmatched `close_file' directive"); else { current_file = current_file->included_by; @@ -6762,7 +7410,7 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, /* Do we at least have room for a macinfo type byte? */ if (mac_ptr >= mac_end) { - complain (&dwarf2_macros_too_long); + dwarf2_macros_too_long_complaint (); return; } @@ -6770,7 +7418,8 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, a look-ahead. */ next_type = read_1_byte (abfd, mac_ptr); if (next_type != 0) - complain (&dwarf2_macros_not_terminated); + complaint (&symfile_complaints, + "no terminating 0-type entry for macros in `.debug_macinfo' section"); return; } @@ -6794,3 +7443,71 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, } } } + +/* Check if the attribute's form is a DW_FORM_block* + if so return true else false. */ +static int +attr_form_is_block (struct attribute *attr) +{ + return (attr == NULL ? 0 : + attr->form == DW_FORM_block1 + || attr->form == DW_FORM_block2 + || attr->form == DW_FORM_block4 + || attr->form == DW_FORM_block); +} + +static void +dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, + const struct comp_unit_head *cu_header, + struct objfile *objfile) +{ + if (attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8) + { + struct dwarf2_loclist_baton *baton; + + baton = obstack_alloc (&objfile->symbol_obstack, + sizeof (struct dwarf2_loclist_baton)); + baton->objfile = objfile; + + /* We don't know how long the location list is, but make sure we + don't run off the edge of the section. */ + baton->size = dwarf_loc_size - DW_UNSND (attr); + baton->data = dwarf_loc_buffer + DW_UNSND (attr); + 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."); + + SYMBOL_LOCATION_FUNCS (sym) = &dwarf2_loclist_funcs; + SYMBOL_LOCATION_BATON (sym) = baton; + } + else + { + struct dwarf2_locexpr_baton *baton; + + baton = obstack_alloc (&objfile->symbol_obstack, + sizeof (struct dwarf2_locexpr_baton)); + baton->objfile = objfile; + + if (attr_form_is_block (attr)) + { + /* Note that we're just copying the block's data pointer + here, not the actual data. We're still pointing into the + dwarf_info_buffer for SYM's objfile; right now we never + release that buffer, but when we do clean up properly + this may need to change. */ + baton->size = DW_BLOCK (attr)->size; + baton->data = DW_BLOCK (attr)->data; + } + else + { + dwarf2_invalid_attrib_class_complaint ("location description", + SYMBOL_NATURAL_NAME (sym)); + baton->size = 0; + baton->data = NULL; + } + + SYMBOL_LOCATION_FUNCS (sym) = &dwarf2_locexpr_funcs; + SYMBOL_LOCATION_BATON (sym) = baton; + } +}