#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);
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. */
/* 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. */
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 *,
#define MAYBE_SWAP(V) byte_swap (V)
#else
-#define MAYBE_SWAP(V) (V)
+#define MAYBE_SWAP(V) static_cast<offset_type> (V)
#endif /* WORDS_BIGENDIAN */
/* Read the given attribute value as an address, taking the attribute's
/* 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
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,
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 ();
}
if (!per_cu->v.quick->compunit_symtab)
{
struct cleanup *back_to = make_cleanup (free_cached_comp_units, NULL);
- increment_reading_symtab ();
+ scoped_restore decrementer = increment_reading_symtab ();
dw2_do_instantiate_symtab (per_cu);
process_cu_includes ();
do_cleanups (back_to);
{
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
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];
}
information (but NAME might contain it). */
if (sym != NULL
- && strcmp_iw (SYMBOL_SEARCH_NAME (sym), name) == 0)
+ && SYMBOL_MATCHES_SEARCH_NAME (sym, name))
return stab;
if (with_opaque != NULL
- && strcmp_iw (SYMBOL_SEARCH_NAME (with_opaque), name) == 0)
+ && SYMBOL_MATCHES_SEARCH_NAME (with_opaque, name))
stab_best = stab;
/* Keep looking through other CUs. */
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);
+ dwarf2_per_objfile->filenames_cache.emplace ();
- if (per_cu->v.quick->compunit_symtab)
- {
- void **slot = htab_find_slot (visited.get (),
- per_cu->v.quick->file_names,
- INSERT);
+ htab_up visited (htab_create_alloc (10,
+ htab_hash_pointer, htab_eq_pointer,
+ NULL, xcalloc, xfree));
- *slot = per_cu->v.quick->file_names;
- }
- }
-
- 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;
+ int j;
+ 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
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 ();
dwarf2_build_psymtabs_hard (struct objfile *objfile)
{
struct cleanup *back_to, *addrmap_cleanup;
- struct obstack temp_obstack;
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);
+ auto_obstack temp_obstack;
objfile->psymtabs_addrmap = addrmap_create_mutable (&temp_obstack);
addrmap_cleanup = make_cleanup (psymtabs_addrmap_cleanup, objfile);
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,
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);
}
}
+/* 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;
+ }
+ }
}
}
}
}
-/* 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;
+ }
- die->in_process = 0;
-}
+ ~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;
+ }
+ }
+
+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)
{
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;
}
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. */
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
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 struct dwarf2_section_info *abbrev_section = &dwo_file.sections.abbrev;
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:
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);
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)
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)
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
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
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
{
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,
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:
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.
\f
/* The "save gdb-index" command. */
-/* The contents of the hash table we create when building the string
- table. */
-struct strtab_entry
-{
- offset_type offset;
- const char *str;
-};
-
-/* Hash function for a strtab_entry.
-
- Function is used only during write_hash_table so no index format backward
- compatibility is needed. */
-
-static hashval_t
-hash_strtab_entry (const void *e)
+/* In-memory buffer to prepare data to be written later to a file. */
+class data_buf
{
- const struct strtab_entry *entry = (const struct strtab_entry *) e;
- return mapped_index_string_hash (INT_MAX, entry->str);
-}
-
-/* Equality function for a strtab_entry. */
+public:
+ /* Copy DATA to the end of the buffer. */
+ template<typename T>
+ void append_data (const T &data)
+ {
+ std::copy (reinterpret_cast<const gdb_byte *> (&data),
+ reinterpret_cast<const gdb_byte *> (&data + 1),
+ grow (sizeof (data)));
+ }
-static int
-eq_strtab_entry (const void *a, const void *b)
-{
- const struct strtab_entry *ea = (const struct strtab_entry *) a;
- const struct strtab_entry *eb = (const struct strtab_entry *) b;
- return !strcmp (ea->str, eb->str);
-}
+ /* Copy CSTR (a zero-terminated string) to the end of buffer. The
+ terminating zero is appended too. */
+ void append_cstr0 (const char *cstr)
+ {
+ const size_t size = strlen (cstr) + 1;
+ std::copy (cstr, cstr + size, grow (size));
+ }
-/* Create a strtab_entry hash table. */
+ /* Accept a host-format integer in VAL and append it to the buffer
+ as a target-format integer which is LEN bytes long. */
+ void append_uint (size_t len, bfd_endian byte_order, ULONGEST val)
+ {
+ ::store_unsigned_integer (grow (len), len, byte_order, val);
+ }
-static htab_t
-create_strtab (void)
-{
- return htab_create_alloc (100, hash_strtab_entry, eq_strtab_entry,
- xfree, xcalloc, xfree);
-}
+ /* Return the size of the buffer. */
+ size_t size () const
+ {
+ return m_vec.size ();
+ }
-/* Add a string to the constant pool. Return the string's offset in
- host order. */
+ /* Write the buffer to FILE. */
+ void file_write (FILE *file) const
+ {
+ if (::fwrite (m_vec.data (), 1, m_vec.size (), file) != m_vec.size ())
+ error (_("couldn't write data to file"));
+ }
-static offset_type
-add_string (htab_t table, struct obstack *cpool, const char *str)
-{
- void **slot;
- struct strtab_entry entry;
- struct strtab_entry *result;
+private:
+ /* Grow SIZE bytes at the end of the buffer. Returns a pointer to
+ the start of the new block. */
+ gdb_byte *grow (size_t size)
+ {
+ m_vec.resize (m_vec.size () + size);
+ return &*m_vec.end () - size;
+ }
- entry.str = str;
- slot = htab_find_slot (table, &entry, INSERT);
- if (*slot)
- result = (struct strtab_entry *) *slot;
- else
- {
- result = XNEW (struct strtab_entry);
- result->offset = obstack_object_size (cpool);
- result->str = str;
- obstack_grow_str0 (cpool, str);
- *slot = result;
- }
- return result->offset;
-}
+ gdb::byte_vector m_vec;
+};
/* An entry in the symbol table. */
struct symtab_index_entry
offset_type index_offset;
/* A sorted vector of the indices of all the CUs that hold an object
of this name. */
- VEC (offset_type) *cu_indices;
+ std::vector<offset_type> cu_indices;
};
/* The symbol table. This is a power-of-2-sized hash table. */
struct mapped_symtab
{
- offset_type n_elements;
- offset_type size;
- struct symtab_index_entry **data;
-};
-
-/* Hash function for a symtab_index_entry. */
-
-static hashval_t
-hash_symtab_entry (const void *e)
-{
- const struct symtab_index_entry *entry
- = (const struct symtab_index_entry *) e;
- return iterative_hash (VEC_address (offset_type, entry->cu_indices),
- sizeof (offset_type) * VEC_length (offset_type,
- entry->cu_indices),
- 0);
-}
-
-/* Equality function for a symtab_index_entry. */
-
-static int
-eq_symtab_entry (const void *a, const void *b)
-{
- const struct symtab_index_entry *ea = (const struct symtab_index_entry *) a;
- const struct symtab_index_entry *eb = (const struct symtab_index_entry *) b;
- int len = VEC_length (offset_type, ea->cu_indices);
- if (len != VEC_length (offset_type, eb->cu_indices))
- return 0;
- return !memcmp (VEC_address (offset_type, ea->cu_indices),
- VEC_address (offset_type, eb->cu_indices),
- sizeof (offset_type) * len);
-}
-
-/* Destroy a symtab_index_entry. */
-
-static void
-delete_symtab_entry (void *p)
-{
- struct symtab_index_entry *entry = (struct symtab_index_entry *) p;
- VEC_free (offset_type, entry->cu_indices);
- xfree (entry);
-}
-
-/* Create a hash table holding symtab_index_entry objects. */
-
-static htab_t
-create_symbol_hash_table (void)
-{
- return htab_create_alloc (100, hash_symtab_entry, eq_symtab_entry,
- delete_symtab_entry, xcalloc, xfree);
-}
-
-/* Create a new mapped symtab object. */
-
-static struct mapped_symtab *
-create_mapped_symtab (void)
-{
- struct mapped_symtab *symtab = XNEW (struct mapped_symtab);
- symtab->n_elements = 0;
- symtab->size = 1024;
- symtab->data = XCNEWVEC (struct symtab_index_entry *, symtab->size);
- return symtab;
-}
-
-/* Destroy a mapped_symtab. */
+ mapped_symtab ()
+ {
+ data.resize (1024);
+ }
-static void
-cleanup_mapped_symtab (void *p)
-{
- struct mapped_symtab *symtab = (struct mapped_symtab *) p;
- /* The contents of the array are freed when the other hash table is
- destroyed. */
- xfree (symtab->data);
- xfree (symtab);
-}
+ offset_type n_elements = 0;
+ std::vector<symtab_index_entry> data;
+};
-/* Find a slot in SYMTAB for the symbol NAME. Returns a pointer to
+/* Find a slot in SYMTAB for the symbol NAME. Returns a reference to
the slot.
Function is used only during write_hash_table so no index format backward
compatibility is needed. */
-static struct symtab_index_entry **
+static symtab_index_entry &
find_slot (struct mapped_symtab *symtab, const char *name)
{
offset_type index, step, hash = mapped_index_string_hash (INT_MAX, name);
- index = hash & (symtab->size - 1);
- step = ((hash * 17) & (symtab->size - 1)) | 1;
+ index = hash & (symtab->data.size () - 1);
+ step = ((hash * 17) & (symtab->data.size () - 1)) | 1;
for (;;)
{
- if (!symtab->data[index] || !strcmp (name, symtab->data[index]->name))
- return &symtab->data[index];
- index = (index + step) & (symtab->size - 1);
+ if (symtab->data[index].name == NULL
+ || strcmp (name, symtab->data[index].name) == 0)
+ return symtab->data[index];
+ index = (index + step) & (symtab->data.size () - 1);
}
}
static void
hash_expand (struct mapped_symtab *symtab)
{
- offset_type old_size = symtab->size;
- offset_type i;
- struct symtab_index_entry **old_entries = symtab->data;
+ auto old_entries = std::move (symtab->data);
- symtab->size *= 2;
- symtab->data = XCNEWVEC (struct symtab_index_entry *, symtab->size);
+ symtab->data.clear ();
+ symtab->data.resize (old_entries.size () * 2);
- for (i = 0; i < old_size; ++i)
- {
- if (old_entries[i])
- {
- struct symtab_index_entry **slot = find_slot (symtab,
- old_entries[i]->name);
- *slot = old_entries[i];
- }
- }
-
- xfree (old_entries);
+ for (auto &it : old_entries)
+ if (it.name != NULL)
+ {
+ auto &ref = find_slot (symtab, it.name);
+ ref = std::move (it);
+ }
}
/* Add an entry to SYMTAB. NAME is the name of the symbol.
int is_static, gdb_index_symbol_kind kind,
offset_type cu_index)
{
- struct symtab_index_entry **slot;
offset_type cu_index_and_attrs;
++symtab->n_elements;
- if (4 * symtab->n_elements / 3 >= symtab->size)
+ if (4 * symtab->n_elements / 3 >= symtab->data.size ())
hash_expand (symtab);
- slot = find_slot (symtab, name);
- if (!*slot)
+ symtab_index_entry &slot = find_slot (symtab, name);
+ if (slot.name == NULL)
{
- *slot = XNEW (struct symtab_index_entry);
- (*slot)->name = name;
+ slot.name = name;
/* index_offset is set later. */
- (*slot)->cu_indices = NULL;
}
cu_index_and_attrs = 0;
the last entry pushed), but a symbol could have multiple kinds in one CU.
To keep things simple we don't worry about the duplication here and
sort and uniqufy the list after we've processed all symbols. */
- VEC_safe_push (offset_type, (*slot)->cu_indices, cu_index_and_attrs);
-}
-
-/* qsort helper routine for uniquify_cu_indices. */
-
-static int
-offset_type_compare (const void *ap, const void *bp)
-{
- offset_type a = *(offset_type *) ap;
- offset_type b = *(offset_type *) bp;
-
- return (a > b) - (b > a);
+ slot.cu_indices.push_back (cu_index_and_attrs);
}
/* Sort and remove duplicates of all symbols' cu_indices lists. */
static void
uniquify_cu_indices (struct mapped_symtab *symtab)
{
- int i;
-
- for (i = 0; i < symtab->size; ++i)
+ for (auto &entry : symtab->data)
{
- struct symtab_index_entry *entry = symtab->data[i];
-
- if (entry
- && entry->cu_indices != NULL)
+ if (entry.name != NULL && !entry.cu_indices.empty ())
{
- unsigned int next_to_insert, next_to_check;
- offset_type last_value;
-
- qsort (VEC_address (offset_type, entry->cu_indices),
- VEC_length (offset_type, entry->cu_indices),
- sizeof (offset_type), offset_type_compare);
-
- last_value = VEC_index (offset_type, entry->cu_indices, 0);
- next_to_insert = 1;
- for (next_to_check = 1;
- next_to_check < VEC_length (offset_type, entry->cu_indices);
- ++next_to_check)
- {
- if (VEC_index (offset_type, entry->cu_indices, next_to_check)
- != last_value)
- {
- last_value = VEC_index (offset_type, entry->cu_indices,
- next_to_check);
- VEC_replace (offset_type, entry->cu_indices, next_to_insert,
- last_value);
- ++next_to_insert;
- }
- }
- VEC_truncate (offset_type, entry->cu_indices, next_to_insert);
+ auto &cu_indices = entry.cu_indices;
+ std::sort (cu_indices.begin (), cu_indices.end ());
+ auto from = std::unique (cu_indices.begin (), cu_indices.end ());
+ cu_indices.erase (from, cu_indices.end ());
}
}
}
-/* Add a vector of indices to the constant pool. */
-
-static offset_type
-add_indices_to_cpool (htab_t symbol_hash_table, struct obstack *cpool,
- struct symtab_index_entry *entry)
+/* A form of 'const char *' suitable for container keys. Only the
+ pointer is stored. The strings themselves are compared, not the
+ pointers. */
+class c_str_view
{
- void **slot;
+public:
+ c_str_view (const char *cstr)
+ : m_cstr (cstr)
+ {}
- slot = htab_find_slot (symbol_hash_table, entry, INSERT);
- if (!*slot)
- {
- offset_type len = VEC_length (offset_type, entry->cu_indices);
- offset_type val = MAYBE_SWAP (len);
- offset_type iter;
- int i;
+ bool operator== (const c_str_view &other) const
+ {
+ return strcmp (m_cstr, other.m_cstr) == 0;
+ }
- *slot = entry;
- entry->index_offset = obstack_object_size (cpool);
+private:
+ friend class c_str_view_hasher;
+ const char *const m_cstr;
+};
- obstack_grow (cpool, &val, sizeof (val));
- for (i = 0;
- VEC_iterate (offset_type, entry->cu_indices, i, iter);
- ++i)
- {
- val = MAYBE_SWAP (iter);
- obstack_grow (cpool, &val, sizeof (val));
- }
- }
- else
- {
- struct symtab_index_entry *old_entry
- = (struct symtab_index_entry *) *slot;
- entry->index_offset = old_entry->index_offset;
- entry = old_entry;
- }
- return entry->index_offset;
-}
+/* A std::unordered_map::hasher for c_str_view that uses the right
+ hash function for strings in a mapped index. */
+class c_str_view_hasher
+{
+public:
+ size_t operator () (const c_str_view &x) const
+ {
+ return mapped_index_string_hash (INT_MAX, x.m_cstr);
+ }
+};
-/* Write the mapped hash table SYMTAB to the obstack OUTPUT, with
- constant pool entries going into the obstack CPOOL. */
+/* A std::unordered_map::hasher for std::vector<>. */
+template<typename T>
+class vector_hasher
+{
+public:
+ size_t operator () (const std::vector<T> &key) const
+ {
+ return iterative_hash (key.data (),
+ sizeof (key.front ()) * key.size (), 0);
+ }
+};
+
+/* Write the mapped hash table SYMTAB to the data buffer OUTPUT, with
+ constant pool entries going into the data buffer CPOOL. */
static void
-write_hash_table (struct mapped_symtab *symtab,
- struct obstack *output, struct obstack *cpool)
+write_hash_table (mapped_symtab *symtab, data_buf &output, data_buf &cpool)
{
- offset_type i;
- htab_t symbol_hash_table;
- htab_t str_table;
-
- symbol_hash_table = create_symbol_hash_table ();
- str_table = create_strtab ();
+ {
+ /* Elements are sorted vectors of the indices of all the CUs that
+ hold an object of this name. */
+ std::unordered_map<std::vector<offset_type>, offset_type,
+ vector_hasher<offset_type>>
+ symbol_hash_table;
+
+ /* We add all the index vectors to the constant pool first, to
+ ensure alignment is ok. */
+ for (symtab_index_entry &entry : symtab->data)
+ {
+ if (entry.name == NULL)
+ continue;
+ gdb_assert (entry.index_offset == 0);
+
+ /* Finding before inserting is faster than always trying to
+ insert, because inserting always allocates a node, does the
+ lookup, and then destroys the new node if another node
+ already had the same key. C++17 try_emplace will avoid
+ this. */
+ const auto found
+ = symbol_hash_table.find (entry.cu_indices);
+ if (found != symbol_hash_table.end ())
+ {
+ entry.index_offset = found->second;
+ continue;
+ }
- /* We add all the index vectors to the constant pool first, to
- ensure alignment is ok. */
- for (i = 0; i < symtab->size; ++i)
- {
- if (symtab->data[i])
- add_indices_to_cpool (symbol_hash_table, cpool, symtab->data[i]);
- }
+ symbol_hash_table.emplace (entry.cu_indices, cpool.size ());
+ entry.index_offset = cpool.size ();
+ cpool.append_data (MAYBE_SWAP (entry.cu_indices.size ()));
+ for (const auto index : entry.cu_indices)
+ cpool.append_data (MAYBE_SWAP (index));
+ }
+ }
/* Now write out the hash table. */
- for (i = 0; i < symtab->size; ++i)
+ std::unordered_map<c_str_view, offset_type, c_str_view_hasher> str_table;
+ for (const auto &entry : symtab->data)
{
offset_type str_off, vec_off;
- if (symtab->data[i])
+ if (entry.name != NULL)
{
- str_off = add_string (str_table, cpool, symtab->data[i]->name);
- vec_off = symtab->data[i]->index_offset;
+ const auto insertpair = str_table.emplace (entry.name, cpool.size ());
+ if (insertpair.second)
+ cpool.append_cstr0 (entry.name);
+ str_off = insertpair.first->second;
+ vec_off = entry.index_offset;
}
else
{
vec_off = 0;
}
- str_off = MAYBE_SWAP (str_off);
- vec_off = MAYBE_SWAP (vec_off);
-
- obstack_grow (output, &str_off, sizeof (str_off));
- obstack_grow (output, &vec_off, sizeof (vec_off));
+ output.append_data (MAYBE_SWAP (str_off));
+ output.append_data (MAYBE_SWAP (vec_off));
}
-
- htab_delete (str_table);
- htab_delete (symbol_hash_table);
}
-/* Struct to map psymtab to CU index in the index file. */
-struct psymtab_cu_index_map
-{
- struct partial_symtab *psymtab;
- unsigned int cu_index;
-};
-
-static hashval_t
-hash_psymtab_cu_index (const void *item)
-{
- const struct psymtab_cu_index_map *map
- = (const struct psymtab_cu_index_map *) item;
-
- return htab_hash_pointer (map->psymtab);
-}
-
-static int
-eq_psymtab_cu_index (const void *item_lhs, const void *item_rhs)
-{
- const struct psymtab_cu_index_map *lhs
- = (const struct psymtab_cu_index_map *) item_lhs;
- const struct psymtab_cu_index_map *rhs
- = (const struct psymtab_cu_index_map *) item_rhs;
-
- return lhs->psymtab == rhs->psymtab;
-}
+typedef std::unordered_map<partial_symtab *, unsigned int> psym_index_map;
/* Helper struct for building the address table. */
struct addrmap_index_data
{
+ addrmap_index_data (data_buf &addr_vec_, psym_index_map &cu_index_htab_)
+ : addr_vec (addr_vec_), cu_index_htab (cu_index_htab_)
+ {}
+
struct objfile *objfile;
- struct obstack *addr_obstack;
- htab_t cu_index_htab;
+ data_buf &addr_vec;
+ psym_index_map &cu_index_htab;
/* Non-zero if the previous_* fields are valid.
We can't write an entry until we see the next entry (since it is only then
CORE_ADDR previous_cu_start;
};
-/* Write an address entry to OBSTACK. */
+/* Write an address entry to ADDR_VEC. */
static void
-add_address_entry (struct objfile *objfile, struct obstack *obstack,
+add_address_entry (struct objfile *objfile, data_buf &addr_vec,
CORE_ADDR start, CORE_ADDR end, unsigned int cu_index)
{
- offset_type cu_index_to_write;
- gdb_byte addr[8];
CORE_ADDR baseaddr;
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
- store_unsigned_integer (addr, 8, BFD_ENDIAN_LITTLE, start - baseaddr);
- obstack_grow (obstack, addr, 8);
- store_unsigned_integer (addr, 8, BFD_ENDIAN_LITTLE, end - baseaddr);
- obstack_grow (obstack, addr, 8);
- cu_index_to_write = MAYBE_SWAP (cu_index);
- obstack_grow (obstack, &cu_index_to_write, sizeof (offset_type));
+ addr_vec.append_uint (8, BFD_ENDIAN_LITTLE, start - baseaddr);
+ addr_vec.append_uint (8, BFD_ENDIAN_LITTLE, end - baseaddr);
+ addr_vec.append_data (MAYBE_SWAP (cu_index));
}
/* Worker function for traversing an addrmap to build the address table. */
struct partial_symtab *pst = (struct partial_symtab *) obj;
if (data->previous_valid)
- add_address_entry (data->objfile, data->addr_obstack,
+ add_address_entry (data->objfile, data->addr_vec,
data->previous_cu_start, start_addr,
data->previous_cu_index);
data->previous_cu_start = start_addr;
if (pst != NULL)
{
- struct psymtab_cu_index_map find_map, *map;
- find_map.psymtab = pst;
- map = ((struct psymtab_cu_index_map *)
- htab_find (data->cu_index_htab, &find_map));
- gdb_assert (map != NULL);
- data->previous_cu_index = map->cu_index;
+ const auto it = data->cu_index_htab.find (pst);
+ gdb_assert (it != data->cu_index_htab.cend ());
+ data->previous_cu_index = it->second;
data->previous_valid = 1;
}
else
- data->previous_valid = 0;
+ data->previous_valid = 0;
return 0;
}
-/* Write OBJFILE's address map to OBSTACK.
+/* Write OBJFILE's address map to ADDR_VEC.
CU_INDEX_HTAB is used to map addrmap entries to their CU indices
in the index file. */
static void
-write_address_map (struct objfile *objfile, struct obstack *obstack,
- htab_t cu_index_htab)
+write_address_map (struct objfile *objfile, data_buf &addr_vec,
+ psym_index_map &cu_index_htab)
{
- struct addrmap_index_data addrmap_index_data;
+ struct addrmap_index_data addrmap_index_data (addr_vec, cu_index_htab);
/* When writing the address table, we have to cope with the fact that
the addrmap iterator only provides the start of a region; we have to
wait until the next invocation to get the start of the next region. */
addrmap_index_data.objfile = objfile;
- addrmap_index_data.addr_obstack = obstack;
- addrmap_index_data.cu_index_htab = cu_index_htab;
addrmap_index_data.previous_valid = 0;
addrmap_foreach (objfile->psymtabs_addrmap, add_address_entry_worker,
doesn't work here. To cope we pass 0xff...ff, this is a rare situation
anyway. */
if (addrmap_index_data.previous_valid)
- add_address_entry (objfile, obstack,
+ add_address_entry (objfile, addr_vec,
addrmap_index_data.previous_cu_start, (CORE_ADDR) -1,
addrmap_index_data.previous_cu_index);
}
static void
write_psymbols (struct mapped_symtab *symtab,
- htab_t psyms_seen,
+ std::unordered_set<partial_symbol *> &psyms_seen,
struct partial_symbol **psymp,
int count,
offset_type cu_index,
for (; count-- > 0; ++psymp)
{
struct partial_symbol *psym = *psymp;
- void **slot;
if (SYMBOL_LANGUAGE (psym) == language_ada)
error (_("Ada is not currently supported by the index"));
/* Only add a given psymbol once. */
- slot = htab_find_slot (psyms_seen, psym, INSERT);
- if (!*slot)
+ if (psyms_seen.insert (psym).second)
{
gdb_index_symbol_kind kind = symbol_kind (psym);
- *slot = psym;
add_index_entry (symtab, SYMBOL_SEARCH_NAME (psym),
is_static, kind, cu_index);
}
}
}
-/* Write the contents of an ("unfinished") obstack to FILE. Throw an
- exception if there is an error. */
-
-static void
-write_obstack (FILE *file, struct obstack *obstack)
-{
- if (fwrite (obstack_base (obstack), 1, obstack_object_size (obstack),
- file)
- != obstack_object_size (obstack))
- error (_("couldn't data write to file"));
-}
-
/* A helper struct used when iterating over debug_types. */
struct signatured_type_index_data
{
+ signatured_type_index_data (data_buf &types_list_,
+ std::unordered_set<partial_symbol *> &psyms_seen_)
+ : types_list (types_list_), psyms_seen (psyms_seen_)
+ {}
+
struct objfile *objfile;
struct mapped_symtab *symtab;
- struct obstack *types_list;
- htab_t psyms_seen;
+ data_buf &types_list;
+ std::unordered_set<partial_symbol *> &psyms_seen;
int cu_index;
};
= (struct signatured_type_index_data *) d;
struct signatured_type *entry = (struct signatured_type *) *slot;
struct partial_symtab *psymtab = entry->per_cu.v.psymtab;
- gdb_byte val[8];
write_psymbols (info->symtab,
info->psyms_seen,
psymtab->n_static_syms, info->cu_index,
1);
- store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE,
- to_underlying (entry->per_cu.sect_off));
- obstack_grow (info->types_list, val, 8);
- store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE,
- to_underlying (entry->type_offset_in_tu));
- obstack_grow (info->types_list, val, 8);
- store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, entry->signature);
- obstack_grow (info->types_list, val, 8);
+ info->types_list.append_uint (8, BFD_ENDIAN_LITTLE,
+ to_underlying (entry->per_cu.sect_off));
+ info->types_list.append_uint (8, BFD_ENDIAN_LITTLE,
+ to_underlying (entry->type_offset_in_tu));
+ info->types_list.append_uint (8, BFD_ENDIAN_LITTLE, entry->signature);
++info->cu_index;
return 1;
}
+/* Recurse into all "included" dependencies and count their symbols as
+ if they appeared in this psymtab. */
+
+static void
+recursively_count_psymbols (struct partial_symtab *psymtab,
+ size_t &psyms_seen)
+{
+ for (int i = 0; i < psymtab->number_of_dependencies; ++i)
+ if (psymtab->dependencies[i]->user != NULL)
+ recursively_count_psymbols (psymtab->dependencies[i],
+ psyms_seen);
+
+ psyms_seen += psymtab->n_global_syms;
+ psyms_seen += psymtab->n_static_syms;
+}
+
/* Recurse into all "included" dependencies and write their symbols as
if they appeared in this psymtab. */
recursively_write_psymbols (struct objfile *objfile,
struct partial_symtab *psymtab,
struct mapped_symtab *symtab,
- htab_t psyms_seen,
+ std::unordered_set<partial_symbol *> &psyms_seen,
offset_type cu_index)
{
int i;
static void
write_psymtabs_to_index (struct objfile *objfile, const char *dir)
{
- struct cleanup *cleanup;
- char *filename;
- struct obstack contents, addr_obstack, constant_pool, symtab_obstack;
- struct obstack cu_list, types_cu_list;
- int i;
- FILE *out_file;
- struct mapped_symtab *symtab;
- offset_type val, size_of_contents, total_len;
- struct stat st;
- struct psymtab_cu_index_map *psymtab_cu_index_map;
-
if (dwarf2_per_objfile->using_index)
error (_("Cannot use an index to create the index"));
if (!objfile->psymtabs || !objfile->psymtabs_addrmap)
return;
+ struct stat st;
if (stat (objfile_name (objfile), &st) < 0)
perror_with_name (objfile_name (objfile));
- filename = concat (dir, SLASH_STRING, lbasename (objfile_name (objfile)),
- INDEX_SUFFIX, (char *) NULL);
- cleanup = make_cleanup (xfree, filename);
+ std::string filename (std::string (dir) + SLASH_STRING
+ + lbasename (objfile_name (objfile)) + INDEX_SUFFIX);
- out_file = gdb_fopen_cloexec (filename, "wb");
+ FILE *out_file = gdb_fopen_cloexec (filename.c_str (), "wb").release ();
if (!out_file)
- error (_("Can't open `%s' for writing"), filename);
-
- gdb::unlinker unlink_file (filename);
-
- symtab = create_mapped_symtab ();
- make_cleanup (cleanup_mapped_symtab, symtab);
-
- obstack_init (&addr_obstack);
- make_cleanup_obstack_free (&addr_obstack);
-
- obstack_init (&cu_list);
- make_cleanup_obstack_free (&cu_list);
+ error (_("Can't open `%s' for writing"), filename.c_str ());
- obstack_init (&types_cu_list);
- make_cleanup_obstack_free (&types_cu_list);
+ /* 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);
- htab_up psyms_seen (htab_create_alloc (100, htab_hash_pointer,
- htab_eq_pointer,
- NULL, xcalloc, xfree));
+ mapped_symtab symtab;
+ data_buf cu_list;
/* While we're scanning CU's create a table that maps a psymtab pointer
(which is what addrmap records) to its index (which is what is recorded
in the index file). This will later be needed to write the address
table. */
- htab_up cu_index_htab (htab_create_alloc (100,
- hash_psymtab_cu_index,
- eq_psymtab_cu_index,
- NULL, xcalloc, xfree));
- psymtab_cu_index_map = XNEWVEC (struct psymtab_cu_index_map,
- dwarf2_per_objfile->n_comp_units);
- make_cleanup (xfree, psymtab_cu_index_map);
+ psym_index_map cu_index_htab;
+ cu_index_htab.reserve (dwarf2_per_objfile->n_comp_units);
/* The CU list is already sorted, so we don't need to do additional
work here. Also, the debug_types entries do not appear in
all_comp_units, but only in their own hash table. */
- for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+
+ /* The psyms_seen set is potentially going to be largish (~40k
+ elements when indexing a -g3 build of GDB itself). Estimate the
+ number of elements in order to avoid too many rehashes, which
+ require rebuilding buckets and thus many trips to
+ malloc/free. */
+ size_t psyms_count = 0;
+ for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ {
+ struct dwarf2_per_cu_data *per_cu
+ = dwarf2_per_objfile->all_comp_units[i];
+ struct partial_symtab *psymtab = per_cu->v.psymtab;
+
+ if (psymtab != NULL && psymtab->user == NULL)
+ recursively_count_psymbols (psymtab, psyms_count);
+ }
+ /* Generating an index for gdb itself shows a ratio of
+ TOTAL_SEEN_SYMS/UNIQUE_SYMS or ~5. 4 seems like a good bet. */
+ std::unordered_set<partial_symbol *> psyms_seen (psyms_count / 4);
+ for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
{
struct dwarf2_per_cu_data *per_cu
= dwarf2_per_objfile->all_comp_units[i];
struct partial_symtab *psymtab = per_cu->v.psymtab;
- gdb_byte val[8];
- struct psymtab_cu_index_map *map;
- void **slot;
/* CU of a shared file from 'dwz -m' may be unused by this main file.
It may be referenced from a local scope but in such case it does not
continue;
if (psymtab->user == NULL)
- recursively_write_psymbols (objfile, psymtab, symtab,
- psyms_seen.get (), i);
+ recursively_write_psymbols (objfile, psymtab, &symtab,
+ psyms_seen, i);
- map = &psymtab_cu_index_map[i];
- map->psymtab = psymtab;
- map->cu_index = i;
- slot = htab_find_slot (cu_index_htab.get (), map, INSERT);
- gdb_assert (slot != NULL);
- gdb_assert (*slot == NULL);
- *slot = map;
+ const auto insertpair = cu_index_htab.emplace (psymtab, i);
+ gdb_assert (insertpair.second);
- store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE,
- to_underlying (per_cu->sect_off));
- obstack_grow (&cu_list, val, 8);
- store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, per_cu->length);
- obstack_grow (&cu_list, val, 8);
+ cu_list.append_uint (8, BFD_ENDIAN_LITTLE,
+ to_underlying (per_cu->sect_off));
+ cu_list.append_uint (8, BFD_ENDIAN_LITTLE, per_cu->length);
}
/* Dump the address map. */
- write_address_map (objfile, &addr_obstack, cu_index_htab.get ());
+ data_buf addr_vec;
+ write_address_map (objfile, addr_vec, cu_index_htab);
/* Write out the .debug_type entries, if any. */
+ data_buf types_cu_list;
if (dwarf2_per_objfile->signatured_types)
{
- struct signatured_type_index_data sig_data;
+ signatured_type_index_data sig_data (types_cu_list,
+ psyms_seen);
sig_data.objfile = objfile;
- sig_data.symtab = symtab;
- sig_data.types_list = &types_cu_list;
- sig_data.psyms_seen = psyms_seen.get ();
+ sig_data.symtab = &symtab;
sig_data.cu_index = dwarf2_per_objfile->n_comp_units;
htab_traverse_noresize (dwarf2_per_objfile->signatured_types,
write_one_signatured_type, &sig_data);
/* Now that we've processed all symbols we can shrink their cu_indices
lists. */
- uniquify_cu_indices (symtab);
+ uniquify_cu_indices (&symtab);
- obstack_init (&constant_pool);
- make_cleanup_obstack_free (&constant_pool);
- obstack_init (&symtab_obstack);
- make_cleanup_obstack_free (&symtab_obstack);
- write_hash_table (symtab, &symtab_obstack, &constant_pool);
+ data_buf symtab_vec, constant_pool;
+ write_hash_table (&symtab, symtab_vec, constant_pool);
- obstack_init (&contents);
- make_cleanup_obstack_free (&contents);
- size_of_contents = 6 * sizeof (offset_type);
- total_len = size_of_contents;
+ data_buf contents;
+ const offset_type size_of_contents = 6 * sizeof (offset_type);
+ offset_type total_len = size_of_contents;
/* The version number. */
- val = MAYBE_SWAP (8);
- obstack_grow (&contents, &val, sizeof (val));
+ contents.append_data (MAYBE_SWAP (8));
/* The offset of the CU list from the start of the file. */
- val = MAYBE_SWAP (total_len);
- obstack_grow (&contents, &val, sizeof (val));
- total_len += obstack_object_size (&cu_list);
+ contents.append_data (MAYBE_SWAP (total_len));
+ total_len += cu_list.size ();
/* The offset of the types CU list from the start of the file. */
- val = MAYBE_SWAP (total_len);
- obstack_grow (&contents, &val, sizeof (val));
- total_len += obstack_object_size (&types_cu_list);
+ contents.append_data (MAYBE_SWAP (total_len));
+ total_len += types_cu_list.size ();
/* The offset of the address table from the start of the file. */
- val = MAYBE_SWAP (total_len);
- obstack_grow (&contents, &val, sizeof (val));
- total_len += obstack_object_size (&addr_obstack);
+ contents.append_data (MAYBE_SWAP (total_len));
+ total_len += addr_vec.size ();
/* The offset of the symbol table from the start of the file. */
- val = MAYBE_SWAP (total_len);
- obstack_grow (&contents, &val, sizeof (val));
- total_len += obstack_object_size (&symtab_obstack);
+ contents.append_data (MAYBE_SWAP (total_len));
+ total_len += symtab_vec.size ();
/* The offset of the constant pool from the start of the file. */
- val = MAYBE_SWAP (total_len);
- obstack_grow (&contents, &val, sizeof (val));
- total_len += obstack_object_size (&constant_pool);
-
- gdb_assert (obstack_object_size (&contents) == size_of_contents);
+ contents.append_data (MAYBE_SWAP (total_len));
+ total_len += constant_pool.size ();
- write_obstack (out_file, &contents);
- write_obstack (out_file, &cu_list);
- write_obstack (out_file, &types_cu_list);
- write_obstack (out_file, &addr_obstack);
- write_obstack (out_file, &symtab_obstack);
- write_obstack (out_file, &constant_pool);
+ gdb_assert (contents.size () == size_of_contents);
- fclose (out_file);
+ contents.file_write (out_file);
+ cu_list.file_write (out_file);
+ types_cu_list.file_write (out_file);
+ addr_vec.file_write (out_file);
+ symtab_vec.file_write (out_file);
+ constant_pool.file_write (out_file);
/* We want to keep the file. */
unlink_file.keep ();
-
- do_cleanups (cleanup);
}
/* Implementation of the `save gdb-index' command.
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)
{