#include "common/function-view.h"
#include "common/gdb_optional.h"
#include "common/underlying.h"
-
+#include "common/byte-vector.h"
+#include "filename-seen-cache.h"
+#include "producer.h"
#include <fcntl.h>
#include <sys/types.h>
#include <algorithm>
#include <unordered_set>
#include <unordered_map>
-
-typedef struct symbol *symbolp;
-DEF_VEC_P (symbolp);
+#include "selftest.h"
/* When == 1, print basic high level tracing messages.
When > 1, be more verbose.
GDB_INDEX_CU_SET_VALUE((cu_index), (value)); \
} while (0)
+#if WORDS_BIGENDIAN
+
+/* Convert VALUE between big- and little-endian. */
+
+static offset_type
+byte_swap (offset_type value)
+{
+ offset_type result;
+
+ result = (value & 0xff) << 24;
+ result |= (value & 0xff00) << 8;
+ result |= (value & 0xff0000) >> 8;
+ result |= (value & 0xff000000) >> 24;
+ return result;
+}
+
+#define MAYBE_SWAP(V) byte_swap (V)
+
+#else
+#define MAYBE_SWAP(V) static_cast<offset_type> (V)
+#endif /* WORDS_BIGENDIAN */
+
+/* An index into a (C++) symbol name component in a symbol name as
+ recorded in the mapped_index's symbol table. For each C++ symbol
+ in the symbol table, we record one entry for the start of each
+ component in the symbol in a table of name components, and then
+ sort the table, in order to be able to binary search symbol names,
+ ignoring leading namespaces, both completion and regular look up.
+ For example, for symbol "A::B::C", we'll have an entry that points
+ to "A::B::C", another that points to "B::C", and another for "C".
+ Note that function symbols in GDB index have no parameter
+ information, just the function/method names. You can convert a
+ name_component to a "const char *" using the
+ 'mapped_index::symbol_name_at(offset_type)' method. */
+
+struct name_component
+{
+ /* Offset in the symbol name where the component starts. Stored as
+ a (32-bit) offset instead of a pointer to save memory and improve
+ locality on 64-bit architectures. */
+ offset_type name_offset;
+
+ /* The symbol's index in the symbol and constant pool tables of a
+ mapped_index. */
+ offset_type idx;
+};
+
/* A description of the mapped index. The file format is described in
a comment by the code that writes the index. */
struct mapped_index
/* A pointer to the constant pool. */
const char *constant_pool;
+
+ /* The name_component table (a sorted vector). See name_component's
+ description above. */
+ std::vector<name_component> name_components;
+
+ /* How NAME_COMPONENTS is sorted. */
+ enum case_sensitivity name_components_casing;
+
+ /* Convenience method to get at the name of the symbol at IDX in the
+ symbol table. */
+ const char *symbol_name_at (offset_type idx) const
+ { return this->constant_pool + MAYBE_SWAP (this->symbol_table[idx]); }
+
+ /* Build the symbol name component sorted vector, if we haven't
+ yet. */
+ void build_name_components ();
+
+ /* Returns the lower (inclusive) and upper (exclusive) bounds of the
+ possible matches for LN_NO_PARAMS in the name component
+ vector. */
+ std::pair<std::vector<name_component>::const_iterator,
+ std::vector<name_component>::const_iterator>
+ find_name_components_bounds (const lookup_name_info &ln_no_params) const;
};
typedef struct dwarf2_per_cu_data *dwarf2_per_cu_ptr;
struct dwarf2_per_objfile
{
- struct dwarf2_section_info info;
- struct dwarf2_section_info abbrev;
- struct dwarf2_section_info line;
- struct dwarf2_section_info loc;
- struct dwarf2_section_info loclists;
- struct dwarf2_section_info macinfo;
- struct dwarf2_section_info macro;
- struct dwarf2_section_info str;
- struct dwarf2_section_info line_str;
- struct dwarf2_section_info ranges;
- struct dwarf2_section_info rnglists;
- struct dwarf2_section_info addr;
- struct dwarf2_section_info frame;
- struct dwarf2_section_info eh_frame;
- struct dwarf2_section_info gdb_index;
+ /* Construct a dwarf2_per_objfile for OBJFILE. NAMES points to the
+ dwarf2 section names, or is NULL if the standard ELF names are
+ used. */
+ dwarf2_per_objfile (struct objfile *objfile,
+ const dwarf2_debug_sections *names);
- VEC (dwarf2_section_info_def) *types;
+ ~dwarf2_per_objfile ();
+
+ DISABLE_COPY_AND_ASSIGN (dwarf2_per_objfile);
+
+ /* Free all cached compilation units. */
+ void free_cached_comp_units ();
+private:
+ /* This function is mapped across the sections and remembers the
+ offset and size of each of the debugging sections we are
+ interested in. */
+ void locate_sections (bfd *abfd, asection *sectp,
+ const dwarf2_debug_sections &names);
+
+public:
+ dwarf2_section_info info {};
+ dwarf2_section_info abbrev {};
+ dwarf2_section_info line {};
+ dwarf2_section_info loc {};
+ dwarf2_section_info loclists {};
+ dwarf2_section_info macinfo {};
+ dwarf2_section_info macro {};
+ dwarf2_section_info str {};
+ dwarf2_section_info line_str {};
+ dwarf2_section_info ranges {};
+ dwarf2_section_info rnglists {};
+ dwarf2_section_info addr {};
+ dwarf2_section_info frame {};
+ dwarf2_section_info eh_frame {};
+ dwarf2_section_info gdb_index {};
+
+ VEC (dwarf2_section_info_def) *types = NULL;
/* Back link. */
- struct objfile *objfile;
+ struct objfile *objfile = NULL;
/* Table of all the compilation units. This is used to locate
the target compilation unit of a particular reference. */
- struct dwarf2_per_cu_data **all_comp_units;
+ struct dwarf2_per_cu_data **all_comp_units = NULL;
/* The number of compilation units in ALL_COMP_UNITS. */
- int n_comp_units;
+ int n_comp_units = 0;
/* The number of .debug_types-related CUs. */
- int n_type_units;
+ int n_type_units = 0;
/* The number of elements allocated in all_type_units.
If there are skeleton-less TUs, we add them to all_type_units lazily. */
- int n_allocated_type_units;
+ int n_allocated_type_units = 0;
/* The .debug_types-related CUs (TUs).
This is stored in malloc space because we may realloc it. */
- struct signatured_type **all_type_units;
+ struct signatured_type **all_type_units = NULL;
/* Table of struct type_unit_group objects.
The hash key is the DW_AT_stmt_list value. */
- htab_t type_unit_groups;
+ htab_t type_unit_groups {};
/* A table mapping .debug_types signatures to its signatured_type entry.
This is NULL if the .debug_types section hasn't been read in yet. */
- htab_t signatured_types;
+ htab_t signatured_types {};
/* Type unit statistics, to see how well the scaling improvements
are doing. */
- struct tu_stats tu_stats;
+ struct tu_stats tu_stats {};
/* 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;
+ dwarf2_per_cu_data *read_in_chain = NULL;
/* A table mapping DW_AT_dwo_name values to struct dwo_file objects.
This is NULL if the table hasn't been allocated yet. */
- htab_t dwo_files;
+ htab_t dwo_files {};
- /* Non-zero if we've check for whether there is a DWP file. */
- int dwp_checked;
+ /* True if we've checked for whether there is a DWP file. */
+ bool dwp_checked = false;
/* The DWP file if there is one, or NULL. */
- struct dwp_file *dwp_file;
+ struct dwp_file *dwp_file = NULL;
/* The shared '.dwz' file, if one exists. This is used when the
original data was compressed using 'dwz -m'. */
- struct dwz_file *dwz_file;
+ struct dwz_file *dwz_file = NULL;
- /* A flag indicating wether this objfile has a section loaded at a
+ /* A flag indicating whether this objfile has a section loaded at a
VMA of 0. */
- int has_section_at_zero;
+ bool has_section_at_zero = false;
/* True if we are using the mapped index,
or we are faking it for OBJF_READNOW's sake. */
- unsigned char using_index;
+ bool using_index = false;
/* The mapped index, or NULL if .gdb_index is missing or not being used. */
- struct mapped_index *index_table;
+ mapped_index *index_table = NULL;
/* When using index_table, this keeps track of all quick_file_names entries.
TUs typically share line table entries with a CU, so we maintain a
sorted all the TUs into "type unit groups", grouped by their
DW_AT_stmt_list value. Therefore the only sharing done here is with a
CU and its associated TU group if there is one. */
- htab_t quick_file_names_table;
+ htab_t quick_file_names_table {};
/* Set during partial symbol reading, to prevent queueing of full
symbols. */
- int reading_partial_symbols;
+ bool reading_partial_symbols = false;
/* Table mapping type DIEs to their struct type *.
This is NULL if not allocated yet.
The mapping is done via (CU/TU + DIE offset) -> type. */
- htab_t die_type_hash;
+ htab_t die_type_hash {};
/* The CUs we recently read. */
- VEC (dwarf2_per_cu_ptr) *just_read_cus;
+ VEC (dwarf2_per_cu_ptr) *just_read_cus = NULL;
/* Table containing line_header indexed by offset and offset_in_dwz. */
- htab_t line_header_hash;
+ htab_t line_header_hash {};
+
+ /* Table containing all filenames. This is an optional because the
+ table is lazily constructed on first access. */
+ gdb::optional<filename_seen_cache> filenames_cache;
};
static struct dwarf2_per_objfile *dwarf2_per_objfile;
/* Header data from the line table, during full symbol processing. */
struct line_header *line_header;
+ /* Non-NULL if LINE_HEADER is owned by this DWARF_CU. Otherwise,
+ it's owned by dwarf2_per_objfile::line_header_hash. If non-NULL,
+ this is the DW_TAG_compile_unit die for this CU. We'll hold on
+ to the line header as long as this DIE is being processed. See
+ process_die_scope. */
+ die_info *line_header_die_owner;
/* A list of methods which need to have physnames computed
after all type information has been read. */
unsigned int checked_producer : 1;
unsigned int producer_is_gxx_lt_4_6 : 1;
unsigned int producer_is_gcc_lt_4_3 : 1;
- unsigned int producer_is_icc : 1;
+ unsigned int producer_is_icc_lt_14 : 1;
/* When set, the file that we're processing is known to have
debugging info for C++ namespaces. GCC 3.3.x did not produce
sections (for lack of a better name). */
struct dwo_sections sections;
- /* The CU in the file.
- We only support one because having more than one requires hacking the
- dwo_name of each to match, which is highly unlikely to happen.
- Doing this means all TUs can share comp_dir: We also assume that
- DW_AT_comp_dir across all TUs in a DWO file will be identical. */
- struct dwo_unit *cu;
+ /* The CUs in the file.
+ Each element is a struct dwo_unit. Multiple CUs per DWO are supported as
+ an extension to handle LLVM's Link Time Optimization output (where
+ multiple source files may be compiled into a single object/dwo pair). */
+ htab_t cus;
/* Table of TUs in the file.
Each element is a struct dwo_unit. */
struct nextfnfield *head;
};
-struct typedef_field_list
+struct decl_field_list
{
- struct typedef_field field;
- struct typedef_field_list *next;
+ struct decl_field field;
+ struct decl_field_list *next;
};
/* The routines that read and process dies for a C struct or C++ class
/* Set if the accesibility of one of the fields is not public. */
int non_public_fields;
- /* Member function fields array, entries are allocated in the order they
- are encountered in the object file. */
- struct nextfnfield *fnfields;
-
/* Member function fieldlist array, contains name of possibly overloaded
member function, number of overloaded member functions and a pointer
to the head of the member function field chain. */
/* typedefs defined inside this class. TYPEDEF_FIELD_LIST contains head of
a NULL terminated list of TYPEDEF_FIELD_LIST_COUNT elements. */
- struct typedef_field_list *typedef_field_list;
+ struct decl_field_list *typedef_field_list;
unsigned typedef_field_list_count;
+
+ /* Nested types defined by this class and the number of elements in this
+ list. */
+ struct decl_field_list *nested_types_list;
+ unsigned nested_types_list_count;
};
/* One item on the queue of compilation units to read in full symbols
static const char *get_section_file_name (const struct dwarf2_section_info *);
-static void dwarf2_locate_sections (bfd *, asection *, void *);
-
static void dwarf2_find_base_address (struct die_info *die,
struct dwarf2_cu *cu);
static struct partial_symtab *create_partial_symtab
(struct dwarf2_per_cu_data *per_cu, const char *name);
+static void build_type_psymtabs_reader (const struct die_reader_specs *reader,
+ const gdb_byte *info_ptr,
+ struct die_info *type_unit_die,
+ int has_children, void *data);
+
static void dwarf2_build_psymtabs_hard (struct objfile *);
static void scan_partial_symbols (struct partial_die_info *,
static void read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu);
+static void read_variable (struct die_info *die, struct dwarf2_cu *cu);
+
static int dwarf2_ranges_read (unsigned, CORE_ADDR *, CORE_ADDR *,
struct dwarf2_cu *, struct partial_symtab *);
}
\f
-#if WORDS_BIGENDIAN
-
-/* Convert VALUE between big- and little-endian. */
-static offset_type
-byte_swap (offset_type value)
-{
- offset_type result;
-
- result = (value & 0xff) << 24;
- result |= (value & 0xff00) << 8;
- result |= (value & 0xff0000) >> 8;
- result |= (value & 0xff000000) >> 24;
- return result;
-}
-
-#define MAYBE_SWAP(V) byte_swap (V)
-
-#else
-#define MAYBE_SWAP(V) static_cast<offset_type> (V)
-#endif /* WORDS_BIGENDIAN */
/* Read the given attribute value as an address, taking the attribute's
form into account. */
/* The suffix for an index file. */
#define INDEX_SUFFIX ".gdb-index"
+/* See declaration. */
+
+dwarf2_per_objfile::dwarf2_per_objfile (struct objfile *objfile_,
+ const dwarf2_debug_sections *names)
+ : objfile (objfile_)
+{
+ if (names == NULL)
+ names = &dwarf2_elf_names;
+
+ bfd *obfd = objfile->obfd;
+
+ for (asection *sec = obfd->sections; sec != NULL; sec = sec->next)
+ locate_sections (obfd, sec, *names);
+}
+
+dwarf2_per_objfile::~dwarf2_per_objfile ()
+{
+ /* Cached DIE trees use xmalloc and the comp_unit_obstack. */
+ free_cached_comp_units ();
+
+ if (quick_file_names_table)
+ htab_delete (quick_file_names_table);
+
+ if (line_header_hash)
+ htab_delete (line_header_hash);
+
+ /* Everything else should be on the objfile obstack. */
+}
+
+/* See declaration. */
+
+void
+dwarf2_per_objfile::free_cached_comp_units ()
+{
+ dwarf2_per_cu_data *per_cu = read_in_chain;
+ dwarf2_per_cu_data **last_chain = &read_in_chain;
+ while (per_cu != NULL)
+ {
+ dwarf2_per_cu_data *next_cu = per_cu->cu->read_in_chain;
+
+ free_heap_comp_unit (per_cu->cu);
+ *last_chain = next_cu;
+ per_cu = next_cu;
+ }
+}
+
/* Try to locate the sections we need for DWARF 2 debugging
information and return true if we have enough to do something.
NAMES points to the dwarf2 section names, or is NULL if the standard
dwarf2_has_info (struct objfile *objfile,
const struct dwarf2_debug_sections *names)
{
+ if (objfile->flags & OBJF_READNEVER)
+ return 0;
+
dwarf2_per_objfile = ((struct dwarf2_per_objfile *)
objfile_data (objfile, dwarf2_objfile_data_key));
if (!dwarf2_per_objfile)
struct dwarf2_per_objfile *data
= XOBNEW (&objfile->objfile_obstack, struct dwarf2_per_objfile);
- memset (data, 0, sizeof (*data));
- set_objfile_data (objfile, dwarf2_objfile_data_key, data);
- dwarf2_per_objfile = data;
-
- bfd_map_over_sections (objfile->obfd, dwarf2_locate_sections,
- (void *) names);
- dwarf2_per_objfile->objfile = objfile;
+ dwarf2_per_objfile = new (data) struct dwarf2_per_objfile (objfile, names);
+ set_objfile_data (objfile, dwarf2_objfile_data_key, dwarf2_per_objfile);
}
return (!dwarf2_per_objfile->info.is_virtual
&& dwarf2_per_objfile->info.s.section != NULL
return 0;
}
-/* This function is mapped across the sections and remembers the
- offset and size of each of the debugging sections we are interested
- in. */
+/* See declaration. */
-static void
-dwarf2_locate_sections (bfd *abfd, asection *sectp, void *vnames)
+void
+dwarf2_per_objfile::locate_sections (bfd *abfd, asection *sectp,
+ const dwarf2_debug_sections &names)
{
- const struct dwarf2_debug_sections *names;
flagword aflag = bfd_get_section_flags (abfd, sectp);
- if (vnames == NULL)
- names = &dwarf2_elf_names;
- else
- names = (const struct dwarf2_debug_sections *) vnames;
-
if ((aflag & SEC_HAS_CONTENTS) == 0)
{
}
- else if (section_is_p (sectp->name, &names->info))
+ else if (section_is_p (sectp->name, &names.info))
{
- dwarf2_per_objfile->info.s.section = sectp;
- dwarf2_per_objfile->info.size = bfd_get_section_size (sectp);
+ this->info.s.section = sectp;
+ this->info.size = bfd_get_section_size (sectp);
}
- else if (section_is_p (sectp->name, &names->abbrev))
+ else if (section_is_p (sectp->name, &names.abbrev))
{
- dwarf2_per_objfile->abbrev.s.section = sectp;
- dwarf2_per_objfile->abbrev.size = bfd_get_section_size (sectp);
+ this->abbrev.s.section = sectp;
+ this->abbrev.size = bfd_get_section_size (sectp);
}
- else if (section_is_p (sectp->name, &names->line))
+ else if (section_is_p (sectp->name, &names.line))
{
- dwarf2_per_objfile->line.s.section = sectp;
- dwarf2_per_objfile->line.size = bfd_get_section_size (sectp);
+ this->line.s.section = sectp;
+ this->line.size = bfd_get_section_size (sectp);
}
- else if (section_is_p (sectp->name, &names->loc))
+ else if (section_is_p (sectp->name, &names.loc))
{
- dwarf2_per_objfile->loc.s.section = sectp;
- dwarf2_per_objfile->loc.size = bfd_get_section_size (sectp);
+ this->loc.s.section = sectp;
+ this->loc.size = bfd_get_section_size (sectp);
}
- else if (section_is_p (sectp->name, &names->loclists))
+ else if (section_is_p (sectp->name, &names.loclists))
{
- dwarf2_per_objfile->loclists.s.section = sectp;
- dwarf2_per_objfile->loclists.size = bfd_get_section_size (sectp);
+ this->loclists.s.section = sectp;
+ this->loclists.size = bfd_get_section_size (sectp);
}
- else if (section_is_p (sectp->name, &names->macinfo))
+ else if (section_is_p (sectp->name, &names.macinfo))
{
- dwarf2_per_objfile->macinfo.s.section = sectp;
- dwarf2_per_objfile->macinfo.size = bfd_get_section_size (sectp);
+ this->macinfo.s.section = sectp;
+ this->macinfo.size = bfd_get_section_size (sectp);
}
- else if (section_is_p (sectp->name, &names->macro))
+ else if (section_is_p (sectp->name, &names.macro))
{
- dwarf2_per_objfile->macro.s.section = sectp;
- dwarf2_per_objfile->macro.size = bfd_get_section_size (sectp);
+ this->macro.s.section = sectp;
+ this->macro.size = bfd_get_section_size (sectp);
}
- else if (section_is_p (sectp->name, &names->str))
+ else if (section_is_p (sectp->name, &names.str))
{
- dwarf2_per_objfile->str.s.section = sectp;
- dwarf2_per_objfile->str.size = bfd_get_section_size (sectp);
+ this->str.s.section = sectp;
+ this->str.size = bfd_get_section_size (sectp);
}
- else if (section_is_p (sectp->name, &names->line_str))
+ else if (section_is_p (sectp->name, &names.line_str))
{
- dwarf2_per_objfile->line_str.s.section = sectp;
- dwarf2_per_objfile->line_str.size = bfd_get_section_size (sectp);
+ this->line_str.s.section = sectp;
+ this->line_str.size = bfd_get_section_size (sectp);
}
- else if (section_is_p (sectp->name, &names->addr))
+ else if (section_is_p (sectp->name, &names.addr))
{
- dwarf2_per_objfile->addr.s.section = sectp;
- dwarf2_per_objfile->addr.size = bfd_get_section_size (sectp);
+ this->addr.s.section = sectp;
+ this->addr.size = bfd_get_section_size (sectp);
}
- else if (section_is_p (sectp->name, &names->frame))
+ else if (section_is_p (sectp->name, &names.frame))
{
- dwarf2_per_objfile->frame.s.section = sectp;
- dwarf2_per_objfile->frame.size = bfd_get_section_size (sectp);
+ this->frame.s.section = sectp;
+ this->frame.size = bfd_get_section_size (sectp);
}
- else if (section_is_p (sectp->name, &names->eh_frame))
+ else if (section_is_p (sectp->name, &names.eh_frame))
{
- dwarf2_per_objfile->eh_frame.s.section = sectp;
- dwarf2_per_objfile->eh_frame.size = bfd_get_section_size (sectp);
+ this->eh_frame.s.section = sectp;
+ this->eh_frame.size = bfd_get_section_size (sectp);
}
- else if (section_is_p (sectp->name, &names->ranges))
+ else if (section_is_p (sectp->name, &names.ranges))
{
- dwarf2_per_objfile->ranges.s.section = sectp;
- dwarf2_per_objfile->ranges.size = bfd_get_section_size (sectp);
+ this->ranges.s.section = sectp;
+ this->ranges.size = bfd_get_section_size (sectp);
}
- else if (section_is_p (sectp->name, &names->rnglists))
+ else if (section_is_p (sectp->name, &names.rnglists))
{
- dwarf2_per_objfile->rnglists.s.section = sectp;
- dwarf2_per_objfile->rnglists.size = bfd_get_section_size (sectp);
+ this->rnglists.s.section = sectp;
+ this->rnglists.size = bfd_get_section_size (sectp);
}
- else if (section_is_p (sectp->name, &names->types))
+ else if (section_is_p (sectp->name, &names.types))
{
struct dwarf2_section_info type_section;
type_section.s.section = sectp;
type_section.size = bfd_get_section_size (sectp);
- VEC_safe_push (dwarf2_section_info_def, dwarf2_per_objfile->types,
+ VEC_safe_push (dwarf2_section_info_def, this->types,
&type_section);
}
- else if (section_is_p (sectp->name, &names->gdb_index))
+ else if (section_is_p (sectp->name, &names.gdb_index))
{
- dwarf2_per_objfile->gdb_index.s.section = sectp;
- dwarf2_per_objfile->gdb_index.size = bfd_get_section_size (sectp);
+ this->gdb_index.s.section = sectp;
+ this->gdb_index.size = bfd_get_section_size (sectp);
}
if ((bfd_get_section_flags (abfd, sectp) & (SEC_LOAD | SEC_ALLOC))
&& bfd_section_vma (abfd, sectp) == 0)
- dwarf2_per_objfile->has_section_at_zero = 1;
+ this->has_section_at_zero = true;
}
/* A helper function that decides whether a section is empty,
static struct dwz_file *
dwarf2_get_dwz_file (void)
{
- char *data;
- struct cleanup *cleanup;
const char *filename;
struct dwz_file *result;
bfd_size_type buildid_len_arg;
return dwarf2_per_objfile->dwz_file;
bfd_set_error (bfd_error_no_error);
- data = bfd_get_alt_debug_link_info (dwarf2_per_objfile->objfile->obfd,
- &buildid_len_arg, &buildid);
+ gdb::unique_xmalloc_ptr<char> data
+ (bfd_get_alt_debug_link_info (dwarf2_per_objfile->objfile->obfd,
+ &buildid_len_arg, &buildid));
if (data == NULL)
{
if (bfd_get_error () == bfd_error_no_error)
error (_("could not read '.gnu_debugaltlink' section: %s"),
bfd_errmsg (bfd_get_error ()));
}
- cleanup = make_cleanup (xfree, data);
- make_cleanup (xfree, buildid);
+
+ gdb::unique_xmalloc_ptr<bfd_byte> buildid_holder (buildid);
buildid_len = (size_t) buildid_len_arg;
- filename = (const char *) data;
+ filename = data.get ();
std::string abs_storage;
if (!IS_ABSOLUTE_PATH (filename))
{
- char *abs = gdb_realpath (objfile_name (dwarf2_per_objfile->objfile));
+ gdb::unique_xmalloc_ptr<char> abs
+ = gdb_realpath (objfile_name (dwarf2_per_objfile->objfile));
- make_cleanup (xfree, abs);
- abs_storage = ldirname (abs) + SLASH_STRING + filename;
+ abs_storage = ldirname (abs.get ()) + SLASH_STRING + filename;
filename = abs_storage.c_str ();
}
bfd_map_over_sections (result->dwz_bfd, locate_dwz_sections, result);
- do_cleanups (cleanup);
-
gdb_bfd_record_inclusion (dwarf2_per_objfile->objfile->obfd, result->dwz_bfd);
dwarf2_per_objfile->dwz_file = result;
return result;
{
struct gdbarch *gdbarch = get_objfile_arch (objfile);
const gdb_byte *iter, *end;
- struct obstack temp_obstack;
struct addrmap *mutable_map;
- struct cleanup *cleanup;
CORE_ADDR baseaddr;
- obstack_init (&temp_obstack);
- cleanup = make_cleanup_obstack_free (&temp_obstack);
+ auto_obstack temp_obstack;
+
mutable_map = addrmap_create_mutable (&temp_obstack);
iter = index->address_table;
objfile->psymtabs_addrmap = addrmap_create_fixed (mutable_map,
&objfile->objfile_obstack);
- do_cleanups (cleanup);
}
/* The hash function for strings in the mapped index. This is the same as
/* Find a slot in the mapped index INDEX for the object named NAME.
If NAME is found, set *VEC_OUT to point to the CU vector in the
- constant pool and return 1. If NAME cannot be found, return 0. */
+ constant pool and return true. If NAME cannot be found, return
+ false. */
-static int
+static bool
find_slot_in_mapped_hash (struct mapped_index *index, const char *name,
offset_type **vec_out)
{
- struct cleanup *back_to = make_cleanup (null_cleanup, 0);
offset_type hash;
offset_type slot, step;
int (*cmp) (const char *, const char *);
+ gdb::unique_xmalloc_ptr<char> without_params;
if (current_language->la_language == language_cplus
|| current_language->la_language == language_fortran
|| current_language->la_language == language_d)
if (strchr (name, '(') != NULL)
{
- char *without_params = cp_remove_params (name);
+ without_params = cp_remove_params (name);
if (without_params != NULL)
- {
- make_cleanup (xfree, without_params);
- name = without_params;
- }
+ name = without_params.get ();
}
}
offset_type i = 2 * slot;
const char *str;
if (index->symbol_table[i] == 0 && index->symbol_table[i + 1] == 0)
- {
- do_cleanups (back_to);
- return 0;
- }
+ return false;
str = index->constant_pool + MAYBE_SWAP (index->symbol_table[i]);
if (!cmp (name, str))
{
*vec_out = (offset_type *) (index->constant_pool
+ MAYBE_SWAP (index->symbol_table[i + 1]));
- do_cleanups (back_to);
- return 1;
+ return true;
}
slot = (slot + step) & (index->symbol_table_slots - 1);
create_addrmap_from_index (objfile, &local_map);
map = XOBNEW (&objfile->objfile_obstack, struct mapped_index);
+ map = new (map) mapped_index ();
*map = local_map;
dwarf2_per_objfile->index_table = map;
qfn->num_file_names, const char *);
if (qfn->real_names[index] == NULL)
- qfn->real_names[index] = gdb_realpath (qfn->file_names[index]);
+ qfn->real_names[index] = gdb_realpath (qfn->file_names[index]).release ();
return qfn->real_names[index];
}
dw2_setup (objfile);
+ lookup_name_info lookup_name (name, symbol_name_match_type::FULL);
+
index = dwarf2_per_objfile->index_table;
/* index is NULL if OBJF_READNOW. */
information (but NAME might contain it). */
if (sym != NULL
- && strcmp_iw (SYMBOL_SEARCH_NAME (sym), name) == 0)
+ && SYMBOL_MATCHES_SEARCH_NAME (sym, lookup_name))
return stab;
if (with_opaque != NULL
- && strcmp_iw (SYMBOL_SEARCH_NAME (with_opaque), name) == 0)
+ && SYMBOL_MATCHES_SEARCH_NAME (with_opaque, lookup_name))
stab_best = stab;
/* Keep looking through other CUs. */
{
int i;
- dw2_setup (objfile);
+ dw2_setup (objfile);
+
+ for (i = 0; i < (dwarf2_per_objfile->n_comp_units
+ + dwarf2_per_objfile->n_type_units); ++i)
+ {
+ struct dwarf2_per_cu_data *per_cu = dw2_get_cutu (i);
+
+ dw2_instantiate_symtab (per_cu);
+ }
+}
+
+static void
+dw2_expand_symtabs_with_fullname (struct objfile *objfile,
+ const char *fullname)
+{
+ int i;
+
+ dw2_setup (objfile);
+
+ /* We don't need to consider type units here.
+ This is only called for examining code, e.g. expand_line_sal.
+ There can be an order of magnitude (or more) more type units
+ than comp units, and we avoid them if we can. */
+
+ for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ {
+ int j;
+ struct dwarf2_per_cu_data *per_cu = dw2_get_cutu (i);
+ struct quick_file_names *file_data;
+
+ /* We only need to look at symtabs not already expanded. */
+ if (per_cu->v.quick->compunit_symtab)
+ continue;
+
+ file_data = dw2_get_file_names (per_cu);
+ if (file_data == NULL)
+ continue;
+
+ for (j = 0; j < file_data->num_file_names; ++j)
+ {
+ const char *this_fullname = file_data->file_names[j];
+
+ if (filename_cmp (this_fullname, fullname) == 0)
+ {
+ dw2_instantiate_symtab (per_cu);
+ break;
+ }
+ }
+ }
+}
+
+static void
+dw2_map_matching_symbols (struct objfile *objfile,
+ const char * name, domain_enum domain,
+ int global,
+ int (*callback) (struct block *,
+ struct symbol *, void *),
+ void *data, symbol_name_match_type match,
+ symbol_compare_ftype *ordered_compare)
+{
+ /* Currently unimplemented; used for Ada. The function can be called if the
+ current language is Ada for a non-Ada objfile using GNU index. As Ada
+ does not look for non-Ada symbols this function should just return. */
+}
+
+/* Symbol name matcher for .gdb_index names.
+
+ Symbol names in .gdb_index have a few particularities:
+
+ - There's no indication of which is the language of each symbol.
+
+ Since each language has its own symbol name matching algorithm,
+ and we don't know which language is the right one, we must match
+ each symbol against all languages. This would be a potential
+ performance problem if it were not mitigated by the
+ mapped_index::name_components lookup table, which significantly
+ reduces the number of times we need to call into this matcher,
+ making it a non-issue.
+
+ - Symbol names in the index have no overload (parameter)
+ information. I.e., in C++, "foo(int)" and "foo(long)" both
+ appear as "foo" in the index, for example.
+
+ This means that the lookup names passed to the symbol name
+ matcher functions must have no parameter information either
+ because (e.g.) symbol search name "foo" does not match
+ lookup-name "foo(int)" [while swapping search name for lookup
+ name would match].
+*/
+class gdb_index_symbol_name_matcher
+{
+public:
+ /* Prepares the vector of comparison functions for LOOKUP_NAME. */
+ gdb_index_symbol_name_matcher (const lookup_name_info &lookup_name);
+
+ /* Walk all the matcher routines and match SYMBOL_NAME against them.
+ Returns true if any matcher matches. */
+ bool matches (const char *symbol_name);
+
+private:
+ /* A reference to the lookup name we're matching against. */
+ const lookup_name_info &m_lookup_name;
+
+ /* A vector holding all the different symbol name matchers, for all
+ languages. */
+ std::vector<symbol_name_matcher_ftype *> m_symbol_name_matcher_funcs;
+};
+
+gdb_index_symbol_name_matcher::gdb_index_symbol_name_matcher
+ (const lookup_name_info &lookup_name)
+ : m_lookup_name (lookup_name)
+{
+ /* Prepare the vector of comparison functions upfront, to avoid
+ doing the same work for each symbol. Care is taken to avoid
+ matching with the same matcher more than once if/when multiple
+ languages use the same matcher function. */
+ auto &matchers = m_symbol_name_matcher_funcs;
+ matchers.reserve (nr_languages);
+
+ matchers.push_back (default_symbol_name_matcher);
+
+ for (int i = 0; i < nr_languages; i++)
+ {
+ const language_defn *lang = language_def ((enum language) i);
+ if (lang->la_get_symbol_name_matcher != NULL)
+ {
+ symbol_name_matcher_ftype *name_matcher
+ = lang->la_get_symbol_name_matcher (m_lookup_name);
+
+ /* Don't insert the same comparison routine more than once.
+ Note that we do this linear walk instead of a cheaper
+ sorted insert, or use a std::set or something like that,
+ because relative order of function addresses is not
+ stable. This is not a problem in practice because the
+ number of supported languages is low, and the cost here
+ is tiny compared to the number of searches we'll do
+ afterwards using this object. */
+ if (std::find (matchers.begin (), matchers.end (), name_matcher)
+ == matchers.end ())
+ matchers.push_back (name_matcher);
+ }
+ }
+}
+
+bool
+gdb_index_symbol_name_matcher::matches (const char *symbol_name)
+{
+ for (auto matches_name : m_symbol_name_matcher_funcs)
+ if (matches_name (symbol_name, m_lookup_name, NULL))
+ return true;
+
+ return false;
+}
+
+/* Starting from a search name, return the string that finds the upper
+ bound of all strings that start with SEARCH_NAME in a sorted name
+ list. Returns the empty string to indicate that the upper bound is
+ the end of the list. */
+
+static std::string
+make_sort_after_prefix_name (const char *search_name)
+{
+ /* When looking to complete "func", we find the upper bound of all
+ symbols that start with "func" by looking for where we'd insert
+ the closest string that would follow "func" in lexicographical
+ order. Usually, that's "func"-with-last-character-incremented,
+ i.e. "fund". Mind non-ASCII characters, though. Usually those
+ will be UTF-8 multi-byte sequences, but we can't be certain.
+ Especially mind the 0xff character, which is a valid character in
+ non-UTF-8 source character sets (e.g. Latin1 'ÿ'), and we can't
+ rule out compilers allowing it in identifiers. Note that
+ conveniently, strcmp/strcasecmp are specified to compare
+ characters interpreted as unsigned char. So what we do is treat
+ the whole string as a base 256 number composed of a sequence of
+ base 256 "digits" and add 1 to it. I.e., adding 1 to 0xff wraps
+ to 0, and carries 1 to the following more-significant position.
+ If the very first character in SEARCH_NAME ends up incremented
+ and carries/overflows, then the upper bound is the end of the
+ list. The string after the empty string is also the empty
+ string.
+
+ Some examples of this operation:
+
+ SEARCH_NAME => "+1" RESULT
+
+ "abc" => "abd"
+ "ab\xff" => "ac"
+ "\xff" "a" "\xff" => "\xff" "b"
+ "\xff" => ""
+ "\xff\xff" => ""
+ "" => ""
+
+ Then, with these symbols for example:
+
+ func
+ func1
+ fund
+
+ completing "func" looks for symbols between "func" and
+ "func"-with-last-character-incremented, i.e. "fund" (exclusive),
+ which finds "func" and "func1", but not "fund".
+
+ And with:
+
+ funcÿ (Latin1 'ÿ' [0xff])
+ funcÿ1
+ fund
+
+ completing "funcÿ" looks for symbols between "funcÿ" and "fund"
+ (exclusive), which finds "funcÿ" and "funcÿ1", but not "fund".
+
+ And with:
+
+ ÿÿ (Latin1 'ÿ' [0xff])
+ ÿÿ1
+
+ completing "ÿ" or "ÿÿ" looks for symbols between between "ÿÿ" and
+ the end of the list.
+ */
+ std::string after = search_name;
+ while (!after.empty () && (unsigned char) after.back () == 0xff)
+ after.pop_back ();
+ if (!after.empty ())
+ after.back () = (unsigned char) after.back () + 1;
+ return after;
+}
+
+/* See declaration. */
+
+std::pair<std::vector<name_component>::const_iterator,
+ std::vector<name_component>::const_iterator>
+mapped_index::find_name_components_bounds
+ (const lookup_name_info &lookup_name_without_params) const
+{
+ auto *name_cmp
+ = this->name_components_casing == case_sensitive_on ? strcmp : strcasecmp;
+
+ const char *cplus
+ = lookup_name_without_params.cplus ().lookup_name ().c_str ();
+
+ /* Comparison function object for lower_bound that matches against a
+ given symbol name. */
+ auto lookup_compare_lower = [&] (const name_component &elem,
+ const char *name)
+ {
+ const char *elem_qualified = this->symbol_name_at (elem.idx);
+ const char *elem_name = elem_qualified + elem.name_offset;
+ return name_cmp (elem_name, name) < 0;
+ };
+
+ /* Comparison function object for upper_bound that matches against a
+ given symbol name. */
+ auto lookup_compare_upper = [&] (const char *name,
+ const name_component &elem)
+ {
+ const char *elem_qualified = this->symbol_name_at (elem.idx);
+ const char *elem_name = elem_qualified + elem.name_offset;
+ return name_cmp (name, elem_name) < 0;
+ };
+
+ auto begin = this->name_components.begin ();
+ auto end = this->name_components.end ();
+
+ /* Find the lower bound. */
+ auto lower = [&] ()
+ {
+ if (lookup_name_without_params.completion_mode () && cplus[0] == '\0')
+ return begin;
+ else
+ return std::lower_bound (begin, end, cplus, lookup_compare_lower);
+ } ();
+
+ /* Find the upper bound. */
+ auto upper = [&] ()
+ {
+ if (lookup_name_without_params.completion_mode ())
+ {
+ /* In completion mode, we want UPPER to point past all
+ symbols names that have the same prefix. I.e., with
+ these symbols, and completing "func":
+
+ function << lower bound
+ function1
+ other_function << upper bound
+
+ We find the upper bound by looking for the insertion
+ point of "func"-with-last-character-incremented,
+ i.e. "fund". */
+ std::string after = make_sort_after_prefix_name (cplus);
+ if (after.empty ())
+ return end;
+ return std::lower_bound (lower, end, after.c_str (),
+ lookup_compare_lower);
+ }
+ else
+ return std::upper_bound (lower, end, cplus, lookup_compare_upper);
+ } ();
+
+ return {lower, upper};
+}
+
+/* See declaration. */
+
+void
+mapped_index::build_name_components ()
+{
+ if (!this->name_components.empty ())
+ return;
+
+ this->name_components_casing = case_sensitivity;
+ auto *name_cmp
+ = this->name_components_casing == case_sensitive_on ? strcmp : strcasecmp;
+
+ /* The code below only knows how to break apart components of C++
+ symbol names (and other languages that use '::' as
+ namespace/module separator). If we add support for wild matching
+ to some language that uses some other operator (E.g., Ada, Go and
+ D use '.'), then we'll need to try splitting the symbol name
+ according to that language too. Note that Ada does support wild
+ matching, but doesn't currently support .gdb_index. */
+ for (size_t iter = 0; iter < this->symbol_table_slots; ++iter)
+ {
+ offset_type idx = 2 * iter;
+
+ if (this->symbol_table[idx] == 0
+ && this->symbol_table[idx + 1] == 0)
+ continue;
+
+ const char *name = this->symbol_name_at (idx);
+
+ /* Add each name component to the name component table. */
+ unsigned int previous_len = 0;
+ for (unsigned int current_len = cp_find_first_component (name);
+ name[current_len] != '\0';
+ current_len += cp_find_first_component (name + current_len))
+ {
+ gdb_assert (name[current_len] == ':');
+ this->name_components.push_back ({previous_len, idx});
+ /* Skip the '::'. */
+ current_len += 2;
+ previous_len = current_len;
+ }
+ this->name_components.push_back ({previous_len, idx});
+ }
+
+ /* Sort name_components elements by name. */
+ auto name_comp_compare = [&] (const name_component &left,
+ const name_component &right)
+ {
+ const char *left_qualified = this->symbol_name_at (left.idx);
+ const char *right_qualified = this->symbol_name_at (right.idx);
+
+ const char *left_name = left_qualified + left.name_offset;
+ const char *right_name = right_qualified + right.name_offset;
+
+ return name_cmp (left_name, right_name) < 0;
+ };
+
+ std::sort (this->name_components.begin (),
+ this->name_components.end (),
+ name_comp_compare);
+}
+
+/* Helper for dw2_expand_symtabs_matching that works with a
+ mapped_index instead of the containing objfile. This is split to a
+ separate function in order to be able to unit test the
+ name_components matching using a mock mapped_index. For each
+ symbol name that matches, calls MATCH_CALLBACK, passing it the
+ symbol's index in the mapped_index symbol table. */
+
+static void
+dw2_expand_symtabs_matching_symbol
+ (mapped_index &index,
+ const lookup_name_info &lookup_name_in,
+ gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
+ enum search_domain kind,
+ gdb::function_view<void (offset_type)> match_callback)
+{
+ lookup_name_info lookup_name_without_params
+ = lookup_name_in.make_ignore_params ();
+ gdb_index_symbol_name_matcher lookup_name_matcher
+ (lookup_name_without_params);
+
+ /* Build the symbol name component sorted vector, if we haven't
+ yet. */
+ index.build_name_components ();
+
+ auto bounds = index.find_name_components_bounds (lookup_name_without_params);
+
+ /* Now for each symbol name in range, check to see if we have a name
+ match, and if so, call the MATCH_CALLBACK callback. */
+
+ /* The same symbol may appear more than once in the range though.
+ E.g., if we're looking for symbols that complete "w", and we have
+ a symbol named "w1::w2", we'll find the two name components for
+ that same symbol in the range. To be sure we only call the
+ callback once per symbol, we first collect the symbol name
+ indexes that matched in a temporary vector and ignore
+ duplicates. */
+ std::vector<offset_type> matches;
+ matches.reserve (std::distance (bounds.first, bounds.second));
+
+ for (; bounds.first != bounds.second; ++bounds.first)
+ {
+ const char *qualified = index.symbol_name_at (bounds.first->idx);
+
+ if (!lookup_name_matcher.matches (qualified)
+ || (symbol_matcher != NULL && !symbol_matcher (qualified)))
+ continue;
+
+ matches.push_back (bounds.first->idx);
+ }
+
+ std::sort (matches.begin (), matches.end ());
+
+ /* Finally call the callback, once per match. */
+ ULONGEST prev = -1;
+ for (offset_type idx : matches)
+ {
+ if (prev != idx)
+ {
+ match_callback (idx);
+ prev = idx;
+ }
+ }
+
+ /* Above we use a type wider than idx's for 'prev', since 0 and
+ (offset_type)-1 are both possible values. */
+ static_assert (sizeof (prev) > sizeof (offset_type), "");
+}
+
+#if GDB_SELF_TEST
+
+namespace selftests { namespace dw2_expand_symtabs_matching {
+
+/* A wrapper around mapped_index that builds a mock mapped_index, from
+ the symbol list passed as parameter to the constructor. */
+class mock_mapped_index
+{
+public:
+ template<size_t N>
+ mock_mapped_index (const char *(&symbols)[N])
+ : mock_mapped_index (symbols, N)
+ {}
+
+ /* Access the built index. */
+ mapped_index &index ()
+ { return m_index; }
+
+ /* Disable copy. */
+ mock_mapped_index(const mock_mapped_index &) = delete;
+ void operator= (const mock_mapped_index &) = delete;
+
+private:
+ mock_mapped_index (const char **symbols, size_t symbols_size)
+ {
+ /* No string can live at offset zero. Add a dummy entry. */
+ obstack_grow_str0 (&m_constant_pool, "");
+
+ for (size_t i = 0; i < symbols_size; i++)
+ {
+ const char *sym = symbols[i];
+ size_t offset = obstack_object_size (&m_constant_pool);
+ obstack_grow_str0 (&m_constant_pool, sym);
+ m_symbol_table.push_back (offset);
+ m_symbol_table.push_back (0);
+ };
+
+ m_index.constant_pool = (const char *) obstack_base (&m_constant_pool);
+ m_index.symbol_table = m_symbol_table.data ();
+ m_index.symbol_table_slots = m_symbol_table.size () / 2;
+ }
+
+public:
+ /* The built mapped_index. */
+ mapped_index m_index{};
+
+ /* The storage that the built mapped_index uses for symbol and
+ constant pool tables. */
+ std::vector<offset_type> m_symbol_table;
+ auto_obstack m_constant_pool;
+};
+
+/* Convenience function that converts a NULL pointer to a "<null>"
+ string, to pass to print routines. */
+
+static const char *
+string_or_null (const char *str)
+{
+ return str != NULL ? str : "<null>";
+}
+
+/* Check if a lookup_name_info built from
+ NAME/MATCH_TYPE/COMPLETION_MODE matches the symbols in the mock
+ index. EXPECTED_LIST is the list of expected matches, in expected
+ matching order. If no match expected, then an empty list is
+ specified. Returns true on success. On failure prints a warning
+ indicating the file:line that failed, and returns false. */
+
+static bool
+check_match (const char *file, int line,
+ mock_mapped_index &mock_index,
+ const char *name, symbol_name_match_type match_type,
+ bool completion_mode,
+ std::initializer_list<const char *> expected_list)
+{
+ lookup_name_info lookup_name (name, match_type, completion_mode);
+
+ bool matched = true;
+
+ auto mismatch = [&] (const char *expected_str,
+ const char *got)
+ {
+ warning (_("%s:%d: match_type=%s, looking-for=\"%s\", "
+ "expected=\"%s\", got=\"%s\"\n"),
+ file, line,
+ (match_type == symbol_name_match_type::FULL
+ ? "FULL" : "WILD"),
+ name, string_or_null (expected_str), string_or_null (got));
+ matched = false;
+ };
+
+ auto expected_it = expected_list.begin ();
+ auto expected_end = expected_list.end ();
+
+ dw2_expand_symtabs_matching_symbol (mock_index.index (), lookup_name,
+ NULL, ALL_DOMAIN,
+ [&] (offset_type idx)
+ {
+ const char *matched_name = mock_index.index ().symbol_name_at (idx);
+ const char *expected_str
+ = expected_it == expected_end ? NULL : *expected_it++;
+
+ if (expected_str == NULL || strcmp (expected_str, matched_name) != 0)
+ mismatch (expected_str, matched_name);
+ });
+
+ const char *expected_str
+ = expected_it == expected_end ? NULL : *expected_it++;
+ if (expected_str != NULL)
+ mismatch (expected_str, NULL);
+
+ return matched;
+}
+
+/* The symbols added to the mock mapped_index for testing (in
+ canonical form). */
+static const char *test_symbols[] = {
+ "function",
+ "std::bar",
+ "std::zfunction",
+ "std::zfunction2",
+ "w1::w2",
+ "ns::foo<char*>",
+ "ns::foo<int>",
+ "ns::foo<long>",
+ "ns2::tmpl<int>::foo2",
+ "(anonymous namespace)::A::B::C",
+
+ /* These are used to check that the increment-last-char in the
+ matching algorithm for completion doesn't match "t1_fund" when
+ completing "t1_func". */
+ "t1_func",
+ "t1_func1",
+ "t1_fund",
+ "t1_fund1",
+
+ /* A UTF-8 name with multi-byte sequences to make sure that
+ cp-name-parser understands this as a single identifier ("função"
+ is "function" in PT). */
+ u8"u8função",
+
+ /* \377 (0xff) is Latin1 'ÿ'. */
+ "yfunc\377",
+
+ /* \377 (0xff) is Latin1 'ÿ'. */
+ "\377",
+ "\377\377123",
+
+ /* A name with all sorts of complications. Starts with "z" to make
+ it easier for the completion tests below. */
+#define Z_SYM_NAME \
+ "z::std::tuple<(anonymous namespace)::ui*, std::bar<(anonymous namespace)::ui> >" \
+ "::tuple<(anonymous namespace)::ui*, " \
+ "std::default_delete<(anonymous namespace)::ui>, void>"
+
+ Z_SYM_NAME
+};
+
+/* Returns true if the mapped_index::find_name_component_bounds method
+ finds EXPECTED_SYMS in INDEX when looking for SEARCH_NAME, in
+ completion mode. */
+
+static bool
+check_find_bounds_finds (mapped_index &index,
+ const char *search_name,
+ gdb::array_view<const char *> expected_syms)
+{
+ lookup_name_info lookup_name (search_name,
+ symbol_name_match_type::FULL, true);
+
+ auto bounds = index.find_name_components_bounds (lookup_name);
+
+ size_t distance = std::distance (bounds.first, bounds.second);
+ if (distance != expected_syms.size ())
+ return false;
+
+ for (size_t exp_elem = 0; exp_elem < distance; exp_elem++)
+ {
+ auto nc_elem = bounds.first + exp_elem;
+ const char *qualified = index.symbol_name_at (nc_elem->idx);
+ if (strcmp (qualified, expected_syms[exp_elem]) != 0)
+ return false;
+ }
+
+ return true;
+}
+
+/* Test the lower-level mapped_index::find_name_component_bounds
+ method. */
+
+static void
+test_mapped_index_find_name_component_bounds ()
+{
+ mock_mapped_index mock_index (test_symbols);
+
+ mock_index.index ().build_name_components ();
+
+ /* Test the lower-level mapped_index::find_name_component_bounds
+ method in completion mode. */
+ {
+ static const char *expected_syms[] = {
+ "t1_func",
+ "t1_func1",
+ };
+
+ SELF_CHECK (check_find_bounds_finds (mock_index.index (),
+ "t1_func", expected_syms));
+ }
+
+ /* Check that the increment-last-char in the name matching algorithm
+ for completion doesn't get confused with Ansi1 'ÿ' / 0xff. */
+ {
+ static const char *expected_syms1[] = {
+ "\377",
+ "\377\377123",
+ };
+ SELF_CHECK (check_find_bounds_finds (mock_index.index (),
+ "\377", expected_syms1));
+
+ static const char *expected_syms2[] = {
+ "\377\377123",
+ };
+ SELF_CHECK (check_find_bounds_finds (mock_index.index (),
+ "\377\377", expected_syms2));
+ }
+}
+
+/* Test dw2_expand_symtabs_matching_symbol. */
+
+static void
+test_dw2_expand_symtabs_matching_symbol ()
+{
+ mock_mapped_index mock_index (test_symbols);
+
+ /* We let all tests run until the end even if some fails, for debug
+ convenience. */
+ bool any_mismatch = false;
+
+ /* Create the expected symbols list (an initializer_list). Needed
+ because lists have commas, and we need to pass them to CHECK,
+ which is a macro. */
+#define EXPECT(...) { __VA_ARGS__ }
+
+ /* Wrapper for check_match that passes down the current
+ __FILE__/__LINE__. */
+#define CHECK_MATCH(NAME, MATCH_TYPE, COMPLETION_MODE, EXPECTED_LIST) \
+ any_mismatch |= !check_match (__FILE__, __LINE__, \
+ mock_index, \
+ NAME, MATCH_TYPE, COMPLETION_MODE, \
+ EXPECTED_LIST)
+
+ /* Identity checks. */
+ for (const char *sym : test_symbols)
+ {
+ /* Should be able to match all existing symbols. */
+ CHECK_MATCH (sym, symbol_name_match_type::FULL, false,
+ EXPECT (sym));
+
+ /* Should be able to match all existing symbols with
+ parameters. */
+ std::string with_params = std::string (sym) + "(int)";
+ CHECK_MATCH (with_params.c_str (), symbol_name_match_type::FULL, false,
+ EXPECT (sym));
+
+ /* Should be able to match all existing symbols with
+ parameters and qualifiers. */
+ with_params = std::string (sym) + " ( int ) const";
+ CHECK_MATCH (with_params.c_str (), symbol_name_match_type::FULL, false,
+ EXPECT (sym));
+
+ /* This should really find sym, but cp-name-parser.y doesn't
+ know about lvalue/rvalue qualifiers yet. */
+ with_params = std::string (sym) + " ( int ) &&";
+ CHECK_MATCH (with_params.c_str (), symbol_name_match_type::FULL, false,
+ {});
+ }
+
+ /* Check that the name matching algorithm for completion doesn't get
+ confused with Latin1 'ÿ' / 0xff. */
+ {
+ static const char str[] = "\377";
+ CHECK_MATCH (str, symbol_name_match_type::FULL, true,
+ EXPECT ("\377", "\377\377123"));
+ }
+
+ /* Check that the increment-last-char in the matching algorithm for
+ completion doesn't match "t1_fund" when completing "t1_func". */
+ {
+ static const char str[] = "t1_func";
+ CHECK_MATCH (str, symbol_name_match_type::FULL, true,
+ EXPECT ("t1_func", "t1_func1"));
+ }
+
+ /* Check that completion mode works at each prefix of the expected
+ symbol name. */
+ {
+ static const char str[] = "function(int)";
+ size_t len = strlen (str);
+ std::string lookup;
+
+ for (size_t i = 1; i < len; i++)
+ {
+ lookup.assign (str, i);
+ CHECK_MATCH (lookup.c_str (), symbol_name_match_type::FULL, true,
+ EXPECT ("function"));
+ }
+ }
+
+ /* While "w" is a prefix of both components, the match function
+ should still only be called once. */
+ {
+ CHECK_MATCH ("w", symbol_name_match_type::FULL, true,
+ EXPECT ("w1::w2"));
+ CHECK_MATCH ("w", symbol_name_match_type::WILD, true,
+ EXPECT ("w1::w2"));
+ }
+
+ /* Same, with a "complicated" symbol. */
+ {
+ static const char str[] = Z_SYM_NAME;
+ size_t len = strlen (str);
+ std::string lookup;
+
+ for (size_t i = 1; i < len; i++)
+ {
+ lookup.assign (str, i);
+ CHECK_MATCH (lookup.c_str (), symbol_name_match_type::FULL, true,
+ EXPECT (Z_SYM_NAME));
+ }
+ }
+
+ /* In FULL mode, an incomplete symbol doesn't match. */
+ {
+ CHECK_MATCH ("std::zfunction(int", symbol_name_match_type::FULL, false,
+ {});
+ }
+
+ /* A complete symbol with parameters matches any overload, since the
+ index has no overload info. */
+ {
+ CHECK_MATCH ("std::zfunction(int)", symbol_name_match_type::FULL, true,
+ EXPECT ("std::zfunction", "std::zfunction2"));
+ CHECK_MATCH ("zfunction(int)", symbol_name_match_type::WILD, true,
+ EXPECT ("std::zfunction", "std::zfunction2"));
+ CHECK_MATCH ("zfunc", symbol_name_match_type::WILD, true,
+ EXPECT ("std::zfunction", "std::zfunction2"));
+ }
+
+ /* Check that whitespace is ignored appropriately. A symbol with a
+ template argument list. */
+ {
+ static const char expected[] = "ns::foo<int>";
+ CHECK_MATCH ("ns :: foo < int > ", symbol_name_match_type::FULL, false,
+ EXPECT (expected));
+ CHECK_MATCH ("foo < int > ", symbol_name_match_type::WILD, false,
+ EXPECT (expected));
+ }
+
+ /* Check that whitespace is ignored appropriately. A symbol with a
+ template argument list that includes a pointer. */
+ {
+ static const char expected[] = "ns::foo<char*>";
+ /* Try both completion and non-completion modes. */
+ static const bool completion_mode[2] = {false, true};
+ for (size_t i = 0; i < 2; i++)
+ {
+ CHECK_MATCH ("ns :: foo < char * >", symbol_name_match_type::FULL,
+ completion_mode[i], EXPECT (expected));
+ CHECK_MATCH ("foo < char * >", symbol_name_match_type::WILD,
+ completion_mode[i], EXPECT (expected));
+
+ CHECK_MATCH ("ns :: foo < char * > (int)", symbol_name_match_type::FULL,
+ completion_mode[i], EXPECT (expected));
+ CHECK_MATCH ("foo < char * > (int)", symbol_name_match_type::WILD,
+ completion_mode[i], EXPECT (expected));
+ }
+ }
+
+ {
+ /* Check method qualifiers are ignored. */
+ static const char expected[] = "ns::foo<char*>";
+ CHECK_MATCH ("ns :: foo < char * > ( int ) const",
+ symbol_name_match_type::FULL, true, EXPECT (expected));
+ CHECK_MATCH ("ns :: foo < char * > ( int ) &&",
+ symbol_name_match_type::FULL, true, EXPECT (expected));
+ CHECK_MATCH ("foo < char * > ( int ) const",
+ symbol_name_match_type::WILD, true, EXPECT (expected));
+ CHECK_MATCH ("foo < char * > ( int ) &&",
+ symbol_name_match_type::WILD, true, EXPECT (expected));
+ }
+
+ /* Test lookup names that don't match anything. */
+ {
+ CHECK_MATCH ("bar2", symbol_name_match_type::WILD, false,
+ {});
+
+ CHECK_MATCH ("doesntexist", symbol_name_match_type::FULL, false,
+ {});
+ }
+
+ /* Some wild matching tests, exercising "(anonymous namespace)",
+ which should not be confused with a parameter list. */
+ {
+ static const char *syms[] = {
+ "A::B::C",
+ "B::C",
+ "C",
+ "A :: B :: C ( int )",
+ "B :: C ( int )",
+ "C ( int )",
+ };
+
+ for (const char *s : syms)
+ {
+ CHECK_MATCH (s, symbol_name_match_type::WILD, false,
+ EXPECT ("(anonymous namespace)::A::B::C"));
+ }
+ }
+
+ {
+ static const char expected[] = "ns2::tmpl<int>::foo2";
+ CHECK_MATCH ("tmp", symbol_name_match_type::WILD, true,
+ EXPECT (expected));
+ CHECK_MATCH ("tmpl<", symbol_name_match_type::WILD, true,
+ EXPECT (expected));
+ }
- for (i = 0; i < (dwarf2_per_objfile->n_comp_units
- + dwarf2_per_objfile->n_type_units); ++i)
- {
- struct dwarf2_per_cu_data *per_cu = dw2_get_cutu (i);
+ SELF_CHECK (!any_mismatch);
- dw2_instantiate_symtab (per_cu);
- }
+#undef EXPECT
+#undef CHECK_MATCH
}
static void
-dw2_expand_symtabs_with_fullname (struct objfile *objfile,
- const char *fullname)
+run_test ()
{
- int i;
+ test_mapped_index_find_name_component_bounds ();
+ test_dw2_expand_symtabs_matching_symbol ();
+}
- dw2_setup (objfile);
+}} // namespace selftests::dw2_expand_symtabs_matching
- /* We don't need to consider type units here.
- This is only called for examining code, e.g. expand_line_sal.
- There can be an order of magnitude (or more) more type units
- than comp units, and we avoid them if we can. */
+#endif /* GDB_SELF_TEST */
- for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
- {
- int j;
- struct dwarf2_per_cu_data *per_cu = dw2_get_cutu (i);
- struct quick_file_names *file_data;
+/* Helper for dw2_expand_matching symtabs. Called on each symbol
+ matched, to expand corresponding CUs that were marked. IDX is the
+ index of the symbol name that matched. */
- /* We only need to look at symtabs not already expanded. */
- if (per_cu->v.quick->compunit_symtab)
- continue;
+static void
+dw2_expand_marked_cus
+ (mapped_index &index, offset_type idx,
+ struct objfile *objfile,
+ gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
+ gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
+ search_domain kind)
+{
+ offset_type *vec, vec_len, vec_idx;
+ bool global_seen = false;
- file_data = dw2_get_file_names (per_cu);
- if (file_data == NULL)
- continue;
+ vec = (offset_type *) (index.constant_pool
+ + MAYBE_SWAP (index.symbol_table[idx + 1]));
+ vec_len = MAYBE_SWAP (vec[0]);
+ for (vec_idx = 0; vec_idx < vec_len; ++vec_idx)
+ {
+ struct dwarf2_per_cu_data *per_cu;
+ offset_type cu_index_and_attrs = MAYBE_SWAP (vec[vec_idx + 1]);
+ /* This value is only valid for index versions >= 7. */
+ int is_static = GDB_INDEX_SYMBOL_STATIC_VALUE (cu_index_and_attrs);
+ gdb_index_symbol_kind symbol_kind =
+ GDB_INDEX_SYMBOL_KIND_VALUE (cu_index_and_attrs);
+ int cu_index = GDB_INDEX_CU_VALUE (cu_index_and_attrs);
+ /* Only check the symbol attributes if they're present.
+ Indices prior to version 7 don't record them,
+ and indices >= 7 may elide them for certain symbols
+ (gold does this). */
+ int attrs_valid =
+ (index.version >= 7
+ && symbol_kind != GDB_INDEX_SYMBOL_KIND_NONE);
- for (j = 0; j < file_data->num_file_names; ++j)
+ /* Work around gold/15646. */
+ if (attrs_valid)
{
- const char *this_fullname = file_data->file_names[j];
+ if (!is_static && global_seen)
+ continue;
+ if (!is_static)
+ global_seen = true;
+ }
- if (filename_cmp (this_fullname, fullname) == 0)
+ /* Only check the symbol's kind if it has one. */
+ if (attrs_valid)
+ {
+ switch (kind)
{
- dw2_instantiate_symtab (per_cu);
+ case VARIABLES_DOMAIN:
+ if (symbol_kind != GDB_INDEX_SYMBOL_KIND_VARIABLE)
+ continue;
+ break;
+ case FUNCTIONS_DOMAIN:
+ if (symbol_kind != GDB_INDEX_SYMBOL_KIND_FUNCTION)
+ continue;
+ break;
+ case TYPES_DOMAIN:
+ if (symbol_kind != GDB_INDEX_SYMBOL_KIND_TYPE)
+ continue;
+ break;
+ default:
break;
}
}
- }
-}
-static void
-dw2_map_matching_symbols (struct objfile *objfile,
- const char * name, domain_enum domain,
- int global,
- int (*callback) (struct block *,
- struct symbol *, void *),
- void *data, symbol_compare_ftype *match,
- symbol_compare_ftype *ordered_compare)
-{
- /* Currently unimplemented; used for Ada. The function can be called if the
- current language is Ada for a non-Ada objfile using GNU index. As Ada
- does not look for non-Ada symbols this function should just return. */
+ /* Don't crash on bad data. */
+ if (cu_index >= (dwarf2_per_objfile->n_comp_units
+ + dwarf2_per_objfile->n_type_units))
+ {
+ complaint (&symfile_complaints,
+ _(".gdb_index entry has bad CU index"
+ " [in module %s]"), objfile_name (objfile));
+ continue;
+ }
+
+ per_cu = dw2_get_cutu (cu_index);
+ if (file_matcher == NULL || per_cu->v.quick->mark)
+ {
+ int symtab_was_null =
+ (per_cu->v.quick->compunit_symtab == NULL);
+
+ dw2_instantiate_symtab (per_cu);
+
+ if (expansion_notify != NULL
+ && symtab_was_null
+ && per_cu->v.quick->compunit_symtab != NULL)
+ expansion_notify (per_cu->v.quick->compunit_symtab);
+ }
+ }
}
static void
dw2_expand_symtabs_matching
(struct objfile *objfile,
gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
+ const lookup_name_info &lookup_name,
gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
enum search_domain kind)
{
int i;
- offset_type iter;
- struct mapped_index *index;
dw2_setup (objfile);
/* index_table is NULL if OBJF_READNOW. */
if (!dwarf2_per_objfile->index_table)
return;
- index = dwarf2_per_objfile->index_table;
if (file_matcher != NULL)
{
}
}
- for (iter = 0; iter < index->symbol_table_slots; ++iter)
- {
- offset_type idx = 2 * iter;
- const char *name;
- offset_type *vec, vec_len, vec_idx;
- int global_seen = 0;
-
- QUIT;
-
- if (index->symbol_table[idx] == 0 && index->symbol_table[idx + 1] == 0)
- continue;
-
- name = index->constant_pool + MAYBE_SWAP (index->symbol_table[idx]);
-
- if (!symbol_matcher (name))
- continue;
-
- /* The name was matched, now expand corresponding CUs that were
- marked. */
- vec = (offset_type *) (index->constant_pool
- + MAYBE_SWAP (index->symbol_table[idx + 1]));
- vec_len = MAYBE_SWAP (vec[0]);
- for (vec_idx = 0; vec_idx < vec_len; ++vec_idx)
- {
- struct dwarf2_per_cu_data *per_cu;
- offset_type cu_index_and_attrs = MAYBE_SWAP (vec[vec_idx + 1]);
- /* This value is only valid for index versions >= 7. */
- int is_static = GDB_INDEX_SYMBOL_STATIC_VALUE (cu_index_and_attrs);
- gdb_index_symbol_kind symbol_kind =
- GDB_INDEX_SYMBOL_KIND_VALUE (cu_index_and_attrs);
- int cu_index = GDB_INDEX_CU_VALUE (cu_index_and_attrs);
- /* Only check the symbol attributes if they're present.
- Indices prior to version 7 don't record them,
- and indices >= 7 may elide them for certain symbols
- (gold does this). */
- int attrs_valid =
- (index->version >= 7
- && symbol_kind != GDB_INDEX_SYMBOL_KIND_NONE);
-
- /* Work around gold/15646. */
- if (attrs_valid)
- {
- if (!is_static && global_seen)
- continue;
- if (!is_static)
- global_seen = 1;
- }
-
- /* Only check the symbol's kind if it has one. */
- if (attrs_valid)
- {
- switch (kind)
- {
- case VARIABLES_DOMAIN:
- if (symbol_kind != GDB_INDEX_SYMBOL_KIND_VARIABLE)
- continue;
- break;
- case FUNCTIONS_DOMAIN:
- if (symbol_kind != GDB_INDEX_SYMBOL_KIND_FUNCTION)
- continue;
- break;
- case TYPES_DOMAIN:
- if (symbol_kind != GDB_INDEX_SYMBOL_KIND_TYPE)
- continue;
- break;
- default:
- break;
- }
- }
-
- /* Don't crash on bad data. */
- if (cu_index >= (dwarf2_per_objfile->n_comp_units
- + dwarf2_per_objfile->n_type_units))
- {
- complaint (&symfile_complaints,
- _(".gdb_index entry has bad CU index"
- " [in module %s]"), objfile_name (objfile));
- continue;
- }
-
- per_cu = dw2_get_cutu (cu_index);
- if (file_matcher == NULL || per_cu->v.quick->mark)
- {
- int symtab_was_null =
- (per_cu->v.quick->compunit_symtab == NULL);
-
- dw2_instantiate_symtab (per_cu);
+ mapped_index &index = *dwarf2_per_objfile->index_table;
- if (expansion_notify != NULL
- && symtab_was_null
- && per_cu->v.quick->compunit_symtab != NULL)
- {
- expansion_notify (per_cu->v.quick->compunit_symtab);
- }
- }
- }
- }
+ dw2_expand_symtabs_matching_symbol (index, lookup_name,
+ symbol_matcher,
+ kind, [&] (offset_type idx)
+ {
+ dw2_expand_marked_cus (index, idx, objfile, file_matcher,
+ expansion_notify, kind);
+ });
}
/* A helper for dw2_find_pc_sect_compunit_symtab which finds the most specific
dw2_map_symbol_filenames (struct objfile *objfile, symbol_filename_ftype *fun,
void *data, int need_fullname)
{
- int i;
- htab_up visited (htab_create_alloc (10, htab_hash_pointer, htab_eq_pointer,
- NULL, xcalloc, xfree));
-
dw2_setup (objfile);
- /* The rule is CUs specify all the files, including those used by
- any TU, so there's no need to scan TUs here.
- We can ignore file names coming from already-expanded CUs. */
-
- for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ if (!dwarf2_per_objfile->filenames_cache)
{
- struct dwarf2_per_cu_data *per_cu = dw2_get_cutu (i);
-
- if (per_cu->v.quick->compunit_symtab)
- {
- void **slot = htab_find_slot (visited.get (),
- per_cu->v.quick->file_names,
- INSERT);
+ dwarf2_per_objfile->filenames_cache.emplace ();
- *slot = per_cu->v.quick->file_names;
- }
- }
+ htab_up visited (htab_create_alloc (10,
+ htab_hash_pointer, htab_eq_pointer,
+ NULL, xcalloc, xfree));
- for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
- {
- int j;
- struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i);
- struct quick_file_names *file_data;
- void **slot;
+ /* The rule is CUs specify all the files, including those used
+ by any TU, so there's no need to scan TUs here. We can
+ ignore file names coming from already-expanded CUs. */
- /* We only need to look at symtabs not already expanded. */
- if (per_cu->v.quick->compunit_symtab)
- continue;
+ for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ {
+ struct dwarf2_per_cu_data *per_cu = dw2_get_cutu (i);
- file_data = dw2_get_file_names (per_cu);
- if (file_data == NULL)
- continue;
+ if (per_cu->v.quick->compunit_symtab)
+ {
+ void **slot = htab_find_slot (visited.get (),
+ per_cu->v.quick->file_names,
+ INSERT);
- slot = htab_find_slot (visited.get (), file_data, INSERT);
- if (*slot)
- {
- /* Already visited. */
- continue;
+ *slot = per_cu->v.quick->file_names;
+ }
}
- *slot = file_data;
- for (j = 0; j < file_data->num_file_names; ++j)
+ for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
{
- const char *this_real_name;
+ struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i);
+ struct quick_file_names *file_data;
+ void **slot;
- if (need_fullname)
- this_real_name = dw2_get_real_path (objfile, file_data, j);
- else
- this_real_name = NULL;
- (*fun) (file_data->file_names[j], this_real_name, data);
+ /* We only need to look at symtabs not already expanded. */
+ if (per_cu->v.quick->compunit_symtab)
+ continue;
+
+ file_data = dw2_get_file_names (per_cu);
+ if (file_data == NULL)
+ continue;
+
+ slot = htab_find_slot (visited.get (), file_data, INSERT);
+ if (*slot)
+ {
+ /* Already visited. */
+ continue;
+ }
+ *slot = file_data;
+
+ for (int j = 0; j < file_data->num_file_names; ++j)
+ {
+ const char *filename = file_data->file_names[j];
+ dwarf2_per_objfile->filenames_cache->seen (filename);
+ }
}
}
+
+ dwarf2_per_objfile->filenames_cache->traverse ([&] (const char *filename)
+ {
+ gdb::unique_xmalloc_ptr<char> this_real_name;
+
+ if (need_fullname)
+ this_real_name = gdb_realpath (filename);
+ (*fun) (filename, this_real_name.get (), data);
+ });
}
static int
dw2_map_matching_symbols,
dw2_expand_symtabs_matching,
dw2_find_pc_sect_compunit_symtab,
+ NULL,
dw2_map_symbol_filenames
};
dwarf2_build_psymtabs (struct objfile *objfile)
{
- if (objfile->global_psymbols.size == 0 && objfile->static_psymbols.size == 0)
- {
- init_psymbol_list (objfile, 1024);
- }
+ if (objfile->global_psymbols.capacity () == 0
+ && objfile->static_psymbols.capacity () == 0)
+ init_psymbol_list (objfile, 1024);
TRY
{
rcuh_kind section_kind)
{
const gdb_byte *beg_of_comp_unit = info_ptr;
- bfd *abfd = get_section_bfd_owner (section);
header->sect_off = (sect_offset) (beg_of_comp_unit - section->buffer);
struct dwarf2_section_info *section;
bfd *abfd;
const gdb_byte *begin_info_ptr, *info_ptr;
- ULONGEST signature; /* Or dwo_id. */
struct attribute *comp_dir, *stmt_list, *low_pc, *high_pc, *ranges;
int i,num_extra_attrs;
struct dwarf2_section_info *dwo_abbrev_section;
struct die_info *comp_unit_die)
{
struct dwarf2_cu *cu = this_cu->cu;
- struct attribute *attr;
ULONGEST signature;
struct dwo_unit *dwo_unit;
const char *comp_dir, *dwo_name;
struct partial_symtab *pst;
pst = start_psymtab_common (objfile, name, 0,
- objfile->global_psymbols.next,
- objfile->static_psymbols.next);
+ objfile->global_psymbols,
+ objfile->static_psymbols);
pst->psymtabs_addrmap_supported = 1;
int want_partial_unit,
enum language pretend_language)
{
- struct process_psymtab_comp_unit_data info;
-
/* If this compilation unit was already read in, free the
cached copy in order to read it in again. This is
necessary because we skipped some symbols when we first
if (this_cu->cu != NULL)
free_one_cached_comp_unit (this_cu);
- gdb_assert (! this_cu->is_debug_types);
- info.want_partial_unit = want_partial_unit;
- info.pretend_language = pretend_language;
- init_cutu_and_read_dies (this_cu, NULL, 0, 0,
- process_psymtab_comp_unit_reader,
- &info);
+ if (this_cu->is_debug_types)
+ init_cutu_and_read_dies (this_cu, NULL, 0, 0, build_type_psymtabs_reader,
+ NULL);
+ else
+ {
+ process_psymtab_comp_unit_data info;
+ info.want_partial_unit = want_partial_unit;
+ info.pretend_language = pretend_language;
+ init_cutu_and_read_dies (this_cu, NULL, 0, 0,
+ process_psymtab_comp_unit_reader, &info);
+ }
/* Age out any secondary CUs. */
age_cached_comp_units ();
}
}
-/* A cleanup function that clears objfile's psymtabs_addrmap field. */
-
-static void
-psymtabs_addrmap_cleanup (void *o)
-{
- struct objfile *objfile = (struct objfile *) o;
-
- objfile->psymtabs_addrmap = NULL;
-}
-
/* Compute the 'user' field for each psymtab in OBJFILE. */
static void
static void
dwarf2_build_psymtabs_hard (struct objfile *objfile)
{
- struct cleanup *back_to, *addrmap_cleanup;
- struct obstack temp_obstack;
+ struct cleanup *back_to;
int i;
if (dwarf_read_debug)
/* Create a temporary address map on a temporary obstack. We later
copy this to the final obstack. */
- obstack_init (&temp_obstack);
- make_cleanup_obstack_free (&temp_obstack);
- objfile->psymtabs_addrmap = addrmap_create_mutable (&temp_obstack);
- addrmap_cleanup = make_cleanup (psymtabs_addrmap_cleanup, objfile);
+ auto_obstack temp_obstack;
+
+ scoped_restore save_psymtabs_addrmap
+ = make_scoped_restore (&objfile->psymtabs_addrmap,
+ addrmap_create_mutable (&temp_obstack));
for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
{
objfile->psymtabs_addrmap = addrmap_create_fixed (objfile->psymtabs_addrmap,
&objfile->objfile_obstack);
- discard_cleanups (addrmap_cleanup);
+ /* At this point we want to keep the address map. */
+ save_psymtabs_addrmap.release ();
do_cleanups (back_to);
static void
read_comp_units_from_section (struct objfile *objfile,
struct dwarf2_section_info *section,
+ struct dwarf2_section_info *abbrev_section,
unsigned int is_dwz,
int *n_allocated,
int *n_comp_units,
struct dwarf2_per_cu_data ***all_comp_units)
{
const gdb_byte *info_ptr;
- bfd *abfd = get_section_bfd_owner (section);
if (dwarf_read_debug)
fprintf_unfiltered (gdb_stdlog, "Reading %s for %s\n",
while (info_ptr < section->buffer + section->size)
{
- unsigned int length, initial_length_size;
struct dwarf2_per_cu_data *this_cu;
sect_offset sect_off = (sect_offset) (info_ptr - section->buffer);
- /* Read just enough information to find out where the next
- compilation unit is. */
- length = read_initial_length (abfd, info_ptr, &initial_length_size);
+ comp_unit_head cu_header;
+ read_and_check_comp_unit_head (&cu_header, section, abbrev_section,
+ info_ptr, rcuh_kind::COMPILE);
/* Save the compilation unit for later lookup. */
- this_cu = XOBNEW (&objfile->objfile_obstack, struct dwarf2_per_cu_data);
- memset (this_cu, 0, sizeof (*this_cu));
+ if (cu_header.unit_type != DW_UT_type)
+ {
+ this_cu = XOBNEW (&objfile->objfile_obstack,
+ struct dwarf2_per_cu_data);
+ memset (this_cu, 0, sizeof (*this_cu));
+ }
+ else
+ {
+ auto sig_type = XOBNEW (&objfile->objfile_obstack,
+ struct signatured_type);
+ memset (sig_type, 0, sizeof (*sig_type));
+ sig_type->signature = cu_header.signature;
+ sig_type->type_offset_in_tu = cu_header.type_cu_offset_in_tu;
+ this_cu = &sig_type->per_cu;
+ }
+ this_cu->is_debug_types = (cu_header.unit_type == DW_UT_type);
this_cu->sect_off = sect_off;
- this_cu->length = length + initial_length_size;
+ this_cu->length = cu_header.length + cu_header.initial_length_size;
this_cu->is_dwz = is_dwz;
this_cu->objfile = objfile;
this_cu->section = section;
n_allocated = 10;
all_comp_units = XNEWVEC (struct dwarf2_per_cu_data *, n_allocated);
- read_comp_units_from_section (objfile, &dwarf2_per_objfile->info, 0,
+ read_comp_units_from_section (objfile, &dwarf2_per_objfile->info,
+ &dwarf2_per_objfile->abbrev, 0,
&n_allocated, &n_comp_units, &all_comp_units);
dwz = dwarf2_get_dwz_file ();
if (dwz != NULL)
- read_comp_units_from_section (objfile, &dwz->info, 1,
+ read_comp_units_from_section (objfile, &dwz->info, &dwz->abbrev, 1,
&n_allocated, &n_comp_units,
&all_comp_units);
break;
case DW_TAG_constant:
{
- struct psymbol_allocation_list *list;
+ std::vector<partial_symbol *> *list;
if (pdi->is_external)
list = &objfile->global_psymbols;
}
}
+/* Check whether [PHYSNAME, PHYSNAME+LEN) ends with a modifier like
+ "const" / "volatile". If so, decrements LEN by the length of the
+ modifier and return true. Otherwise return false. */
+
+template<size_t N>
+static bool
+check_modifier (const char *physname, size_t &len, const char (&mod)[N])
+{
+ size_t mod_len = sizeof (mod) - 1;
+ if (len > mod_len && startswith (physname + (len - mod_len), mod))
+ {
+ len -= mod_len;
+ return true;
+ }
+ return false;
+}
+
/* Compute the physnames of any methods on the CU's method list.
The computation of method physnames is delayed in order to avoid the
{
int i;
struct delayed_method_info *mi;
+
+ /* Only C++ delays computing physnames. */
+ if (VEC_empty (delayed_method_info, cu->method_list))
+ return;
+ gdb_assert (cu->language == language_cplus);
+
for (i = 0; VEC_iterate (delayed_method_info, cu->method_list, i, mi) ; ++i)
{
const char *physname;
physname = dwarf2_physname (mi->name, mi->die, cu);
TYPE_FN_FIELD_PHYSNAME (fn_flp->fn_fields, mi->index)
= physname ? physname : "";
+
+ /* Since there's no tag to indicate whether a method is a
+ const/volatile overload, extract that information out of the
+ demangled name. */
+ if (physname != NULL)
+ {
+ size_t len = strlen (physname);
+
+ while (1)
+ {
+ if (physname[len] == ')') /* shortcut */
+ break;
+ else if (check_modifier (physname, len, " const"))
+ TYPE_FN_FIELD_CONST (fn_flp->fn_fields, mi->index) = 1;
+ else if (check_modifier (physname, len, " volatile"))
+ TYPE_FN_FIELD_VOLATILE (fn_flp->fn_fields, mi->index) = 1;
+ else
+ break;
+ }
+ }
}
}
struct gdbarch *gdbarch = get_objfile_arch (objfile);
CORE_ADDR lowpc, highpc;
struct compunit_symtab *cust;
- struct cleanup *back_to, *delayed_list_cleanup;
+ struct cleanup *delayed_list_cleanup;
CORE_ADDR baseaddr;
struct block *static_block;
CORE_ADDR addr;
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
buildsym_init ();
- back_to = make_cleanup (really_free_pendings, NULL);
+ scoped_free_pendings free_pending;
delayed_list_cleanup = make_cleanup (free_delayed_list, cu);
cu->list_in_scope = &file_symbols;
/* Push it for inclusion processing later. */
VEC_safe_push (dwarf2_per_cu_ptr, dwarf2_per_objfile->just_read_cus, per_cu);
-
- do_cleanups (back_to);
}
/* Generate full symbol information for type unit PER_CU, whose DIEs have
struct dwarf2_cu *cu = per_cu->cu;
struct objfile *objfile = per_cu->objfile;
struct compunit_symtab *cust;
- struct cleanup *back_to, *delayed_list_cleanup;
+ struct cleanup *delayed_list_cleanup;
struct signatured_type *sig_type;
gdb_assert (per_cu->is_debug_types);
sig_type = (struct signatured_type *) per_cu;
buildsym_init ();
- back_to = make_cleanup (really_free_pendings, NULL);
+ scoped_free_pendings free_pending;
delayed_list_cleanup = make_cleanup (free_delayed_list, cu);
cu->list_in_scope = &file_symbols;
pst->compunit_symtab = cust;
pst->readin = 1;
}
-
- do_cleanups (back_to);
}
/* Process an imported unit DIE. */
}
}
-/* Reset the in_process bit of a die. */
-
-static void
-reset_die_in_process (void *arg)
+/* RAII object that represents a process_die scope: i.e.,
+ starts/finishes processing a DIE. */
+class process_die_scope
{
- struct die_info *die = (struct die_info *) arg;
+public:
+ process_die_scope (die_info *die, dwarf2_cu *cu)
+ : m_die (die), m_cu (cu)
+ {
+ /* We should only be processing DIEs not already in process. */
+ gdb_assert (!m_die->in_process);
+ m_die->in_process = true;
+ }
+
+ ~process_die_scope ()
+ {
+ m_die->in_process = false;
+
+ /* If we're done processing the DIE for the CU that owns the line
+ header, we don't need the line header anymore. */
+ if (m_cu->line_header_die_owner == m_die)
+ {
+ delete m_cu->line_header;
+ m_cu->line_header = NULL;
+ m_cu->line_header_die_owner = NULL;
+ }
+ }
- die->in_process = 0;
-}
+private:
+ die_info *m_die;
+ dwarf2_cu *m_cu;
+};
/* Process a die and its children. */
static void
process_die (struct die_info *die, struct dwarf2_cu *cu)
{
- struct cleanup *in_process;
-
- /* We should only be processing those not already in process. */
- gdb_assert (!die->in_process);
-
- die->in_process = 1;
- in_process = make_cleanup (reset_die_in_process,die);
+ process_die_scope scope (die, cu);
switch (die->tag)
{
process_imported_unit_die (die, cu);
break;
+ case DW_TAG_variable:
+ read_variable (die, cu);
+ break;
+
default:
new_symbol (die, NULL, cu);
break;
}
-
- do_cleanups (in_process);
}
\f
/* DWARF name computation. */
}
}
+/* Return the DIE's linkage name attribute, either DW_AT_linkage_name
+ or DW_AT_MIPS_linkage_name. Returns NULL if the attribute is not
+ defined for the given DIE. */
+
+static struct attribute *
+dw2_linkage_name_attr (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct attribute *attr;
+
+ attr = dwarf2_attr (die, DW_AT_linkage_name, cu);
+ if (attr == NULL)
+ attr = dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu);
+
+ return attr;
+}
+
+/* Return the DIE's linkage name as a string, either DW_AT_linkage_name
+ or DW_AT_MIPS_linkage_name. Returns NULL if the attribute is not
+ defined for the given DIE. */
+
+static const char *
+dw2_linkage_name (struct die_info *die, struct dwarf2_cu *cu)
+{
+ const char *linkage_name;
+
+ linkage_name = dwarf2_string_attr (die, DW_AT_linkage_name, cu);
+ if (linkage_name == NULL)
+ linkage_name = dwarf2_string_attr (die, DW_AT_MIPS_linkage_name, cu);
+
+ return linkage_name;
+}
+
/* 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++),
to be able to reference. Ideally, we want the user to be able
to reference this entity using either natural or linkage name,
but we haven't started looking at this enhancement yet. */
- const char *linkage_name;
+ const char *linkage_name = dw2_linkage_name (die, cu);
- linkage_name = dwarf2_string_attr (die, DW_AT_linkage_name, cu);
- if (linkage_name == NULL)
- linkage_name = dwarf2_string_attr (die, DW_AT_MIPS_linkage_name, cu);
if (linkage_name != NULL)
return linkage_name;
}
{
if (die_needs_namespace (die, cu))
{
- long length;
const char *prefix;
const char *canonical_name = NULL;
{
struct objfile *objfile = cu->objfile;
const char *retval, *mangled = NULL, *canon = NULL;
- struct cleanup *back_to;
int need_copy = 1;
/* In this case dwarf2_compute_name is just a shortcut not building anything
if (!die_needs_namespace (die, cu))
return dwarf2_compute_name (name, die, cu, 1);
- back_to = make_cleanup (null_cleanup, NULL);
-
- mangled = dwarf2_string_attr (die, DW_AT_linkage_name, cu);
- if (mangled == NULL)
- mangled = dwarf2_string_attr (die, DW_AT_MIPS_linkage_name, cu);
+ mangled = dw2_linkage_name (die, cu);
/* rustc emits invalid values for DW_AT_linkage_name. Ignore these.
See https://github.com/rust-lang/rust/issues/32925. */
/* DW_AT_linkage_name is missing in some cases - depend on what GDB
has computed. */
+ gdb::unique_xmalloc_ptr<char> demangled;
if (mangled != NULL)
{
- char *demangled;
-
/* Use DMGL_RET_DROP for C++ template functions to suppress their return
type. It is easier for GDB users to search for such functions as
`name(params)' than `long name(params)'. In such case the minimal
/* This is a lie, but we already lie to the caller new_symbol_full.
new_symbol_full assumes we return the mangled name.
This just undoes that lie until things are cleaned up. */
- demangled = NULL;
}
else
{
- demangled = gdb_demangle (mangled,
- (DMGL_PARAMS | DMGL_ANSI | DMGL_RET_DROP));
+ demangled.reset (gdb_demangle (mangled,
+ (DMGL_PARAMS | DMGL_ANSI
+ | DMGL_RET_DROP)));
}
if (demangled)
- {
- make_cleanup (xfree, demangled);
- canon = demangled;
- }
+ canon = demangled.get ();
else
{
canon = mangled;
obstack_copy0 (&objfile->per_bfd->storage_obstack,
retval, strlen (retval)));
- do_cleanups (back_to);
return retval;
}
const char *import_alias;
const char *imported_declaration = NULL;
const char *import_prefix;
- VEC (const_char_ptr) *excludes = NULL;
- struct cleanup *cleanups;
+ std::vector<const char *> excludes;
import_attr = dwarf2_attr (die, DW_AT_import, cu);
if (import_attr == NULL)
else
canonical_name = imported_name;
- cleanups = make_cleanup (VEC_cleanup (const_char_ptr), &excludes);
-
if (die->tag == DW_TAG_imported_module && cu->language == language_fortran)
for (child_die = die->child; child_die && child_die->tag;
child_die = sibling_die (child_die))
continue;
}
- VEC_safe_push (const_char_ptr, excludes, imported_name);
+ excludes.push_back (imported_name);
process_die (child_die, cu);
}
excludes,
0,
&objfile->objfile_obstack);
+}
- do_cleanups (cleanups);
+/* ICC<14 does not output the required DW_AT_declaration on incomplete
+ types, but gives them a size of zero. Starting with version 14,
+ ICC is compatible with GCC. */
+
+static int
+producer_is_icc_lt_14 (struct dwarf2_cu *cu)
+{
+ if (!cu->checked_producer)
+ check_producer (cu);
+
+ return cu->producer_is_icc_lt_14;
}
/* Check for possibly missing DW_AT_comp_dir with relative .debug_line
struct attribute *attr;
struct line_header line_header_local;
hashval_t line_header_local_hash;
- unsigned u;
void **slot;
int decode_mapping;
line_header_up lh = dwarf_decode_line_header (line_offset, cu);
if (lh == NULL)
return;
- cu->line_header = lh.get ();
+
+ cu->line_header = lh.release ();
+ cu->line_header_die_owner = die;
if (dwarf2_per_objfile->line_header_hash == NULL)
slot = NULL;
/* This newly decoded line number information unit will be owned
by line_header_hash hash table. */
*slot = cu->line_header;
+ cu->line_header_die_owner = NULL;
}
else
{
dwarf_decode_lines (cu->line_header, comp_dir, cu, NULL, lowpc,
decode_mapping);
- lh.release ();
}
/* Process DW_TAG_compile_unit or DW_TAG_partial_unit. */
return;
}
- cu->line_header = lh.get ();
+ cu->line_header = lh.release ();
+ cu->line_header_die_owner = die;
if (first_time)
{
process_full_type_unit still needs to know if this is the first
time. */
- tu_group->num_symtabs = lh->file_names.size ();
- tu_group->symtabs = XNEWVEC (struct symtab *, lh->file_names.size ());
+ tu_group->num_symtabs = cu->line_header->file_names.size ();
+ tu_group->symtabs = XNEWVEC (struct symtab *,
+ cu->line_header->file_names.size ());
- for (i = 0; i < lh->file_names.size (); ++i)
+ for (i = 0; i < cu->line_header->file_names.size (); ++i)
{
- file_entry &fe = lh->file_names[i];
+ file_entry &fe = cu->line_header->file_names[i];
- dwarf2_start_subfile (fe.name, fe.include_dir (lh.get ()));
+ dwarf2_start_subfile (fe.name, fe.include_dir (cu->line_header));
if (current_subfile->symtab == NULL)
{
- /* NOTE: start_subfile will recognize when it's been passed
- a file it has already seen. So we can't assume there's a
- simple mapping from lh->file_names to subfiles, plus
- lh->file_names may contain dups. */
+ /* NOTE: start_subfile will recognize when it's been
+ passed a file it has already seen. So we can't
+ assume there's a simple mapping from
+ cu->line_header->file_names to subfiles, plus
+ cu->line_header->file_names may contain dups. */
current_subfile->symtab
= allocate_symtab (cust, current_subfile->name);
}
{
restart_symtab (tu_group->compunit_symtab, "", 0);
- for (i = 0; i < lh->file_names.size (); ++i)
+ for (i = 0; i < cu->line_header->file_names.size (); ++i)
{
- struct file_entry *fe = &lh->file_names[i];
+ file_entry &fe = cu->line_header->file_names[i];
- fe->symtab = tu_group->symtabs[i];
+ fe.symtab = tu_group->symtabs[i];
}
}
- lh.release ();
-
/* The main symtab is allocated last. Type units don't have DW_AT_name
so they don't have a "real" (so to speak) symtab anyway.
There is later code that will assign the main symtab to all symbols
hex_string (dwo_unit->signature));
}
-/* Create the dwo_unit for the lone CU in DWO_FILE.
+/* Create the dwo_units for the CUs in a DWO_FILE.
Note: This function processes DWO files only, not DWP files. */
-static struct dwo_unit *
-create_dwo_cu (struct dwo_file *dwo_file)
+static void
+create_cus_hash_table (struct dwo_file &dwo_file, dwarf2_section_info §ion,
+ htab_t &cus_htab)
{
struct objfile *objfile = dwarf2_per_objfile->objfile;
- struct dwarf2_section_info *section = &dwo_file->sections.info;
const gdb_byte *info_ptr, *end_ptr;
- struct create_dwo_cu_data create_dwo_cu_data;
- struct dwo_unit *dwo_unit;
- dwarf2_read_section (objfile, section);
- info_ptr = section->buffer;
+ dwarf2_read_section (objfile, §ion);
+ info_ptr = section.buffer;
if (info_ptr == NULL)
- return NULL;
+ return;
if (dwarf_read_debug)
{
fprintf_unfiltered (gdb_stdlog, "Reading %s for %s:\n",
- get_section_name (section),
- get_section_file_name (section));
+ get_section_name (§ion),
+ get_section_file_name (§ion));
}
- create_dwo_cu_data.dwo_file = dwo_file;
- dwo_unit = NULL;
-
- end_ptr = info_ptr + section->size;
+ end_ptr = info_ptr + section.size;
while (info_ptr < end_ptr)
{
struct dwarf2_per_cu_data per_cu;
+ struct create_dwo_cu_data create_dwo_cu_data;
+ struct dwo_unit *dwo_unit;
+ void **slot;
+ sect_offset sect_off = (sect_offset) (info_ptr - section.buffer);
memset (&create_dwo_cu_data.dwo_unit, 0,
sizeof (create_dwo_cu_data.dwo_unit));
memset (&per_cu, 0, sizeof (per_cu));
per_cu.objfile = objfile;
per_cu.is_debug_types = 0;
- per_cu.sect_off = sect_offset (info_ptr - section->buffer);
- per_cu.section = section;
+ per_cu.sect_off = sect_offset (info_ptr - section.buffer);
+ per_cu.section = §ion;
+ create_dwo_cu_data.dwo_file = &dwo_file;
+
+ init_cutu_and_read_dies_no_follow (
+ &per_cu, &dwo_file, create_dwo_cu_reader, &create_dwo_cu_data);
+ info_ptr += per_cu.length;
+
+ // If the unit could not be parsed, skip it.
+ if (create_dwo_cu_data.dwo_unit.dwo_file == NULL)
+ continue;
- init_cutu_and_read_dies_no_follow (&per_cu, dwo_file,
- create_dwo_cu_reader,
- &create_dwo_cu_data);
+ if (cus_htab == NULL)
+ cus_htab = allocate_dwo_unit_table (objfile);
- if (create_dwo_cu_data.dwo_unit.dwo_file != NULL)
+ dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
+ *dwo_unit = create_dwo_cu_data.dwo_unit;
+ slot = htab_find_slot (cus_htab, dwo_unit, INSERT);
+ gdb_assert (slot != NULL);
+ if (*slot != NULL)
{
- /* If we've already found one, complain. We only support one
- because having more than one requires hacking the dwo_name of
- each to match, which is highly unlikely to happen. */
- if (dwo_unit != NULL)
- {
- complaint (&symfile_complaints,
- _("Multiple CUs in DWO file %s [in module %s]"),
- dwo_file->dwo_name, objfile_name (objfile));
- break;
- }
+ const struct dwo_unit *dup_cu = (const struct dwo_unit *)*slot;
+ sect_offset dup_sect_off = dup_cu->sect_off;
- dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
- *dwo_unit = create_dwo_cu_data.dwo_unit;
+ complaint (&symfile_complaints,
+ _("debug cu entry at offset 0x%x is duplicate to"
+ " the entry at offset 0x%x, signature %s"),
+ to_underlying (sect_off), to_underlying (dup_sect_off),
+ hex_string (dwo_unit->signature));
}
-
- info_ptr += per_cu.length;
+ *slot = (void *)dwo_unit;
}
-
- return dwo_unit;
}
/* DWP file .debug_{cu,tu}_index section format:
struct dwo_unit *dwo_unit;
struct virtual_v1_dwo_sections sections;
void **dwo_file_slot;
- char *virtual_dwo_name;
- struct cleanup *cleanups;
int i;
gdb_assert (dwp_file->version == 1);
+ 1 /* trailing zero */)
memset (§ions, 0, sizeof (sections));
- cleanups = make_cleanup (null_cleanup, 0);
for (i = 0; i < MAX_NR_V1_DWO_SECTIONS; ++i)
{
(fewer struct dwo_file objects to allocate). Remember that for really
large apps there can be on the order of 8K CUs and 200K TUs, or more. */
- virtual_dwo_name =
- xstrprintf ("virtual-dwo/%d-%d-%d-%d",
- get_section_id (§ions.abbrev),
- get_section_id (§ions.line),
- get_section_id (§ions.loc),
- get_section_id (§ions.str_offsets));
- make_cleanup (xfree, virtual_dwo_name);
+ std::string virtual_dwo_name =
+ string_printf ("virtual-dwo/%d-%d-%d-%d",
+ get_section_id (§ions.abbrev),
+ get_section_id (§ions.line),
+ get_section_id (§ions.loc),
+ get_section_id (§ions.str_offsets));
/* Can we use an existing virtual DWO file? */
- dwo_file_slot = lookup_dwo_file_slot (virtual_dwo_name, comp_dir);
+ dwo_file_slot = lookup_dwo_file_slot (virtual_dwo_name.c_str (), comp_dir);
/* Create one if necessary. */
if (*dwo_file_slot == NULL)
{
if (dwarf_read_debug)
{
fprintf_unfiltered (gdb_stdlog, "Creating virtual DWO: %s\n",
- virtual_dwo_name);
+ virtual_dwo_name.c_str ());
}
dwo_file = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_file);
dwo_file->dwo_name
= (const char *) obstack_copy0 (&objfile->objfile_obstack,
- virtual_dwo_name,
- strlen (virtual_dwo_name));
+ virtual_dwo_name.c_str (),
+ virtual_dwo_name.size ());
dwo_file->comp_dir = comp_dir;
dwo_file->sections.abbrev = sections.abbrev;
dwo_file->sections.line = sections.line;
if (dwarf_read_debug)
{
fprintf_unfiltered (gdb_stdlog, "Using existing virtual DWO: %s\n",
- virtual_dwo_name);
+ virtual_dwo_name.c_str ());
}
dwo_file = (struct dwo_file *) *dwo_file_slot;
}
- do_cleanups (cleanups);
dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
dwo_unit->dwo_file = dwo_file;
if (sectp == NULL
|| offset + size > bfd_get_section_size (sectp))
{
- bfd *abfd = sectp->owner;
-
error (_("Dwarf Error: Bad DWP V2 section info, doesn't fit"
" in section %s [in module %s]"),
sectp ? bfd_section_name (abfd, sectp) : "<unknown>",
struct dwo_unit *dwo_unit;
struct virtual_v2_dwo_sections sections;
void **dwo_file_slot;
- char *virtual_dwo_name;
- struct cleanup *cleanups;
int i;
gdb_assert (dwp_file->version == 2);
/* Fetch the section offsets of this DWO unit. */
memset (§ions, 0, sizeof (sections));
- cleanups = make_cleanup (null_cleanup, 0);
for (i = 0; i < dwp_htab->nr_columns; ++i)
{
(fewer struct dwo_file objects to allocate). Remember that for really
large apps there can be on the order of 8K CUs and 200K TUs, or more. */
- virtual_dwo_name =
- xstrprintf ("virtual-dwo/%ld-%ld-%ld-%ld",
- (long) (sections.abbrev_size ? sections.abbrev_offset : 0),
- (long) (sections.line_size ? sections.line_offset : 0),
- (long) (sections.loc_size ? sections.loc_offset : 0),
- (long) (sections.str_offsets_size
- ? sections.str_offsets_offset : 0));
- make_cleanup (xfree, virtual_dwo_name);
+ std::string virtual_dwo_name =
+ string_printf ("virtual-dwo/%ld-%ld-%ld-%ld",
+ (long) (sections.abbrev_size ? sections.abbrev_offset : 0),
+ (long) (sections.line_size ? sections.line_offset : 0),
+ (long) (sections.loc_size ? sections.loc_offset : 0),
+ (long) (sections.str_offsets_size
+ ? sections.str_offsets_offset : 0));
/* Can we use an existing virtual DWO file? */
- dwo_file_slot = lookup_dwo_file_slot (virtual_dwo_name, comp_dir);
+ dwo_file_slot = lookup_dwo_file_slot (virtual_dwo_name.c_str (), comp_dir);
/* Create one if necessary. */
if (*dwo_file_slot == NULL)
{
if (dwarf_read_debug)
{
fprintf_unfiltered (gdb_stdlog, "Creating virtual DWO: %s\n",
- virtual_dwo_name);
+ virtual_dwo_name.c_str ());
}
dwo_file = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_file);
dwo_file->dwo_name
= (const char *) obstack_copy0 (&objfile->objfile_obstack,
- virtual_dwo_name,
- strlen (virtual_dwo_name));
+ virtual_dwo_name.c_str (),
+ virtual_dwo_name.size ());
dwo_file->comp_dir = comp_dir;
dwo_file->sections.abbrev =
create_dwp_v2_section (&dwp_file->sections.abbrev,
if (dwarf_read_debug)
{
fprintf_unfiltered (gdb_stdlog, "Using existing virtual DWO: %s\n",
- virtual_dwo_name);
+ virtual_dwo_name.c_str ());
}
dwo_file = (struct dwo_file *) *dwo_file_slot;
}
- do_cleanups (cleanups);
dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
dwo_unit->dwo_file = dwo_file;
bfd_map_over_sections (dwo_file->dbfd, dwarf2_locate_dwo_sections,
&dwo_file->sections);
- dwo_file->cu = create_dwo_cu (dwo_file);
+ create_cus_hash_table (*dwo_file, dwo_file->sections.info, dwo_file->cus);
create_debug_types_hash_table (dwo_file, dwo_file->sections.types,
dwo_file->tus);
dwp_file->tus = create_dwp_hash_table (dwp_file, 1);
/* The DWP file version is stored in the hash table. Oh well. */
- if (dwp_file->cus->version != dwp_file->tus->version)
+ if (dwp_file->cus && dwp_file->tus
+ && dwp_file->cus->version != dwp_file->tus->version)
{
/* Technically speaking, we should try to limp along, but this is
pretty bizarre. We use pulongest here because that's the established
pulongest (dwp_file->cus->version),
pulongest (dwp_file->tus->version), dwp_name.c_str ());
}
- dwp_file->version = dwp_file->cus->version;
+
+ if (dwp_file->cus)
+ dwp_file->version = dwp_file->cus->version;
+ else if (dwp_file->tus)
+ dwp_file->version = dwp_file->tus->version;
+ else
+ dwp_file->version = 2;
if (dwp_file->version == 2)
bfd_map_over_sections (dwp_file->dbfd, dwarf2_locate_v2_dwp_sections,
dwo_cutu
= (struct dwo_unit *) htab_find (dwo_file->tus, &find_dwo_cutu);
}
- else if (!is_debug_types && dwo_file->cu)
+ else if (!is_debug_types && dwo_file->cus)
{
- if (signature == dwo_file->cu->signature)
- dwo_cutu = dwo_file->cu;
+ struct dwo_unit find_dwo_cutu;
+
+ memset (&find_dwo_cutu, 0, sizeof (find_dwo_cutu));
+ find_dwo_cutu.signature = signature;
+ dwo_cutu = (struct dwo_unit *)htab_find (dwo_file->cus,
+ &find_dwo_cutu);
}
if (dwo_cutu != NULL)
{
/* Print the name of the DWP file if we looked there, helps the user
better diagnose the problem. */
- char *dwp_text = NULL;
- struct cleanup *cleanups;
+ std::string dwp_text;
if (dwp_file != NULL)
- dwp_text = xstrprintf (" [in DWP file %s]", lbasename (dwp_file->name));
- cleanups = make_cleanup (xfree, dwp_text);
+ dwp_text = string_printf (" [in DWP file %s]",
+ lbasename (dwp_file->name));
warning (_("Could not find DWO %s %s(%s)%s referenced by %s at offset 0x%x"
" [in module %s]"),
kind, dwo_name, hex_string (signature),
- dwp_text != NULL ? dwp_text : "",
+ dwp_text.c_str (),
this_unit->is_debug_types ? "TU" : "CU",
to_underlying (this_unit->sect_off), objfile_name (objfile));
-
- do_cleanups (cleanups);
}
return NULL;
}
\f
/* Read in various DIEs. */
-/* qsort helper for inherit_abstract_dies. */
-
-static int
-unsigned_int_compar (const void *ap, const void *bp)
-{
- unsigned int a = *(unsigned int *) ap;
- unsigned int b = *(unsigned int *) bp;
-
- return (a > b) - (b > a);
-}
-
/* DW_AT_abstract_origin inherits whole DIEs (not just their attributes).
Inherit only the children of the DW_AT_abstract_origin DIE not being
already referenced by DW_AT_abstract_origin from the children of the
inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu)
{
struct die_info *child_die;
- unsigned die_children_count;
- /* CU offsets which were referenced by children of the current DIE. */
- sect_offset *offsets;
- sect_offset *offsets_end, *offsetp;
+ sect_offset *offsetp;
/* Parent of DIE - referenced by DW_AT_abstract_origin. */
struct die_info *origin_die;
/* Iterator of the ORIGIN_DIE children. */
struct die_info *origin_child_die;
- struct cleanup *cleanups;
struct attribute *attr;
struct dwarf2_cu *origin_cu;
struct pending **origin_previous_list_in_scope;
to_underlying (die->sect_off),
to_underlying (origin_die->sect_off));
- child_die = die->child;
- die_children_count = 0;
- while (child_die && child_die->tag)
- {
- child_die = sibling_die (child_die);
- die_children_count++;
- }
- offsets = XNEWVEC (sect_offset, die_children_count);
- cleanups = make_cleanup (xfree, offsets);
+ std::vector<sect_offset> offsets;
- offsets_end = offsets;
for (child_die = die->child;
child_die && child_die->tag;
child_die = sibling_die (child_die))
to_underlying (child_die->sect_off),
to_underlying (child_origin_die->sect_off));
else
- *offsets_end++ = child_origin_die->sect_off;
+ offsets.push_back (child_origin_die->sect_off);
}
}
- qsort (offsets, offsets_end - offsets, sizeof (*offsets),
- unsigned_int_compar);
- for (offsetp = offsets + 1; offsetp < offsets_end; offsetp++)
+ std::sort (offsets.begin (), offsets.end ());
+ sect_offset *offsets_end = offsets.data () + offsets.size ();
+ for (offsetp = offsets.data () + 1; offsetp < offsets_end; offsetp++)
if (offsetp[-1] == *offsetp)
complaint (&symfile_complaints,
_("Multiple children of DIE 0x%x refer "
"to DIE 0x%x as their abstract origin"),
to_underlying (die->sect_off), to_underlying (*offsetp));
- offsetp = offsets;
+ offsetp = offsets.data ();
origin_child_die = origin_die->child;
while (origin_child_die && origin_child_die->tag)
{
origin_child_die = sibling_die (origin_child_die);
}
origin_cu->list_in_scope = origin_previous_list_in_scope;
-
- do_cleanups (cleanups);
}
static void
CORE_ADDR baseaddr;
struct block *block;
int inlined_func = (die->tag == DW_TAG_inlined_subroutine);
- VEC (symbolp) *template_args = NULL;
+ std::vector<struct symbol *> template_args;
struct template_symbol *templ_func = NULL;
if (inlined_func)
|| child_die->tag == DW_TAG_template_value_param)
{
templ_func = allocate_template_symbol (objfile);
- templ_func->base.is_cplus_template_function = 1;
+ templ_func->subclass = SYMBOL_TEMPLATE;
break;
}
}
struct symbol *arg = new_symbol (child_die, NULL, cu);
if (arg != NULL)
- VEC_safe_push (symbolp, template_args, arg);
+ template_args.push_back (arg);
}
else
process_die (child_die, cu);
gdbarch_make_symbol_special (gdbarch, newobj->name, objfile);
/* Attach template arguments to function. */
- if (! VEC_empty (symbolp, template_args))
+ if (!template_args.empty ())
{
gdb_assert (templ_func != NULL);
- templ_func->n_template_arguments = VEC_length (symbolp, template_args);
+ templ_func->n_template_arguments = template_args.size ();
templ_func->template_arguments
= XOBNEWVEC (&objfile->objfile_obstack, struct symbol *,
templ_func->n_template_arguments);
memcpy (templ_func->template_arguments,
- VEC_address (symbolp, template_args),
+ template_args.data (),
(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
const char *target_physname;
/* Prefer the mangled name; otherwise compute the demangled one. */
- target_physname = dwarf2_string_attr (target_die,
- DW_AT_linkage_name,
- target_cu);
- if (target_physname == NULL)
- target_physname = dwarf2_string_attr (target_die,
- DW_AT_MIPS_linkage_name,
- target_cu);
+ target_physname = dw2_linkage_name (target_die, target_cu);
if (target_physname == NULL)
target_physname = dwarf2_physname (NULL, target_die, target_cu);
if (target_physname == NULL)
}
}
+/* Helper function for read_variable. If DIE represents a virtual
+ table, then return the type of the concrete object that is
+ associated with the virtual table. Otherwise, return NULL. */
+
+static struct type *
+rust_containing_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct attribute *attr = dwarf2_attr (die, DW_AT_type, cu);
+ if (attr == NULL)
+ return NULL;
+
+ /* Find the type DIE. */
+ struct die_info *type_die = NULL;
+ struct dwarf2_cu *type_cu = cu;
+
+ if (attr_form_is_ref (attr))
+ type_die = follow_die_ref (die, attr, &type_cu);
+ if (type_die == NULL)
+ return NULL;
+
+ if (dwarf2_attr (type_die, DW_AT_containing_type, type_cu) == NULL)
+ return NULL;
+ return die_containing_type (type_die, type_cu);
+}
+
+/* Read a variable (DW_TAG_variable) DIE and create a new symbol. */
+
+static void
+read_variable (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct rust_vtable_symbol *storage = NULL;
+
+ if (cu->language == language_rust)
+ {
+ struct type *containing_type = rust_containing_type (die, cu);
+
+ if (containing_type != NULL)
+ {
+ struct objfile *objfile = cu->objfile;
+
+ storage = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+ struct rust_vtable_symbol);
+ initialize_objfile_symbol (storage);
+ storage->concrete_type = containing_type;
+ storage->subclass = SYMBOL_RUST_VTABLE;
+ }
+ }
+
+ new_symbol_full (die, NULL, cu, storage);
+}
+
/* Call CALLBACK from DW_AT_ranges attribute value OFFSET
reading .debug_rnglists.
Callback's type should be:
Callback &&callback)
{
struct objfile *objfile = cu->objfile;
- struct gdbarch *gdbarch = get_objfile_arch (objfile);
- struct comp_unit_head *cu_header = &cu->header;
bfd *obfd = objfile->obfd;
- unsigned int addr_size = cu_header->addr_size;
- CORE_ADDR mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
/* Base address selection entry. */
CORE_ADDR base;
int found_base;
- unsigned int dummy;
const gdb_byte *buffer;
- CORE_ADDR low = 0;
- CORE_ADDR high = 0;
CORE_ADDR baseaddr;
bool overflow = false;
Callback &&callback)
{
struct objfile *objfile = cu->objfile;
- struct gdbarch *gdbarch = get_objfile_arch (objfile);
struct comp_unit_head *cu_header = &cu->header;
bfd *obfd = objfile->obfd;
unsigned int addr_size = cu_header->addr_size;
attr = dwarf2_attr (die, DW_AT_ranges, cu);
if (attr)
{
- bfd *obfd = objfile->obfd;
/* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton.
We take advantage of the fact that DW_AT_ranges does not appear
in DW_TAG_compile_unit of DWO files. */
cu->producer_is_gxx_lt_4_6 = major < 4 || (major == 4 && minor < 6);
cu->producer_is_gcc_lt_4_3 = major < 4 || (major == 4 && minor < 3);
}
- else if (startswith (cu->producer, "Intel(R) C"))
- cu->producer_is_icc = 1;
+ else if (producer_is_icc (cu->producer, &major, &minor))
+ cu->producer_is_icc_lt_14 = major < 14;
else
{
/* For other non-GCC compilers, expect their behavior is DWARF version
}
}
-/* Add a typedef defined in the scope of the FIP's class. */
+/* Can the type given by DIE define another type? */
+
+static bool
+type_can_define_types (const struct die_info *die)
+{
+ switch (die->tag)
+ {
+ case DW_TAG_typedef:
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_enumeration_type:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Add a type definition defined in the scope of the FIP's class. */
static void
-dwarf2_add_typedef (struct field_info *fip, struct die_info *die,
- struct dwarf2_cu *cu)
+dwarf2_add_type_defn (struct field_info *fip, struct die_info *die,
+ struct dwarf2_cu *cu)
{
- struct typedef_field_list *new_field;
- struct typedef_field *fp;
+ struct decl_field_list *new_field;
+ struct decl_field *fp;
/* Allocate a new field list entry and link it in. */
- new_field = XCNEW (struct typedef_field_list);
+ new_field = XCNEW (struct decl_field_list);
make_cleanup (xfree, new_field);
- gdb_assert (die->tag == DW_TAG_typedef);
+ gdb_assert (type_can_define_types (die));
fp = &new_field->field;
- /* Get name of field. */
+ /* Get name of field. NULL is okay here, meaning an anonymous type. */
fp->name = dwarf2_name (die, cu);
- if (fp->name == NULL)
- return;
-
fp->type = read_type_die (die, cu);
- new_field->next = fip->typedef_field_list;
- fip->typedef_field_list = new_field;
- fip->typedef_field_list_count++;
+ /* Save accessibility. */
+ enum dwarf_access_attribute accessibility;
+ struct attribute *attr = dwarf2_attr (die, DW_AT_accessibility, cu);
+ if (attr != NULL)
+ accessibility = (enum dwarf_access_attribute) DW_UNSND (attr);
+ else
+ accessibility = dwarf2_default_access_attribute (die, cu);
+ switch (accessibility)
+ {
+ case DW_ACCESS_public:
+ /* The assumed value if neither private nor protected. */
+ break;
+ case DW_ACCESS_private:
+ fp->is_private = 1;
+ break;
+ case DW_ACCESS_protected:
+ fp->is_protected = 1;
+ break;
+ default:
+ complaint (&symfile_complaints,
+ _("Unhandled DW_AT_accessibility value (%x)"), accessibility);
+ }
+
+ if (die->tag == DW_TAG_typedef)
+ {
+ new_field->next = fip->typedef_field_list;
+ fip->typedef_field_list = new_field;
+ fip->typedef_field_list_count++;
+ }
+ else
+ {
+ new_field->next = fip->nested_types_list;
+ fip->nested_types_list = new_field;
+ fip->nested_types_list_count++;
+ }
}
/* Create the vector of fields, and attach it to the type. */
is_vtable_name (const char *name, struct dwarf2_cu *cu)
{
static const char vptr[] = "_vptr";
- static const char vtable[] = "vtable";
/* Look for the C++ form of the vtable. */
if (startswith (name, vptr) && is_cplus_marker (name[sizeof (vptr) - 1]))
smash_to_methodptr_type (type, new_type);
}
-/* Return non-zero if the CU's PRODUCER string matches the Intel C/C++ compiler
- (icc). */
-
-static int
-producer_is_icc (struct dwarf2_cu *cu)
-{
- if (!cu->checked_producer)
- check_producer (cu);
-
- return cu->producer_is_icc;
-}
/* Called when we find the DIE that starts a structure or union scope
(definition) to create a type for the structure or union. Fill in
TYPE_LENGTH (type) = 0;
}
- if (producer_is_icc (cu) && (TYPE_LENGTH (type) == 0))
+ if (producer_is_icc_lt_14 (cu) && (TYPE_LENGTH (type) == 0))
{
- /* ICC does not output the required DW_AT_declaration
- on incomplete types, but gives them a size of zero. */
+ /* ICC<14 does not output the required DW_AT_declaration on
+ incomplete types, but gives them a size of zero. */
TYPE_STUB (type) = 1;
}
else
if (die->child != NULL && ! die_is_declaration (die, cu))
{
struct field_info fi;
- VEC (symbolp) *template_args = NULL;
+ std::vector<struct symbol *> template_args;
struct cleanup *back_to = make_cleanup (null_cleanup, 0);
memset (&fi, 0, sizeof (struct field_info));
/* C++ base class field. */
dwarf2_add_field (&fi, child_die, cu);
}
- else if (child_die->tag == DW_TAG_typedef)
- dwarf2_add_typedef (&fi, child_die, cu);
+ else if (type_can_define_types (child_die))
+ dwarf2_add_type_defn (&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);
if (arg != NULL)
- VEC_safe_push (symbolp, template_args, arg);
+ template_args.push_back (arg);
}
child_die = sibling_die (child_die);
}
/* Attach template arguments to type. */
- if (! VEC_empty (symbolp, template_args))
+ if (!template_args.empty ())
{
ALLOCATE_CPLUS_STRUCT_TYPE (type);
- TYPE_N_TEMPLATE_ARGUMENTS (type)
- = VEC_length (symbolp, template_args);
+ TYPE_N_TEMPLATE_ARGUMENTS (type) = template_args.size ();
TYPE_TEMPLATE_ARGUMENTS (type)
= XOBNEWVEC (&objfile->objfile_obstack,
struct symbol *,
TYPE_N_TEMPLATE_ARGUMENTS (type));
memcpy (TYPE_TEMPLATE_ARGUMENTS (type),
- VEC_address (symbolp, template_args),
+ template_args.data (),
(TYPE_N_TEMPLATE_ARGUMENTS (type)
* sizeof (struct symbol *)));
- VEC_free (symbolp, template_args);
}
/* Attach fields and member functions to the type. */
ALLOCATE_CPLUS_STRUCT_TYPE (type);
TYPE_TYPEDEF_FIELD_ARRAY (type)
- = ((struct typedef_field *)
+ = ((struct decl_field *)
TYPE_ALLOC (type, sizeof (TYPE_TYPEDEF_FIELD (type, 0)) * i));
TYPE_TYPEDEF_FIELD_COUNT (type) = i;
/* Reverse the list order to keep the debug info elements order. */
while (--i >= 0)
{
- struct typedef_field *dest, *src;
+ struct decl_field *dest, *src;
dest = &TYPE_TYPEDEF_FIELD (type, i);
src = &fi.typedef_field_list->field;
}
}
+ /* Copy fi.nested_types_list linked list elements content into the
+ allocated array TYPE_NESTED_TYPES_ARRAY (type). */
+ if (fi.nested_types_list != NULL && cu->language != language_ada)
+ {
+ int i = fi.nested_types_list_count;
+
+ ALLOCATE_CPLUS_STRUCT_TYPE (type);
+ TYPE_NESTED_TYPES_ARRAY (type)
+ = ((struct decl_field *)
+ TYPE_ALLOC (type, sizeof (struct decl_field) * i));
+ TYPE_NESTED_TYPES_COUNT (type) = i;
+
+ /* Reverse the list order to keep the debug info elements order. */
+ while (--i >= 0)
+ {
+ struct decl_field *dest, *src;
+
+ dest = &TYPE_NESTED_TYPES_FIELD (type, i);
+ src = &fi.nested_types_list->field;
+ fi.nested_types_list = fi.nested_types_list->next;
+ *dest = *src;
+ }
+ }
+
do_cleanups (back_to);
}
struct type *type,
struct dwarf2_cu *cu)
{
- struct obstack obstack;
struct die_info *child_die;
int unsigned_enum = 1;
int flag_enum = 1;
ULONGEST mask = 0;
- struct cleanup *old_chain;
- obstack_init (&obstack);
- old_chain = make_cleanup_obstack_free (&obstack);
+ auto_obstack obstack;
for (child_die = die->child;
child_die != NULL && child_die->tag;
TYPE_UNSIGNED (type) = 1;
if (flag_enum)
TYPE_FLAG_ENUM (type) = 1;
-
- do_cleanups (old_chain);
}
/* Given a DW_AT_enumeration_type die, set its type. We do not
struct die_info *child_die;
struct type *type;
struct type *element_type, *range_type, *index_type;
- struct type **range_types = NULL;
struct attribute *attr;
- int ndim = 0;
- struct cleanup *back_to;
const char *name;
unsigned int bit_stride = 0;
return set_die_type (die, type, cu);
}
- back_to = make_cleanup (null_cleanup, NULL);
+ std::vector<struct type *> range_types;
child_die = die->child;
while (child_die && child_die->tag)
{
{
/* The range type was succesfully read. Save it for the
array type creation. */
- if ((ndim % DW_FIELD_ALLOC_CHUNK) == 0)
- {
- range_types = (struct type **)
- xrealloc (range_types, (ndim + DW_FIELD_ALLOC_CHUNK)
- * sizeof (struct type *));
- if (ndim == 0)
- make_cleanup (free_current_contents, &range_types);
- }
- range_types[ndim++] = child_type;
+ range_types.push_back (child_type);
}
}
child_die = sibling_die (child_die);
{
int i = 0;
- while (i < ndim)
+ while (i < range_types.size ())
type = create_array_type_with_stride (NULL, type, range_types[i++],
bit_stride);
}
else
{
+ size_t ndim = range_types.size ();
while (ndim-- > 0)
type = create_array_type_with_stride (NULL, type, range_types[ndim],
bit_stride);
/* set_die_type should be already done. */
set_descriptive_type (type, die, cu);
- do_cleanups (back_to);
-
return type;
}
{
const char *previous_prefix = determine_prefix (die, cu);
+ std::vector<const char *> excludes;
add_using_directive (using_directives (cu->language),
previous_prefix, TYPE_NAME (type), NULL,
- NULL, NULL, 0, &objfile->objfile_obstack);
+ NULL, excludes, 0, &objfile->objfile_obstack);
}
}
if (format)
type = init_float_type (objfile, bits, name, format);
else
- type = init_type (objfile, TYPE_CODE_ERROR, bits / TARGET_CHAR_BIT, name);
+ type = init_type (objfile, TYPE_CODE_ERROR, bits, name);
return type;
}
{
case DW_ATE_address:
/* Turn DW_ATE_address into a void * pointer. */
- type = init_type (objfile, TYPE_CODE_VOID, 1, NULL);
+ type = init_type (objfile, TYPE_CODE_VOID, TARGET_CHAR_BIT, NULL);
type = init_pointer_type (objfile, bits, name, type);
break;
case DW_ATE_boolean:
default:
complaint (&symfile_complaints, _("unsupported DW_AT_encoding: '%s'"),
dwarf_type_encoding_name (encoding));
- type = init_type (objfile, TYPE_CODE_ERROR,
- bits / TARGET_CHAR_BIT, name);
+ type = init_type (objfile, TYPE_CODE_ERROR, bits, name);
break;
}
if (attr != NULL)
{
if (attr->form == DW_FORM_strp || attr->form == DW_FORM_line_strp
- || attr->form == DW_FORM_string || attr->form == DW_FORM_GNU_strp_alt)
+ || attr->form == DW_FORM_string
+ || attr->form == DW_FORM_GNU_str_index
+ || attr->form == DW_FORM_GNU_strp_alt)
str = DW_STRING (attr);
else
complaint (&symfile_complaints,
ULONGEST data_count, datai;
const gdb_byte *buf = *bufp;
const gdb_byte *format_header_data;
- int i;
unsigned int bytes_read;
format_count = read_1_byte (abfd, buf);
const char *name, const char *comp_dir, CORE_ADDR low_pc)
{
struct compunit_symtab *cust
- = start_symtab (cu->objfile, name, comp_dir, low_pc);
+ = start_symtab (cu->objfile, name, comp_dir, low_pc, cu->language);
record_debugformat ("DWARF 2");
record_producer (cu->producer);
variables with missing type entries. Change the
misleading `void' type to something sensible. */
if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_VOID)
- SYMBOL_TYPE (sym)
- = objfile_type (objfile)->nodebug_data_symbol;
+ SYMBOL_TYPE (sym) = objfile_type (objfile)->builtin_int;
attr = dwarf2_attr (die, DW_AT_const_value, cu);
/* In the case of DW_TAG_member, we should only be called for
break;
case DW_FORM_sdata:
+ case DW_FORM_implicit_const:
*value = DW_SND (attr);
break;
{
if (child->tag == DW_TAG_subprogram)
{
- const char *linkage_name;
+ const char *linkage_name = dw2_linkage_name (child, cu);
- linkage_name = dwarf2_string_attr (child, DW_AT_linkage_name, cu);
- if (linkage_name == NULL)
- linkage_name = dwarf2_string_attr (child, DW_AT_MIPS_linkage_name,
- cu);
if (linkage_name != NULL)
{
char *actual_name
if (dwarf2_string_attr (die, DW_AT_name, cu) != NULL)
return NULL;
- attr = dwarf2_attr (die, DW_AT_linkage_name, cu);
- if (attr == NULL)
- attr = dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu);
+ attr = dw2_linkage_name_attr (die, cu);
if (attr == NULL || DW_STRING (attr) == NULL)
return NULL;
{
char *demangled = NULL;
- attr = dwarf2_attr (die, DW_AT_linkage_name, cu);
- if (attr == NULL)
- attr = dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu);
-
+ attr = dw2_linkage_name_attr (die, cu);
if (attr == NULL || DW_STRING (attr) == NULL)
return NULL;
fprintf_unfiltered (f,
"unexpected attribute form: DW_FORM_indirect");
break;
+ case DW_FORM_implicit_const:
+ fprintf_unfiltered (f, "constant: %s",
+ plongest (DW_SND (&die->attrs[i])));
+ break;
default:
fprintf_unfiltered (f, "unsupported attribute form: %d.",
die->attrs[i].form);
static LONGEST
dwarf2_get_attr_constant_value (const struct attribute *attr, int default_value)
{
- if (attr->form == DW_FORM_sdata)
+ if (attr->form == DW_FORM_sdata || attr->form == DW_FORM_implicit_const)
return DW_SND (attr);
else if (attr->form == DW_FORM_udata
|| attr->form == DW_FORM_data1
break;
case DW_FORM_sdata:
+ case DW_FORM_implicit_const:
type = die_type (die, cu);
result = write_constant_as_bytes (obstack, byte_order,
type, DW_SND (attr), len);
return current_file;
}
-
-/* Copy the LEN characters at BUF to a xmalloc'ed block of memory,
- followed by a null byte. */
-static char *
-copy_string (const char *buf, int len)
-{
- char *s = (char *) xmalloc (len + 1);
-
- memcpy (s, buf, len);
- s[len] = '\0';
- return s;
-}
-
-
static const char *
consume_improper_spaces (const char *p, const char *body)
{
{
/* It's an object-like macro. */
int name_len = p - body;
- char *name = copy_string (body, name_len);
+ char *name = savestring (body, name_len);
const char *replacement;
if (*p == ' ')
else if (*p == '(')
{
/* It's a function-like macro. */
- char *name = copy_string (body, p - body);
+ char *name = savestring (body, p - body);
int argc = 0;
int argv_size = 1;
char **argv = XNEWVEC (char *, argv_size);
argv = XRESIZEVEC (char *, argv, argv_size);
}
- argv[argc++] = copy_string (arg_start, p - arg_start);
+ argv[argc++] = savestring (arg_start, p - arg_start);
}
p = consume_improper_spaces (p, body);
}
break;
+ case DW_FORM_implicit_const:
+ break;
+
default:
{
- complain:
complaint (&symfile_complaints,
_("invalid form 0x%x in `%s'"),
form, get_section_name (section));
enum dwarf_macro_record_type macinfo_type;
unsigned int offset_size = cu->header.offset_size;
const gdb_byte *opcode_definitions[256];
- struct cleanup *cleanup;
void **slot;
struct dwarf2_section_info *section;
const char *section_name;
case DW_FORM_data2:
case DW_FORM_data4:
case DW_FORM_data8:
+ case DW_FORM_implicit_const:
return 1;
default:
return 0;
static void
free_cached_comp_units (void *data)
{
- struct dwarf2_per_cu_data *per_cu, **last_chain;
-
- per_cu = dwarf2_per_objfile->read_in_chain;
- last_chain = &dwarf2_per_objfile->read_in_chain;
- while (per_cu != NULL)
- {
- struct dwarf2_per_cu_data *next_cu;
-
- next_cu = per_cu->cu->read_in_chain;
-
- free_heap_comp_unit (per_cu->cu);
- *last_chain = next_cu;
-
- per_cu = next_cu;
- }
+ dwarf2_per_objfile->free_cached_comp_units ();
}
/* Increase the age counter on each cached compilation unit, and free
if (dwarf2_per_objfile == NULL)
return;
- /* Cached DIE trees use xmalloc and the comp_unit_obstack. */
- free_cached_comp_units (NULL);
-
- if (dwarf2_per_objfile->quick_file_names_table)
- htab_delete (dwarf2_per_objfile->quick_file_names_table);
-
- if (dwarf2_per_objfile->line_header_hash)
- htab_delete (dwarf2_per_objfile->line_header_hash);
-
- /* Everything else should be on the objfile obstack. */
+ dwarf2_per_objfile->~dwarf2_per_objfile ();
}
/* A set of CU "per_cu" pointer, DIE offset, and GDB type pointer.
static struct cmd_list_element *show_dwarf_cmdlist;
static void
-set_dwarf_cmd (char *args, int from_tty)
+set_dwarf_cmd (const char *args, int from_tty)
{
help_list (set_dwarf_cmdlist, "maintenance set dwarf ", all_commands,
gdb_stdout);
}
static void
-show_dwarf_cmd (char *args, int from_tty)
+show_dwarf_cmd (const char *args, int from_tty)
{
cmd_show_list (show_dwarf_cmdlist, from_tty, "");
}
if (data->dwz_file && data->dwz_file->dwz_bfd)
gdb_bfd_unref (data->dwz_file->dwz_bfd);
+
+ if (data->index_table != NULL)
+ data->index_table->~mapped_index ();
}
\f
return &*m_vec.end () - size;
}
- std::vector<gdb_byte> m_vec;
+ gdb::byte_vector m_vec;
};
/* An entry in the symbol table. */
write_psymbols (info->symtab,
info->psyms_seen,
- info->objfile->global_psymbols.list
- + psymtab->globals_offset,
+ &info->objfile->global_psymbols[psymtab->globals_offset],
psymtab->n_global_syms, info->cu_index,
0);
write_psymbols (info->symtab,
info->psyms_seen,
- info->objfile->static_psymbols.list
- + psymtab->statics_offset,
+ &info->objfile->static_psymbols[psymtab->statics_offset],
psymtab->n_static_syms, info->cu_index,
1);
write_psymbols (symtab,
psyms_seen,
- objfile->global_psymbols.list + psymtab->globals_offset,
+ &objfile->global_psymbols[psymtab->globals_offset],
psymtab->n_global_syms, cu_index,
0);
write_psymbols (symtab,
psyms_seen,
- objfile->static_psymbols.list + psymtab->statics_offset,
+ &objfile->static_psymbols[psymtab->statics_offset],
psymtab->n_static_syms, cu_index,
1);
}
-/* Closes FILE on scope exit. */
-struct file_closer
-{
- explicit file_closer (FILE *file)
- : m_file (file)
- {}
-
- ~file_closer ()
- { fclose (m_file); }
-
-private:
- FILE *m_file;
-};
-
/* Create an index file for OBJFILE in the directory DIR. */
static void
std::string filename (std::string (dir) + SLASH_STRING
+ lbasename (objfile_name (objfile)) + INDEX_SUFFIX);
- FILE *out_file = gdb_fopen_cloexec (filename.c_str (), "wb");
+ FILE *out_file = gdb_fopen_cloexec (filename.c_str (), "wb").release ();
if (!out_file)
error (_("Can't open `%s' for writing"), filename.c_str ());
- file_closer close_out_file (out_file);
+ /* Order matters here; we want FILE to be closed before FILENAME is
+ unlinked, because on MS-Windows one cannot delete a file that is
+ still open. (Don't call anything here that might throw until
+ file_closer is created.) */
gdb::unlinker unlink_file (filename.c_str ());
+ gdb_file_up close_out_file (out_file);
mapped_symtab symtab;
data_buf cu_list;
GDB manual. Any changes here must be documented there. */
static void
-save_gdb_index_command (char *arg, int from_tty)
+save_gdb_index_command (const char *arg, int from_tty)
{
struct objfile *objfile;
value);
}
-void _initialize_dwarf2_read (void);
-
void
_initialize_dwarf2_read (void)
{
&dwarf2_block_frame_base_locexpr_funcs);
dwarf2_loclist_block_index = register_symbol_block_impl (LOC_BLOCK,
&dwarf2_block_frame_base_loclist_funcs);
+
+#if GDB_SELF_TEST
+ selftests::register_test ("dw2_expand_symtabs_matching",
+ selftests::dw2_expand_symtabs_matching::run_test);
+#endif
}