#include "namespace.h"
#include "common/gdb_unlinker.h"
#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>
-
-typedef struct symbol *symbolp;
-DEF_VEC_P (symbolp);
+#include <unordered_set>
+#include <unordered_map>
+#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;
-
- VEC (dwarf2_section_info_def) *types;
+ /* 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);
+
+ ~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;
short version;
unsigned char addr_size;
unsigned char signed_addr_p;
- sect_offset abbrev_offset;
+ sect_offset abbrev_sect_off;
/* Size of file offsets; either 4 or 8. */
unsigned int offset_size;
/* Offset to the first byte of this compilation unit header in the
.debug_info section, for resolving relative reference dies. */
- sect_offset offset;
+ sect_offset sect_off;
/* Offset to first die in this cu from the start of the cu.
This will be the first byte following the compilation unit header. */
- cu_offset first_die_offset;
+ cu_offset first_die_cu_offset;
/* 64-bit signature of this type unit - it is valid only for
UNIT_TYPE DW_UT_type. */
ULONGEST signature;
/* For types, offset in the type's DIE of the type defined by this TU. */
- cu_offset type_offset_in_tu;
+ cu_offset type_cu_offset_in_tu;
};
/* Type used for delaying computation of method physnames.
/* 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
initial_length_size.
If the DIE refers to a DWO file, this is always of the original die,
not the DWO file. */
- sect_offset offset;
+ sect_offset sect_off;
unsigned int length;
/* DWARF standard version this data has been read from (such as 4 or 5). */
struct dwo_unit *dwo_unit;
/* Offset in .debug_line or .debug_line.dwo. */
- sect_offset line_offset;
+ sect_offset line_sect_off;
};
/* Each element of dwarf2_per_objfile->type_unit_groups is a pointer to
/* The section this CU/TU lives in, in the DWO file. */
struct dwarf2_section_info *section;
- /* Same as dwarf2_per_cu_data:{offset,length} but in the DWO section. */
- sect_offset offset;
+ /* Same as dwarf2_per_cu_data:{sect_off,length} but in the DWO section. */
+ sect_offset sect_off;
unsigned int length;
/* For types, offset in the type's DIE of the type defined by this TU. */
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. */
int has_children,
void *data);
+/* A 1-based directory index. This is a strong typedef to prevent
+ accidentally using a directory index as a 0-based index into an
+ array/vector. */
+enum class dir_index : unsigned int {};
+
+/* Likewise, a 1-based file name index. */
+enum class file_name_index : unsigned int {};
+
struct file_entry
{
file_entry () = default;
- file_entry (const char *name_, unsigned int dir_index_,
+ file_entry (const char *name_, dir_index d_index_,
unsigned int mod_time_, unsigned int length_)
: name (name_),
- dir_index (dir_index_),
+ d_index (d_index_),
mod_time (mod_time_),
length (length_)
{}
- /* Return the include directory at DIR_INDEX stored in LH. Returns
- NULL if DIR_INDEX is out of bounds. */
+ /* Return the include directory at D_INDEX stored in LH. Returns
+ NULL if D_INDEX is out of bounds. */
const char *include_dir (const line_header *lh) const;
/* The file name. Note this is an observing pointer. The memory is
const char *name {};
/* The directory index (1-based). */
- unsigned int dir_index {};
+ dir_index d_index {};
unsigned int mod_time {};
void add_include_dir (const char *include_dir);
/* Add an entry to the file name table. */
- void add_file_name (const char *name, unsigned int dir_index,
+ void add_file_name (const char *name, dir_index d_index,
unsigned int mod_time, unsigned int length);
- /* Return the include dir at INDEX (0-based). Returns NULL if INDEX
+ /* Return the include dir at INDEX (1-based). Returns NULL if INDEX
is out of bounds. */
- const char *include_dir_at (unsigned int index) const
+ const char *include_dir_at (dir_index index) const
{
- if (index >= include_dirs.size ())
+ /* Convert directory index number (1-based) to vector index
+ (0-based). */
+ size_t vec_index = to_underlying (index) - 1;
+
+ if (vec_index >= include_dirs.size ())
return NULL;
- return include_dirs[index];
+ return include_dirs[vec_index];
}
- /* Return the file name at INDEX (0-based). Returns NULL if INDEX
+ /* Return the file name at INDEX (1-based). Returns NULL if INDEX
is out of bounds. */
- file_entry *file_name_at (unsigned int index)
+ file_entry *file_name_at (file_name_index index)
{
- if (index >= file_names.size ())
+ /* Convert file name index number (1-based) to vector index
+ (0-based). */
+ size_t vec_index = to_underlying (index) - 1;
+
+ if (vec_index >= file_names.size ())
return NULL;
- return &file_names[index];
+ return &file_names[vec_index];
}
/* Const version of the above. */
}
/* Offset of line number information in .debug_line section. */
- sect_offset offset {};
+ sect_offset sect_off {};
/* OFFSET is for struct dwz_file associated with dwarf2_per_objfile. */
unsigned offset_in_dwz : 1; /* Can't initialize bitfields in-class. */
const char *
file_entry::include_dir (const line_header *lh) const
{
- /* lh->include_dirs is 0-based, but the directory index numbers in
- the statement program are 1-based. */
- return lh->include_dir_at (dir_index - 1);
+ return lh->include_dir_at (d_index);
}
/* When we construct a partial symbol table entry we only
struct partial_die_info
{
/* Offset of this DIE. */
- sect_offset offset;
+ sect_offset sect_off;
/* DWARF-2 tag for this DIE. */
ENUM_BITFIELD(dwarf_tag) tag : 16;
/* The location description associated with this DIE, if any. */
struct dwarf_block *locdesc;
/* The offset of an import, for DW_TAG_imported_unit. */
- sect_offset offset;
+ sect_offset sect_off;
} d;
/* If HAS_PC_INFO, the PC range associated with this DIE. */
{
/* Where the abbrev table came from.
This is used as a sanity check when the table is used. */
- sect_offset offset;
+ sect_offset sect_off;
/* Storage for the abbrev table. */
struct obstack abbrev_obstack;
unsigned int abbrev;
/* Offset in .debug_info or .debug_types section. */
- sect_offset offset;
+ sect_offset sect_off;
/* The dies in a compilation unit form an n-ary tree. PARENT
points to this die's parent; CHILD points to the first child of
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 struct die_info *die_specification (struct die_info *die,
struct dwarf2_cu **);
-static line_header_up dwarf_decode_line_header (unsigned int offset,
+static line_header_up dwarf_decode_line_header (sect_offset sect_off,
struct dwarf2_cu *cu);
static void dwarf_decode_lines (struct line_header *, const char *,
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 *);
static const char *dwarf_form_name (unsigned int);
-static char *dwarf_bool_name (unsigned int);
+static const char *dwarf_bool_name (unsigned int);
static const char *dwarf_type_encoding_name (unsigned int);
static int partial_die_eq (const void *item_lhs, const void *item_rhs);
static struct dwarf2_per_cu_data *dwarf2_find_containing_comp_unit
- (sect_offset offset, unsigned int offset_in_dwz, struct objfile *objfile);
+ (sect_offset sect_off, unsigned int offset_in_dwz, struct objfile *objfile);
static void init_one_comp_unit (struct dwarf2_cu *cu,
struct dwarf2_per_cu_data *per_cu);
static hashval_t
line_header_hash (const struct line_header *ofs)
{
- return ofs->offset.sect_off ^ ofs->offset_in_dwz;
+ return to_underlying (ofs->sect_off) ^ ofs->offset_in_dwz;
}
/* Hash function for htab_create_alloc_ex for line_header_hash. */
const struct line_header *ofs_lhs = (const struct line_header *) item_lhs;
const struct line_header *ofs_rhs = (const struct line_header *) item_rhs;
- return (ofs_lhs->offset.sect_off == ofs_rhs->offset.sect_off
+ return (ofs_lhs->sect_off == ofs_rhs->sect_off
&& ofs_lhs->offset_in_dwz == ofs_rhs->offset_in_dwz);
}
\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) (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;
if (stmt_list_hash->dwo_unit != NULL)
v += (uintptr_t) stmt_list_hash->dwo_unit->dwo_file;
- v += stmt_list_hash->line_offset.sect_off;
+ v += to_underlying (stmt_list_hash->line_sect_off);
return v;
}
&& lhs->dwo_unit->dwo_file != rhs->dwo_unit->dwo_file)
return 0;
- return lhs->line_offset.sect_off == rhs->line_offset.sect_off;
+ return lhs->line_sect_off == rhs->line_sect_off;
}
/* Hash function for a quick_file_names. */
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);
for (i = 0; i < n_elements; i += 2)
{
- struct dwarf2_per_cu_data *the_cu;
- ULONGEST offset, length;
-
gdb_static_assert (sizeof (ULONGEST) >= 8);
- offset = extract_unsigned_integer (cu_list, 8, BFD_ENDIAN_LITTLE);
- length = extract_unsigned_integer (cu_list + 8, 8, BFD_ENDIAN_LITTLE);
+
+ sect_offset sect_off
+ = (sect_offset) extract_unsigned_integer (cu_list, 8, BFD_ENDIAN_LITTLE);
+ ULONGEST length = extract_unsigned_integer (cu_list + 8, 8, BFD_ENDIAN_LITTLE);
cu_list += 2 * 8;
- the_cu = OBSTACK_ZALLOC (&objfile->objfile_obstack,
- struct dwarf2_per_cu_data);
- the_cu->offset.sect_off = offset;
+ dwarf2_per_cu_data *the_cu
+ = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+ struct dwarf2_per_cu_data);
+ the_cu->sect_off = sect_off;
the_cu->length = length;
the_cu->objfile = objfile;
the_cu->section = section;
for (i = 0; i < elements; i += 3)
{
struct signatured_type *sig_type;
- ULONGEST offset, type_offset_in_tu, signature;
+ ULONGEST signature;
void **slot;
+ cu_offset type_offset_in_tu;
gdb_static_assert (sizeof (ULONGEST) >= 8);
- offset = extract_unsigned_integer (bytes, 8, BFD_ENDIAN_LITTLE);
- type_offset_in_tu = extract_unsigned_integer (bytes + 8, 8,
- BFD_ENDIAN_LITTLE);
+ sect_offset sect_off
+ = (sect_offset) extract_unsigned_integer (bytes, 8, BFD_ENDIAN_LITTLE);
+ type_offset_in_tu
+ = (cu_offset) extract_unsigned_integer (bytes + 8, 8,
+ BFD_ENDIAN_LITTLE);
signature = extract_unsigned_integer (bytes + 16, 8, BFD_ENDIAN_LITTLE);
bytes += 3 * 8;
sig_type = OBSTACK_ZALLOC (&objfile->objfile_obstack,
struct signatured_type);
sig_type->signature = signature;
- sig_type->type_offset_in_tu.cu_off = type_offset_in_tu;
+ sig_type->type_offset_in_tu = type_offset_in_tu;
sig_type->per_cu.is_debug_types = 1;
sig_type->per_cu.section = section;
- sig_type->per_cu.offset.sect_off = offset;
+ sig_type->per_cu.sect_off = sect_off;
sig_type->per_cu.objfile = objfile;
sig_type->per_cu.v.quick
= OBSTACK_ZALLOC (&objfile->objfile_obstack,
{
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;
int i;
void **slot;
struct quick_file_names *qfn;
- unsigned int line_offset;
gdb_assert (! this_cu->is_debug_types);
lh_cu = this_cu;
slot = NULL;
- line_offset = 0;
line_header_up lh;
+ sect_offset line_offset {};
attr = dwarf2_attr (comp_unit_die, DW_AT_stmt_list, cu);
if (attr)
{
struct quick_file_names find_entry;
- line_offset = DW_UNSND (attr);
+ line_offset = (sect_offset) DW_UNSND (attr);
/* We may have already read in this line header (TU line header sharing).
If we have we're done. */
find_entry.hash.dwo_unit = cu->dwo_unit;
- find_entry.hash.line_offset.sect_off = line_offset;
+ find_entry.hash.line_sect_off = line_offset;
slot = htab_find_slot (dwarf2_per_objfile->quick_file_names_table,
&find_entry, INSERT);
if (*slot != NULL)
qfn = XOBNEW (&objfile->objfile_obstack, struct quick_file_names);
qfn->hash.dwo_unit = cu->dwo_unit;
- qfn->hash.line_offset.sect_off = line_offset;
+ qfn->hash.line_sect_off = line_offset;
gdb_assert (slot != NULL);
*slot = qfn;
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. */
if (file_data == NULL)
continue;
- for (j = 0; j < file_data->num_file_names; ++j)
+ 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));
+ }
+
+ SELF_CHECK (!any_mismatch);
+
+#undef EXPECT
+#undef CHECK_MATCH
+}
+
+static void
+run_test ()
+{
+ test_mapped_index_find_name_component_bounds ();
+ test_dw2_expand_symtabs_matching_symbol ();
+}
+
+}} // namespace selftests::dw2_expand_symtabs_matching
+
+#endif /* GDB_SELF_TEST */
+
+/* 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. */
+
+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;
+
+ 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 = true;
+ }
+
+ /* 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)
{
- const char *this_fullname = file_data->file_names[j];
+ int symtab_was_null =
+ (per_cu->v.quick->compunit_symtab == NULL);
- if (filename_cmp (this_fullname, fullname) == 0)
- {
- dw2_instantiate_symtab (per_cu);
- break;
- }
+ 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_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. */
-}
-
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);
+ mapped_index &index = *dwarf2_per_objfile->index_table;
- 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);
- }
- }
- }
- }
+ 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
{
return header->initial_length_size + header->length;
}
-/* Return TRUE if OFFSET is within CU_HEADER. */
+/* Return TRUE if SECT_OFF is within CU_HEADER. */
-static inline int
-offset_in_cu_p (const struct comp_unit_head *cu_header, sect_offset offset)
+static inline bool
+offset_in_cu_p (const comp_unit_head *cu_header, sect_offset sect_off)
{
- sect_offset bottom = { cu_header->offset.sect_off };
- sect_offset top = { cu_header->offset.sect_off + get_cu_length (cu_header) };
+ sect_offset bottom = cu_header->sect_off;
+ sect_offset top = cu_header->sect_off + get_cu_length (cu_header);
- return (offset.sect_off >= bottom.sect_off && offset.sect_off < top.sect_off);
+ return sect_off >= bottom && sect_off < top;
}
/* Find the base address of the compilation unit for range lists and
cu_header->addr_size = read_1_byte (abfd, info_ptr);
info_ptr += 1;
}
- cu_header->abbrev_offset.sect_off = read_offset (abfd, info_ptr, cu_header,
- &bytes_read);
+ cu_header->abbrev_sect_off = (sect_offset) read_offset (abfd, info_ptr,
+ cu_header,
+ &bytes_read);
info_ptr += bytes_read;
if (cu_header->version < 5)
{
type_offset = read_offset (abfd, info_ptr, cu_header, &bytes_read);
info_ptr += bytes_read;
- cu_header->type_offset_in_tu.cu_off = type_offset;
- if (cu_header->type_offset_in_tu.cu_off != type_offset)
+ cu_header->type_cu_offset_in_tu = (cu_offset) type_offset;
+ if (to_underlying (cu_header->type_cu_offset_in_tu) != type_offset)
error (_("Dwarf Error: Too big type_offset in compilation unit "
"header (is %s) [in module %s]"), plongest (type_offset),
filename);
"(is %d, should be 2, 3, 4 or 5) [in module %s]"), header->version,
filename);
- if (header->abbrev_offset.sect_off
+ if (to_underlying (header->abbrev_sect_off)
>= dwarf2_section_size (dwarf2_per_objfile->objfile, abbrev_section))
- error (_("Dwarf Error: bad offset (0x%lx) in compilation unit header "
- "(offset 0x%lx + 6) [in module %s]"),
- (long) header->abbrev_offset.sect_off, (long) header->offset.sect_off,
+ error (_("Dwarf Error: bad offset (0x%x) in compilation unit header "
+ "(offset 0x%x + 6) [in module %s]"),
+ to_underlying (header->abbrev_sect_off),
+ to_underlying (header->sect_off),
filename);
- /* Cast to unsigned long to use 64-bit arithmetic when possible to
+ /* Cast to ULONGEST to use 64-bit arithmetic when possible to
avoid potential 32-bit overflow. */
- if (((unsigned long) header->offset.sect_off + get_cu_length (header))
+ if (((ULONGEST) header->sect_off + get_cu_length (header))
> section->size)
- error (_("Dwarf Error: bad length (0x%lx) in compilation unit header "
- "(offset 0x%lx + 0) [in module %s]"),
- (long) header->length, (long) header->offset.sect_off,
+ error (_("Dwarf Error: bad length (0x%x) in compilation unit header "
+ "(offset 0x%x + 0) [in module %s]"),
+ header->length, to_underlying (header->sect_off),
filename);
}
rcuh_kind section_kind)
{
const gdb_byte *beg_of_comp_unit = info_ptr;
- bfd *abfd = get_section_bfd_owner (section);
- header->offset.sect_off = beg_of_comp_unit - section->buffer;
+ header->sect_off = (sect_offset) (beg_of_comp_unit - section->buffer);
info_ptr = read_comp_unit_head (header, info_ptr, section, section_kind);
- header->first_die_offset.cu_off = info_ptr - beg_of_comp_unit;
+ header->first_die_cu_offset = (cu_offset) (info_ptr - beg_of_comp_unit);
error_check_comp_unit_head (header, section, abbrev_section);
static sect_offset
read_abbrev_offset (struct dwarf2_section_info *section,
- sect_offset offset)
+ sect_offset sect_off)
{
bfd *abfd = get_section_bfd_owner (section);
const gdb_byte *info_ptr;
unsigned int initial_length_size, offset_size;
- sect_offset abbrev_offset;
uint16_t version;
dwarf2_read_section (dwarf2_per_objfile->objfile, section);
- info_ptr = section->buffer + offset.sect_off;
+ info_ptr = section->buffer + to_underlying (sect_off);
read_initial_length (abfd, info_ptr, &initial_length_size);
offset_size = initial_length_size == 4 ? 4 : 8;
info_ptr += initial_length_size;
info_ptr += 2;
}
- abbrev_offset.sect_off = read_offset_1 (abfd, info_ptr, offset_size);
- return abbrev_offset;
+ return (sect_offset) read_offset_1 (abfd, info_ptr, offset_size);
}
/* Allocate a new partial symtab for file named NAME and mark this new
attr = dwarf2_attr (die, DW_AT_stmt_list, cu);
if (attr)
- lh = dwarf_decode_line_header (DW_UNSND (attr), cu);
+ lh = dwarf_decode_line_header ((sect_offset) DW_UNSND (attr), cu);
if (lh == NULL)
return; /* No linetable, so no includes. */
end_ptr = info_ptr + section->size;
while (info_ptr < end_ptr)
{
- sect_offset offset;
struct signatured_type *sig_type;
struct dwo_unit *dwo_tu;
void **slot;
struct comp_unit_head header;
unsigned int length;
- offset.sect_off = ptr - section->buffer;
+ sect_offset sect_off = (sect_offset) (ptr - section->buffer);
/* Initialize it due to a false compiler warning. */
header.signature = -1;
- header.type_offset_in_tu.cu_off = -1;
+ header.type_cu_offset_in_tu = (cu_offset) -1;
/* We need to read the type's signature in order to build the hash
table, but we don't need anything else just yet. */
struct dwo_unit);
dwo_tu->dwo_file = dwo_file;
dwo_tu->signature = header.signature;
- dwo_tu->type_offset_in_tu = header.type_offset_in_tu;
+ dwo_tu->type_offset_in_tu = header.type_cu_offset_in_tu;
dwo_tu->section = section;
- dwo_tu->offset = offset;
+ dwo_tu->sect_off = sect_off;
dwo_tu->length = length;
}
else
sig_type = OBSTACK_ZALLOC (&objfile->objfile_obstack,
struct signatured_type);
sig_type->signature = header.signature;
- sig_type->type_offset_in_tu = header.type_offset_in_tu;
+ sig_type->type_offset_in_tu = header.type_cu_offset_in_tu;
sig_type->per_cu.objfile = objfile;
sig_type->per_cu.is_debug_types = 1;
sig_type->per_cu.section = section;
- sig_type->per_cu.offset = offset;
+ sig_type->per_cu.sect_off = sect_off;
sig_type->per_cu.length = length;
}
gdb_assert (slot != NULL);
if (*slot != NULL)
{
- sect_offset dup_offset;
+ sect_offset dup_sect_off;
if (dwo_file)
{
const struct dwo_unit *dup_tu
= (const struct dwo_unit *) *slot;
- dup_offset = dup_tu->offset;
+ dup_sect_off = dup_tu->sect_off;
}
else
{
const struct signatured_type *dup_tu
= (const struct signatured_type *) *slot;
- dup_offset = dup_tu->per_cu.offset;
+ dup_sect_off = dup_tu->per_cu.sect_off;
}
complaint (&symfile_complaints,
_("debug type entry at offset 0x%x is duplicate to"
" the entry at offset 0x%x, signature %s"),
- offset.sect_off, dup_offset.sect_off,
+ to_underlying (sect_off), to_underlying (dup_sect_off),
hex_string (header.signature));
}
*slot = dwo_file ? (void *) dwo_tu : (void *) sig_type;
if (dwarf_read_debug > 1)
fprintf_unfiltered (gdb_stdlog, " offset 0x%x, signature %s\n",
- offset.sect_off,
+ to_underlying (sect_off),
hex_string (header.signature));
info_ptr += length;
else
gdb_assert (sig_entry->per_cu.v.psymtab == NULL);
gdb_assert (sig_entry->signature == dwo_entry->signature);
- gdb_assert (sig_entry->type_offset_in_section.sect_off == 0);
+ gdb_assert (to_underlying (sig_entry->type_offset_in_section) == 0);
gdb_assert (sig_entry->type_unit_group == NULL);
gdb_assert (sig_entry->dwo_unit == NULL);
sig_entry->per_cu.section = dwo_entry->section;
- sig_entry->per_cu.offset = dwo_entry->offset;
+ sig_entry->per_cu.sect_off = dwo_entry->sect_off;
sig_entry->per_cu.length = dwo_entry->length;
sig_entry->per_cu.reading_dwo_directly = 1;
sig_entry->per_cu.objfile = objfile;
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;
section = dwo_unit->section;
dwarf2_read_section (objfile, section);
abfd = get_section_bfd_owner (section);
- begin_info_ptr = info_ptr = section->buffer + dwo_unit->offset.sect_off;
+ begin_info_ptr = info_ptr = (section->buffer
+ + to_underlying (dwo_unit->sect_off));
dwo_abbrev_section = &dwo_unit->dwo_file->sections.abbrev;
init_cu_die_reader (result_reader, cu, section, dwo_unit->dwo_file);
" TU at offset 0x%x [in module %s]"),
hex_string (sig_type->signature),
hex_string (cu->header.signature),
- dwo_unit->offset.sect_off,
+ to_underlying (dwo_unit->sect_off),
bfd_get_filename (abfd));
}
- gdb_assert (dwo_unit->offset.sect_off == cu->header.offset.sect_off);
+ gdb_assert (dwo_unit->sect_off == cu->header.sect_off);
/* For DWOs coming from DWP files, we don't know the CU length
nor the type's offset in the TU until now. */
dwo_unit->length = get_cu_length (&cu->header);
- dwo_unit->type_offset_in_tu = cu->header.type_offset_in_tu;
+ dwo_unit->type_offset_in_tu = cu->header.type_cu_offset_in_tu;
/* Establish the type offset that can be used to lookup the type.
For DWO files, we don't know it until now. */
- sig_type->type_offset_in_section.sect_off =
- dwo_unit->offset.sect_off + dwo_unit->type_offset_in_tu.cu_off;
+ sig_type->type_offset_in_section
+ = dwo_unit->sect_off + to_underlying (dwo_unit->type_offset_in_tu);
}
else
{
info_ptr = read_and_check_comp_unit_head (&cu->header, section,
dwo_abbrev_section,
info_ptr, rcuh_kind::COMPILE);
- gdb_assert (dwo_unit->offset.sect_off == cu->header.offset.sect_off);
+ gdb_assert (dwo_unit->sect_off == cu->header.sect_off);
/* For DWOs coming from DWP files, we don't know the CU length
until now. */
dwo_unit->length = get_cu_length (&cu->header);
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;
if (dwarf_die_debug)
fprintf_unfiltered (gdb_stdlog, "Reading %s unit at offset 0x%x\n",
this_cu->is_debug_types ? "type" : "comp",
- this_cu->offset.sect_off);
+ to_underlying (this_cu->sect_off));
if (use_existing_cu)
gdb_assert (keep);
/* This is cheap if the section is already read in. */
dwarf2_read_section (objfile, section);
- begin_info_ptr = info_ptr = section->buffer + this_cu->offset.sect_off;
+ begin_info_ptr = info_ptr = section->buffer + to_underlying (this_cu->sect_off);
abbrev_section = get_abbrev_section_for_cu (this_cu);
}
/* Get the header. */
- if (cu->header.first_die_offset.cu_off != 0 && ! rereading_dwo_cu)
+ if (to_underlying (cu->header.first_die_cu_offset) != 0 && !rereading_dwo_cu)
{
/* We already have the header, there's no need to read it in again. */
- info_ptr += cu->header.first_die_offset.cu_off;
+ info_ptr += to_underlying (cu->header.first_die_cu_offset);
}
else
{
we can go from a pointer to one to a pointer to the other. */
sig_type = (struct signatured_type *) this_cu;
gdb_assert (sig_type->signature == cu->header.signature);
- gdb_assert (sig_type->type_offset_in_tu.cu_off
- == cu->header.type_offset_in_tu.cu_off);
- gdb_assert (this_cu->offset.sect_off == cu->header.offset.sect_off);
+ gdb_assert (sig_type->type_offset_in_tu
+ == cu->header.type_cu_offset_in_tu);
+ gdb_assert (this_cu->sect_off == cu->header.sect_off);
/* LENGTH has not been set yet for type units if we're
using .gdb_index. */
this_cu->length = get_cu_length (&cu->header);
/* Establish the type offset that can be used to lookup the type. */
- sig_type->type_offset_in_section.sect_off =
- this_cu->offset.sect_off + sig_type->type_offset_in_tu.cu_off;
+ sig_type->type_offset_in_section =
+ this_cu->sect_off + to_underlying (sig_type->type_offset_in_tu);
this_cu->dwarf_version = cu->header.version;
}
info_ptr,
rcuh_kind::COMPILE);
- gdb_assert (this_cu->offset.sect_off == cu->header.offset.sect_off);
+ gdb_assert (this_cu->sect_off == cu->header.sect_off);
gdb_assert (this_cu->length == get_cu_length (&cu->header));
this_cu->dwarf_version = cu->header.version;
}
if (abbrev_table != NULL)
{
gdb_assert (cu->abbrev_table == NULL);
- gdb_assert (cu->header.abbrev_offset.sect_off
- == abbrev_table->offset.sect_off);
+ gdb_assert (cu->header.abbrev_sect_off == abbrev_table->sect_off);
cu->abbrev_table = abbrev_table;
}
else if (cu->abbrev_table == NULL)
complaint (&symfile_complaints,
_("compilation unit with DW_AT_GNU_dwo_name"
" has children (offset 0x%x) [in module %s]"),
- this_cu->offset.sect_off, bfd_get_filename (abfd));
+ to_underlying (this_cu->sect_off), bfd_get_filename (abfd));
}
dwo_unit = lookup_dwo_unit (this_cu, comp_unit_die);
if (dwo_unit != NULL)
if (dwarf_die_debug)
fprintf_unfiltered (gdb_stdlog, "Reading %s unit at offset 0x%x\n",
this_cu->is_debug_types ? "type" : "comp",
- this_cu->offset.sect_off);
+ to_underlying (this_cu->sect_off));
gdb_assert (this_cu->cu == NULL);
cleanups = make_cleanup (free_stack_comp_unit, &cu);
- begin_info_ptr = info_ptr = section->buffer + this_cu->offset.sect_off;
+ begin_info_ptr = info_ptr = section->buffer + to_underlying (this_cu->sect_off);
info_ptr = read_and_check_comp_unit_head (&cu.header, section,
abbrev_section, info_ptr,
(this_cu->is_debug_types
}
else
{
- unsigned int line_offset = line_offset_struct.sect_off;
+ unsigned int line_offset = to_underlying (line_offset_struct);
struct partial_symtab *pst;
char *name;
}
tu_group->hash.dwo_unit = cu->dwo_unit;
- tu_group->hash.line_offset = line_offset_struct;
+ tu_group->hash.line_sect_off = line_offset_struct;
return tu_group;
}
}
type_unit_group_for_lookup.hash.dwo_unit = cu->dwo_unit;
- type_unit_group_for_lookup.hash.line_offset.sect_off = line_offset;
+ type_unit_group_for_lookup.hash.line_sect_off = (sect_offset) line_offset;
slot = htab_find_slot (dwarf2_per_objfile->type_unit_groups,
&type_unit_group_for_lookup, INSERT);
if (*slot != NULL)
}
else
{
- sect_offset line_offset_struct;
-
- line_offset_struct.sect_off = line_offset;
+ sect_offset line_offset_struct = (sect_offset) line_offset;
tu_group = create_type_unit_group (cu, line_offset_struct);
*slot = tu_group;
++tu_stats->nr_symtabs;
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;
"Psymtab for %s unit @0x%x: %s - %s"
", %d global, %d static syms\n",
per_cu->is_debug_types ? "type" : "comp",
- per_cu->offset.sect_off,
+ to_underlying (per_cu->sect_off),
paddress (gdbarch, pst->textlow),
paddress (gdbarch, pst->texthigh),
pst->n_global_syms, pst->n_static_syms);
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 ();
= (const struct tu_abbrev_offset * const*) ap;
const struct tu_abbrev_offset * const *b
= (const struct tu_abbrev_offset * const*) bp;
- unsigned int aoff = (*a)->abbrev_offset.sect_off;
- unsigned int boff = (*b)->abbrev_offset.sect_off;
+ sect_offset aoff = (*a)->abbrev_offset;
+ sect_offset boff = (*b)->abbrev_offset;
return (aoff > boff) - (aoff < boff);
}
sorted_by_abbrev[i].sig_type = sig_type;
sorted_by_abbrev[i].abbrev_offset =
read_abbrev_offset (sig_type->per_cu.section,
- sig_type->per_cu.offset);
+ sig_type->per_cu.sect_off);
}
cleanups = make_cleanup (xfree, sorted_by_abbrev);
qsort (sorted_by_abbrev, dwarf2_per_objfile->n_type_units,
sizeof (struct tu_abbrev_offset), sort_tu_by_abbrev_offset);
- abbrev_offset.sect_off = ~(unsigned) 0;
+ abbrev_offset = (sect_offset) ~(unsigned) 0;
abbrev_table = NULL;
make_cleanup (abbrev_table_free_cleanup, &abbrev_table);
/* Switch to the next abbrev table if necessary. */
if (abbrev_table == NULL
- || tu->abbrev_offset.sect_off != abbrev_offset.sect_off)
+ || tu->abbrev_offset != abbrev_offset)
{
if (abbrev_table != NULL)
{
}
}
-/* 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 offset;
- offset.sect_off = info_ptr - section->buffer;
+ 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));
- this_cu->offset = offset;
- this_cu->length = length + initial_length_size;
+ 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 = 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);
objfile_name (cu->objfile));
}
- per_cu = dwarf2_find_containing_comp_unit (pdi->d.offset,
+ per_cu = dwarf2_find_containing_comp_unit (pdi->d.sect_off,
pdi->is_dwz,
cu->objfile);
ignoring them. */
complaint (&symfile_complaints,
_("unhandled containing DIE tag %d for DIE at %d"),
- parent->tag, pdi->offset.sect_off);
+ parent->tag, to_underlying (pdi->sect_off));
parent->scope = grandparent_scope;
}
/* DW_FORM_ref_addr is using section offset. */
attr.name = (enum dwarf_attribute) 0;
attr.form = DW_FORM_ref_addr;
- attr.u.unsnd = pdi->offset.sect_off;
+ attr.u.unsnd = to_underlying (pdi->sect_off);
die = follow_die_ref (NULL, &attr, &ref_cu);
return xstrdup (dwarf2_full_name (NULL, die, ref_cu));
break;
case DW_TAG_constant:
{
- struct psymbol_allocation_list *list;
+ std::vector<partial_symbol *> *list;
if (pdi->is_external)
list = &objfile->global_psymbols;
error (_("Dwarf Error: Could not find abbrev number %d in %s"
" at offset 0x%x [in module %s]"),
abbrev_number, cu->per_cu->is_debug_types ? "TU" : "CU",
- cu->header.offset.sect_off, bfd_get_filename (abfd));
+ to_underlying (cu->header.sect_off), bfd_get_filename (abfd));
}
return abbrev;
_("ignoring absolute DW_AT_sibling"));
else
{
- unsigned int off = dwarf2_get_ref_die_offset (&attr).sect_off;
- const gdb_byte *sibling_ptr = buffer + off;
+ sect_offset off = dwarf2_get_ref_die_offset (&attr);
+ const gdb_byte *sibling_ptr = buffer + to_underlying (off);
if (sibling_ptr < info_ptr)
complaint (&symfile_complaints,
sprintf (buf, "TU %s at offset 0x%x",
hex_string (sig_type->signature),
- per_cu->offset.sect_off);
+ to_underlying (per_cu->sect_off));
/* There can be 100s of TUs.
Only print them in verbose mode. */
debug_print_threshold = 2;
}
else
{
- sprintf (buf, "CU at offset 0x%x", per_cu->offset.sect_off);
+ sprintf (buf, "CU at offset 0x%x",
+ to_underlying (per_cu->sect_off));
debug_print_threshold = 1;
}
{
const struct die_info *die = (const struct die_info *) item;
- return die->offset.sect_off;
+ return to_underlying (die->sect_off);
}
/* Trivial comparison function for die_info structures: two DIEs
const struct die_info *die_lhs = (const struct die_info *) item_lhs;
const struct die_info *die_rhs = (const struct die_info *) item_rhs;
- return die_lhs->offset.sect_off == die_rhs->offset.sect_off;
+ return die_lhs->sect_off == die_rhs->sect_off;
}
/* die_reader_func for load_full_comp_unit.
}
}
+/* 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. */
attr = dwarf2_attr (die, DW_AT_import, cu);
if (attr != NULL)
{
- struct dwarf2_per_cu_data *per_cu;
- sect_offset offset;
- int is_dwz;
-
- offset = dwarf2_get_ref_die_offset (attr);
- is_dwz = (attr->form == DW_FORM_GNU_ref_alt || cu->per_cu->is_dwz);
- per_cu = dwarf2_find_containing_comp_unit (offset, is_dwz, cu->objfile);
+ sect_offset sect_off = dwarf2_get_ref_die_offset (attr);
+ bool is_dwz = (attr->form == DW_FORM_GNU_ref_alt || cu->per_cu->is_dwz);
+ dwarf2_per_cu_data *per_cu
+ = dwarf2_find_containing_comp_unit (sect_off, is_dwz, cu->objfile);
/* If necessary, add it to the queue and load its DIEs. */
if (maybe_queue_comp_unit (cu, per_cu, cu->language))
}
}
-/* 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)
{
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;
complaint (&symfile_complaints,
_("Computed physname <%s> does not match demangled <%s> "
"(from linkage <%s>) - DIE at 0x%x [in module %s]"),
- physname, canon, mangled, die->offset.sect_off,
+ physname, canon, mangled, to_underlying (die->sect_off),
objfile_name (objfile));
/* Prefer DW_AT_linkage_name (in the CANON form) - when it
obstack_copy0 (&objfile->per_bfd->storage_obstack,
retval, strlen (retval)));
- do_cleanups (back_to);
return retval;
}
{
complaint (&symfile_complaints,
_("DIE at 0x%x has too many recursively imported "
- "declarations"), d->offset.sect_off);
+ "declarations"), to_underlying (d->sect_off));
return 0;
}
if (attr != NULL)
{
struct type *type;
- sect_offset offset = dwarf2_get_ref_die_offset (attr);
+ sect_offset sect_off = dwarf2_get_ref_die_offset (attr);
- type = get_die_type_at_offset (offset, cu->per_cu);
+ type = get_die_type_at_offset (sect_off, cu->per_cu);
if (type != NULL && TYPE_CODE (type) == TYPE_CODE_NAMESPACE)
{
/* This declaration is a global namespace alias. Add
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))
complaint (&symfile_complaints,
_("child DW_TAG_imported_declaration expected "
"- DIE at 0x%x [in module %s]"),
- child_die->offset.sect_off, objfile_name (objfile));
+ to_underlying (child_die->sect_off), objfile_name (objfile));
continue;
}
complaint (&symfile_complaints,
_("child DW_TAG_imported_declaration has unknown "
"imported name - DIE at 0x%x [in module %s]"),
- child_die->offset.sect_off, objfile_name (objfile));
+ to_underlying (child_die->sect_off), objfile_name (objfile));
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 objfile *objfile = dwarf2_per_objfile->objfile;
struct attribute *attr;
- unsigned int line_offset;
struct line_header line_header_local;
hashval_t line_header_local_hash;
- unsigned u;
void **slot;
int decode_mapping;
if (attr == NULL)
return;
- line_offset = DW_UNSND (attr);
+ sect_offset line_offset = (sect_offset) DW_UNSND (attr);
/* The line header hash table is only created if needed (it exists to
prevent redundant reading of the line table for partial_units).
dummy_obstack_deallocate);
}
- line_header_local.offset.sect_off = line_offset;
+ line_header_local.sect_off = line_offset;
line_header_local.offset_in_dwz = cu->per_cu->is_dwz;
line_header_local_hash = line_header_hash (&line_header_local);
if (dwarf2_per_objfile->line_header_hash != NULL)
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. */
struct type_unit_group *tu_group;
int first_time;
struct attribute *attr;
- unsigned int i, line_offset;
+ unsigned int i;
struct signatured_type *sig_type;
gdb_assert (per_cu->is_debug_types);
line_header_up lh;
if (attr != NULL)
{
- line_offset = DW_UNSND (attr);
+ sect_offset line_offset = (sect_offset) DW_UNSND (attr);
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 (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
void *datap)
{
struct dwarf2_cu *cu = reader->cu;
- sect_offset offset = cu->per_cu->offset;
+ sect_offset sect_off = cu->per_cu->sect_off;
struct dwarf2_section_info *section = cu->per_cu->section;
struct create_dwo_cu_data *data = (struct create_dwo_cu_data *) datap;
struct dwo_file *dwo_file = data->dwo_file;
complaint (&symfile_complaints,
_("Dwarf Error: debug entry at offset 0x%x is missing"
" its dwo_id [in module %s]"),
- offset.sect_off, dwo_file->dwo_name);
+ to_underlying (sect_off), dwo_file->dwo_name);
return;
}
dwo_unit->dwo_file = dwo_file;
dwo_unit->signature = DW_UNSND (attr);
dwo_unit->section = section;
- dwo_unit->offset = offset;
+ dwo_unit->sect_off = sect_off;
dwo_unit->length = cu->per_cu->length;
if (dwarf_read_debug)
fprintf_unfiltered (gdb_stdlog, " offset 0x%x, dwo_id %s\n",
- offset.sect_off, hex_string (dwo_unit->signature));
+ to_underlying (sect_off),
+ 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.offset.sect_off = 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;
- init_cutu_and_read_dies_no_follow (&per_cu, dwo_file,
- create_dwo_cu_reader,
- &create_dwo_cu_data);
+ // If the unit could not be parsed, skip it.
+ if (create_dwo_cu_data.dwo_unit.dwo_file == NULL)
+ continue;
+
+ 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",
- this_unit->offset.sect_off, objfile_name (objfile));
-
- do_cleanups (cleanups);
+ to_underlying (this_unit->sect_off), objfile_name (objfile));
}
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;
&& origin_die->tag == DW_TAG_subprogram))
complaint (&symfile_complaints,
_("DIE 0x%x and its abstract origin 0x%x have different tags"),
- die->offset.sect_off, origin_die->offset.sect_off);
+ 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))
&& child_origin_die->tag == DW_TAG_subprogram))
complaint (&symfile_complaints,
_("Child DIE 0x%x and its abstract origin 0x%x have "
- "different tags"), child_die->offset.sect_off,
- child_origin_die->offset.sect_off);
+ "different tags"),
+ to_underlying (child_die->sect_off),
+ to_underlying (child_origin_die->sect_off));
if (child_origin_die->parent != origin_die)
complaint (&symfile_complaints,
_("Child DIE 0x%x and its abstract origin 0x%x have "
- "different parents"), child_die->offset.sect_off,
- child_origin_die->offset.sect_off);
+ "different parents"),
+ to_underlying (child_die->sect_off),
+ to_underlying (child_origin_die->sect_off));
else
- *offsets_end++ = child_origin_die->offset;
+ 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++)
- if (offsetp[-1].sect_off == offsetp->sect_off)
+ 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"),
- die->offset.sect_off, offsetp->sect_off);
+ 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)
{
/* Is ORIGIN_CHILD_DIE referenced by any of the DIE children? */
while (offsetp < offsets_end
- && offsetp->sect_off < origin_child_die->offset.sect_off)
+ && *offsetp < origin_child_die->sect_off)
offsetp++;
if (offsetp >= offsets_end
- || offsetp->sect_off > origin_child_die->offset.sect_off)
+ || *offsetp > origin_child_die->sect_off)
{
/* Found that ORIGIN_CHILD_DIE is really not referenced.
Check whether we're already processing ORIGIN_CHILD_DIE.
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)
{
complaint (&symfile_complaints,
_("missing name for subprogram DIE at %d"),
- die->offset.sect_off);
+ to_underlying (die->sect_off));
return;
}
complaint (&symfile_complaints,
_("cannot get low and high bounds "
"for subprogram DIE at %d"),
- die->offset.sect_off);
+ to_underlying (die->sect_off));
return;
}
|| 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
complaint (&symfile_complaints,
_("missing DW_AT_call_return_pc for DW_TAG_call_site "
"DIE 0x%x [in module %s]"),
- die->offset.sect_off, objfile_name (objfile));
+ to_underlying (die->sect_off), objfile_name (objfile));
return;
}
pc = attr_value_as_address (attr) + baseaddr;
complaint (&symfile_complaints,
_("Duplicate PC %s for DW_TAG_call_site "
"DIE 0x%x [in module %s]"),
- paddress (gdbarch, pc), die->offset.sect_off,
+ paddress (gdbarch, pc), to_underlying (die->sect_off),
objfile_name (objfile));
return;
}
complaint (&symfile_complaints,
_("Tag %d is not DW_TAG_call_site_parameter in "
"DW_TAG_call_site child DIE 0x%x [in module %s]"),
- child_die->tag, child_die->offset.sect_off,
+ child_die->tag, to_underlying (child_die->sect_off),
objfile_name (objfile));
continue;
}
complaint (&symfile_complaints,
_("Cannot find function owning DW_TAG_call_site "
"DIE 0x%x [in module %s]"),
- die->offset.sect_off, objfile_name (objfile));
+ to_underlying (die->sect_off), objfile_name (objfile));
}
}
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)
complaint (&symfile_complaints,
_("DW_AT_call_target target DIE has invalid "
"physname, for referencing DIE 0x%x [in module %s]"),
- die->offset.sect_off, objfile_name (objfile));
+ to_underlying (die->sect_off), objfile_name (objfile));
else
SET_FIELD_PHYSNAME (call_site->target, target_physname);
}
complaint (&symfile_complaints,
_("DW_AT_call_target target DIE has invalid "
"low pc, for referencing DIE 0x%x [in module %s]"),
- die->offset.sect_off, objfile_name (objfile));
+ to_underlying (die->sect_off), objfile_name (objfile));
else
{
lowpc = gdbarch_adjust_dwarf2_addr (gdbarch, lowpc + baseaddr);
complaint (&symfile_complaints,
_("DW_TAG_call_site DW_AT_call_target is neither "
"block nor reference, for DIE 0x%x [in module %s]"),
- die->offset.sect_off, objfile_name (objfile));
+ to_underlying (die->sect_off), objfile_name (objfile));
call_site->per_cu = cu->per_cu;
}
if (loc == NULL && origin != NULL && attr_form_is_ref (origin))
{
- sect_offset offset;
-
parameter->kind = CALL_SITE_PARAMETER_PARAM_OFFSET;
- offset = dwarf2_get_ref_die_offset (origin);
- if (!offset_in_cu_p (&cu->header, offset))
+
+ sect_offset sect_off
+ = (sect_offset) dwarf2_get_ref_die_offset (origin);
+ if (!offset_in_cu_p (&cu->header, sect_off))
{
/* As DW_OP_GNU_parameter_ref uses CU-relative offset this
binding can be done only inside one CU. Such referenced DIE
complaint (&symfile_complaints,
_("DW_AT_call_parameter offset is not in CU for "
"DW_TAG_call_site child DIE 0x%x [in module %s]"),
- child_die->offset.sect_off, objfile_name (objfile));
+ to_underlying (child_die->sect_off),
+ objfile_name (objfile));
continue;
}
- parameter->u.param_offset.cu_off = (offset.sect_off
- - cu->header.offset.sect_off);
+ parameter->u.param_cu_off
+ = (cu_offset) (sect_off - cu->header.sect_off);
}
else if (loc == NULL || origin != NULL || !attr_form_is_block (loc))
{
complaint (&symfile_complaints,
_("No DW_FORM_block* DW_AT_location for "
"DW_TAG_call_site child DIE 0x%x [in module %s]"),
- child_die->offset.sect_off, objfile_name (objfile));
+ to_underlying (child_die->sect_off), objfile_name (objfile));
continue;
}
else
"for DW_FORM_block* DW_AT_location is supported for "
"DW_TAG_call_site child DIE 0x%x "
"[in module %s]"),
- child_die->offset.sect_off, objfile_name (objfile));
+ to_underlying (child_die->sect_off),
+ objfile_name (objfile));
continue;
}
}
complaint (&symfile_complaints,
_("No DW_FORM_block* DW_AT_call_value for "
"DW_TAG_call_site child DIE 0x%x [in module %s]"),
- child_die->offset.sect_off, objfile_name (objfile));
+ to_underlying (child_die->sect_off),
+ objfile_name (objfile));
continue;
}
parameter->value = DW_BLOCK (attr)->data;
complaint (&symfile_complaints,
_("No DW_FORM_block* DW_AT_call_data_value for "
"DW_TAG_call_site child DIE 0x%x [in module %s]"),
- child_die->offset.sect_off, objfile_name (objfile));
+ to_underlying (child_die->sect_off),
+ objfile_name (objfile));
else
{
parameter->data_value = DW_BLOCK (attr)->data;
}
}
+/* 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. */
complaint (&symfile_complaints,
_("cannot determine context for virtual member "
"function \"%s\" (offset %d)"),
- fieldname, die->offset.sect_off);
+ fieldname, to_underlying (die->sect_off));
}
else
{
complaint (&symfile_complaints,
_("Member function \"%s\" (offset %d) is virtual "
"but the vtable offset is not specified"),
- fieldname, die->offset.sect_off);
+ fieldname, to_underlying (die->sect_off));
ALLOCATE_CPLUS_STRUCT_TYPE (type);
TYPE_CPLUS_DYNAMIC (type) = 1;
}
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 signatured_type *sig_type;
sig_type = (struct signatured_type *) cu->per_cu;
- gdb_assert (sig_type->type_offset_in_section.sect_off != 0);
- if (sig_type->type_offset_in_section.sect_off != die->offset.sect_off)
+ gdb_assert (to_underlying (sig_type->type_offset_in_section) != 0);
+ if (sig_type->type_offset_in_section != die->sect_off)
return;
}
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;
}
baton->data = ptr;
*ptr++ = DW_OP_call4;
- cu_off = common_die->offset.sect_off - cu->per_cu->offset.sect_off;
+ cu_off = common_die->sect_off - cu->per_cu->sect_off;
store_unsigned_integer (ptr, 4, byte_order, cu_off);
ptr += 4;
_("Variable in common block has "
"DW_AT_data_member_location "
"- DIE at 0x%x [in module %s]"),
- child_die->offset.sect_off,
+ to_underlying (child_die->sect_off),
objfile_name (cu->objfile));
if (attr_form_is_section_offset (member_loc))
{
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 (!module_name)
complaint (&symfile_complaints,
_("DW_TAG_module has no name, offset 0x%x"),
- die->offset.sect_off);
+ to_underlying (die->sect_off));
type = init_type (objfile, TYPE_CODE_MODULE, 0, module_name);
/* determine_prefix uses TYPE_TAG_NAME. */
complaint (&symfile_complaints,
_("Self-referential DW_TAG_typedef "
"- DIE at 0x%x [in module %s]"),
- die->offset.sect_off, objfile_name (objfile));
+ to_underlying (die->sect_off), objfile_name (objfile));
TYPE_TARGET_TYPE (this_type) = NULL;
}
return this_type;
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:
type = init_integer_type (objfile, bits, 1, name);
break;
case DW_ATE_UTF:
- /* We just treat this as an integer and then recognize the
- type by name elsewhere. */
- type = init_integer_type (objfile, bits, 0, name);
+ {
+ gdbarch *arch = get_objfile_arch (objfile);
+
+ if (bits == 16)
+ type = builtin_type (arch)->builtin_char16;
+ else if (bits == 32)
+ type = builtin_type (arch)->builtin_char32;
+ else
+ {
+ complaint (&symfile_complaints,
+ _("unsupported DW_ATE_UTF bit size: '%d'"),
+ bits);
+ type = init_integer_type (objfile, bits, 1, name);
+ }
+ return set_die_type (die, type, cu);
+ }
break;
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;
}
else if (!low_default_is_valid)
complaint (&symfile_complaints, _("Missing DW_AT_lower_bound "
"- DIE at 0x%x [in module %s]"),
- die->offset.sect_off, objfile_name (cu->objfile));
+ to_underlying (die->sect_off), objfile_name (cu->objfile));
attr = dwarf2_attr (die, DW_AT_upper_bound, cu);
if (!attr_to_dynamic_prop (attr, die, cu, &high))
int *has_children, int num_extra_attrs)
{
unsigned int abbrev_number, bytes_read, i;
- sect_offset offset;
struct abbrev_info *abbrev;
struct die_info *die;
struct dwarf2_cu *cu = reader->cu;
bfd *abfd = reader->abfd;
- offset.sect_off = info_ptr - reader->buffer;
+ sect_offset sect_off = (sect_offset) (info_ptr - reader->buffer);
abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
if (!abbrev_number)
bfd_get_filename (abfd));
die = dwarf_alloc_die (cu, abbrev->num_attrs + num_extra_attrs);
- die->offset = offset;
+ die->sect_off = sect_off;
die->tag = abbrev->tag;
die->abbrev = abbrev_number;
static struct abbrev_table *
abbrev_table_read_table (struct dwarf2_section_info *section,
- sect_offset offset)
+ sect_offset sect_off)
{
struct objfile *objfile = dwarf2_per_objfile->objfile;
bfd *abfd = get_section_bfd_owner (section);
unsigned int allocated_attrs;
abbrev_table = XNEW (struct abbrev_table);
- abbrev_table->offset = offset;
+ abbrev_table->sect_off = sect_off;
obstack_init (&abbrev_table->abbrev_obstack);
abbrev_table->abbrevs =
XOBNEWVEC (&abbrev_table->abbrev_obstack, struct abbrev_info *,
ABBREV_HASH_SIZE * sizeof (struct abbrev_info *));
dwarf2_read_section (objfile, section);
- abbrev_ptr = section->buffer + offset.sect_off;
+ abbrev_ptr = section->buffer + to_underlying (sect_off);
abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
abbrev_ptr += bytes_read;
struct dwarf2_section_info *abbrev_section)
{
cu->abbrev_table =
- abbrev_table_read_table (abbrev_section, cu->header.abbrev_offset);
+ abbrev_table_read_table (abbrev_section, cu->header.abbrev_sect_off);
}
/* Release the memory used by the abbrev table for a compilation unit. */
complaint (&symfile_complaints,
_("DW_TAG_typedef has childen - GCC PR debug/47510 bug "
"- DIE at 0x%x [in module %s]"),
- part_die->offset.sect_off, objfile_name (objfile));
+ to_underlying (part_die->sect_off), objfile_name (objfile));
/* If we're at the second level, and we're an enumerator, and
our parent has no specification (meaning possibly lives in a
void **slot;
slot = htab_find_slot_with_hash (cu->partial_dies, part_die,
- part_die->offset.sect_off, INSERT);
+ to_underlying (part_die->sect_off),
+ INSERT);
*slot = part_die;
}
memset (part_die, 0, sizeof (struct partial_die_info));
- part_die->offset.sect_off = info_ptr - buffer;
+ part_die->sect_off = (sect_offset) (info_ptr - buffer);
info_ptr += abbrev_len;
_("ignoring absolute DW_AT_sibling"));
else
{
- unsigned int off = dwarf2_get_ref_die_offset (&attr).sect_off;
- const gdb_byte *sibling_ptr = buffer + off;
+ sect_offset off = dwarf2_get_ref_die_offset (&attr);
+ const gdb_byte *sibling_ptr = buffer + to_underlying (off);
if (sibling_ptr < info_ptr)
complaint (&symfile_complaints,
case DW_AT_import:
if (part_die->tag == DW_TAG_imported_unit)
{
- part_die->d.offset = dwarf2_get_ref_die_offset (&attr);
+ part_die->d.sect_off = dwarf2_get_ref_die_offset (&attr);
part_die->is_dwz = (attr.form == DW_FORM_GNU_ref_alt
|| cu->per_cu->is_dwz);
}
_("DW_AT_low_pc %s is zero "
"for DIE at 0x%x [in module %s]"),
paddress (gdbarch, part_die->lowpc),
- part_die->offset.sect_off, objfile_name (objfile));
+ to_underlying (part_die->sect_off), objfile_name (objfile));
}
/* dwarf2_get_pc_bounds has also the strict low < high requirement. */
else if (part_die->lowpc >= part_die->highpc)
"for DIE at 0x%x [in module %s]"),
paddress (gdbarch, part_die->lowpc),
paddress (gdbarch, part_die->highpc),
- part_die->offset.sect_off, objfile_name (objfile));
+ to_underlying (part_die->sect_off),
+ objfile_name (objfile));
}
else
part_die->has_pc_info = 1;
/* Find a cached partial DIE at OFFSET in CU. */
static struct partial_die_info *
-find_partial_die_in_comp_unit (sect_offset offset, struct dwarf2_cu *cu)
+find_partial_die_in_comp_unit (sect_offset sect_off, struct dwarf2_cu *cu)
{
struct partial_die_info *lookup_die = NULL;
struct partial_die_info part_die;
- part_die.offset = offset;
+ part_die.sect_off = sect_off;
lookup_die = ((struct partial_die_info *)
htab_find_with_hash (cu->partial_dies, &part_die,
- offset.sect_off));
+ to_underlying (sect_off)));
return lookup_die;
}
DW_FORM_ref_sig8). */
static struct partial_die_info *
-find_partial_die (sect_offset offset, int offset_in_dwz, struct dwarf2_cu *cu)
+find_partial_die (sect_offset sect_off, int offset_in_dwz, struct dwarf2_cu *cu)
{
struct objfile *objfile = cu->objfile;
struct dwarf2_per_cu_data *per_cu = NULL;
struct partial_die_info *pd = NULL;
if (offset_in_dwz == cu->per_cu->is_dwz
- && offset_in_cu_p (&cu->header, offset))
+ && offset_in_cu_p (&cu->header, sect_off))
{
- pd = find_partial_die_in_comp_unit (offset, cu);
+ pd = find_partial_die_in_comp_unit (sect_off, cu);
if (pd != NULL)
return pd;
/* We missed recording what we needed.
/* TUs don't reference other CUs/TUs (except via type signatures). */
if (cu->per_cu->is_debug_types)
{
- error (_("Dwarf Error: Type Unit at offset 0x%lx contains"
- " external reference to offset 0x%lx [in module %s].\n"),
- (long) cu->header.offset.sect_off, (long) offset.sect_off,
+ error (_("Dwarf Error: Type Unit at offset 0x%x contains"
+ " external reference to offset 0x%x [in module %s].\n"),
+ to_underlying (cu->header.sect_off), to_underlying (sect_off),
bfd_get_filename (objfile->obfd));
}
- per_cu = dwarf2_find_containing_comp_unit (offset, offset_in_dwz,
+ per_cu = dwarf2_find_containing_comp_unit (sect_off, offset_in_dwz,
objfile);
if (per_cu->cu == NULL || per_cu->cu->partial_dies == NULL)
load_partial_comp_unit (per_cu);
per_cu->cu->last_used = 0;
- pd = find_partial_die_in_comp_unit (offset, per_cu->cu);
+ pd = find_partial_die_in_comp_unit (sect_off, per_cu->cu);
}
/* If we didn't find it, and not all dies have been loaded,
set. */
load_partial_comp_unit (per_cu);
- pd = find_partial_die_in_comp_unit (offset, per_cu->cu);
+ pd = find_partial_die_in_comp_unit (sect_off, per_cu->cu);
}
if (pd == NULL)
internal_error (__FILE__, __LINE__,
_("could not find partial DIE 0x%x "
"in cache [from module %s]\n"),
- offset.sect_off, bfd_get_filename (objfile->obfd));
+ to_underlying (sect_off), bfd_get_filename (objfile->obfd));
return pd;
}
info_ptr += bytes_read;
break;
case DW_FORM_ref1:
- DW_UNSND (attr) = (cu->header.offset.sect_off
+ DW_UNSND (attr) = (to_underlying (cu->header.sect_off)
+ read_1_byte (abfd, info_ptr));
info_ptr += 1;
break;
case DW_FORM_ref2:
- DW_UNSND (attr) = (cu->header.offset.sect_off
+ DW_UNSND (attr) = (to_underlying (cu->header.sect_off)
+ read_2_bytes (abfd, info_ptr));
info_ptr += 2;
break;
case DW_FORM_ref4:
- DW_UNSND (attr) = (cu->header.offset.sect_off
+ DW_UNSND (attr) = (to_underlying (cu->header.sect_off)
+ read_4_bytes (abfd, info_ptr));
info_ptr += 4;
break;
case DW_FORM_ref8:
- DW_UNSND (attr) = (cu->header.offset.sect_off
+ DW_UNSND (attr) = (to_underlying (cu->header.sect_off)
+ read_8_bytes (abfd, info_ptr));
info_ptr += 8;
break;
info_ptr += 8;
break;
case DW_FORM_ref_udata:
- DW_UNSND (attr) = (cu->header.offset.sect_off
+ DW_UNSND (attr) = (to_underlying (cu->header.sect_off)
+ read_unsigned_leb128 (abfd, info_ptr, &bytes_read));
info_ptr += bytes_read;
break;
dwarf2_read_section (objfile, str_offsets_section);
if (str_section->buffer == NULL)
error (_("%s used without .debug_str.dwo section"
- " in CU at offset 0x%lx [in module %s]"),
- form_name, (long) cu->header.offset.sect_off, objf_name);
+ " in CU at offset 0x%x [in module %s]"),
+ form_name, to_underlying (cu->header.sect_off), objf_name);
if (str_offsets_section->buffer == NULL)
error (_("%s used without .debug_str_offsets.dwo section"
- " in CU at offset 0x%lx [in module %s]"),
- form_name, (long) cu->header.offset.sect_off, objf_name);
+ " in CU at offset 0x%x [in module %s]"),
+ form_name, to_underlying (cu->header.sect_off), objf_name);
if (str_index * cu->header.offset_size >= str_offsets_section->size)
error (_("%s pointing outside of .debug_str_offsets.dwo"
- " section in CU at offset 0x%lx [in module %s]"),
- form_name, (long) cu->header.offset.sect_off, objf_name);
+ " section in CU at offset 0x%x [in module %s]"),
+ form_name, to_underlying (cu->header.sect_off), objf_name);
info_ptr = (str_offsets_section->buffer
+ str_index * cu->header.offset_size);
if (cu->header.offset_size == 4)
str_offset = bfd_get_64 (abfd, info_ptr);
if (str_offset >= str_section->size)
error (_("Offset from %s pointing outside of"
- " .debug_str.dwo section in CU at offset 0x%lx [in module %s]"),
- form_name, (long) cu->header.offset.sect_off, objf_name);
+ " .debug_str.dwo section in CU at offset 0x%x [in module %s]"),
+ form_name, to_underlying (cu->header.sect_off), objf_name);
return (const char *) (str_section->buffer + str_offset);
}
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,
_("string type expected for attribute %s for "
"DIE at 0x%x in module %s"),
- dwarf_attr_name (name), die->offset.sect_off,
+ dwarf_attr_name (name), to_underlying (die->sect_off),
objfile_name (cu->objfile));
}
void
line_header::add_file_name (const char *name,
- unsigned int dir_index,
+ dir_index d_index,
unsigned int mod_time,
unsigned int length)
{
fprintf_unfiltered (gdb_stdlog, "Adding file %u: %s\n",
(unsigned) file_names.size () + 1, name);
- file_names.emplace_back (name, dir_index, mod_time, length);
+ file_names.emplace_back (name, d_index, mod_time, length);
}
/* A convenience function to find the proper .debug_line section for a CU. */
const struct comp_unit_head *cu_header,
void (*callback) (struct line_header *lh,
const char *name,
- unsigned int dir_index,
+ dir_index d_index,
unsigned int mod_time,
unsigned int length))
{
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);
for (formati = 0; formati < format_count; formati++)
{
- ULONGEST content_type, form;
- const char *string_trash;
- const char **stringp = &string_trash;
- unsigned int uint_trash, *uintp = &uint_trash;
-
- content_type = read_unsigned_leb128 (abfd, format, &bytes_read);
+ ULONGEST content_type = read_unsigned_leb128 (abfd, format, &bytes_read);
format += bytes_read;
- switch (content_type)
- {
- case DW_LNCT_path:
- stringp = &fe.name;
- break;
- case DW_LNCT_directory_index:
- uintp = &fe.dir_index;
- break;
- case DW_LNCT_timestamp:
- uintp = &fe.mod_time;
- break;
- case DW_LNCT_size:
- uintp = &fe.length;
- break;
- case DW_LNCT_MD5:
- break;
- default:
- complaint (&symfile_complaints,
- _("Unknown format content type %s"),
- pulongest (content_type));
- }
- form = read_unsigned_leb128 (abfd, format, &bytes_read);
+ ULONGEST form = read_unsigned_leb128 (abfd, format, &bytes_read);
format += bytes_read;
+
+ gdb::optional<const char *> string;
+ gdb::optional<unsigned int> uint;
+
switch (form)
{
case DW_FORM_string:
- *stringp = read_direct_string (abfd, buf, &bytes_read);
+ string.emplace (read_direct_string (abfd, buf, &bytes_read));
buf += bytes_read;
break;
case DW_FORM_line_strp:
- *stringp = read_indirect_line_string (abfd, buf, cu_header, &bytes_read);
+ string.emplace (read_indirect_line_string (abfd, buf,
+ cu_header,
+ &bytes_read));
buf += bytes_read;
break;
case DW_FORM_data1:
- *uintp = read_1_byte (abfd, buf);
+ uint.emplace (read_1_byte (abfd, buf));
buf += 1;
break;
case DW_FORM_data2:
- *uintp = read_2_bytes (abfd, buf);
+ uint.emplace (read_2_bytes (abfd, buf));
buf += 2;
break;
case DW_FORM_data4:
- *uintp = read_4_bytes (abfd, buf);
+ uint.emplace (read_4_bytes (abfd, buf));
buf += 4;
break;
case DW_FORM_data8:
- *uintp = read_8_bytes (abfd, buf);
+ uint.emplace (read_8_bytes (abfd, buf));
buf += 8;
break;
case DW_FORM_udata:
- *uintp = read_unsigned_leb128 (abfd, buf, &bytes_read);
+ uint.emplace (read_unsigned_leb128 (abfd, buf, &bytes_read));
buf += bytes_read;
break;
current GDB. */
break;
}
+
+ switch (content_type)
+ {
+ case DW_LNCT_path:
+ if (string.has_value ())
+ fe.name = *string;
+ break;
+ case DW_LNCT_directory_index:
+ if (uint.has_value ())
+ fe.d_index = (dir_index) *uint;
+ break;
+ case DW_LNCT_timestamp:
+ if (uint.has_value ())
+ fe.mod_time = *uint;
+ break;
+ case DW_LNCT_size:
+ if (uint.has_value ())
+ fe.length = *uint;
+ break;
+ case DW_LNCT_MD5:
+ break;
+ default:
+ complaint (&symfile_complaints,
+ _("Unknown format content type %s"),
+ pulongest (content_type));
+ }
}
- callback (lh, fe.name, fe.dir_index, fe.mod_time, fe.length);
+ callback (lh, fe.name, fe.d_index, fe.mod_time, fe.length);
}
*bufp = buf;
and must not be freed. */
static line_header_up
-dwarf_decode_line_header (unsigned int offset, struct dwarf2_cu *cu)
+dwarf_decode_line_header (sect_offset sect_off, struct dwarf2_cu *cu)
{
const gdb_byte *line_ptr;
unsigned int bytes_read, offset_size;
/* Make sure that at least there's room for the total_length field.
That could be 12 bytes long, but we're just going to fudge that. */
- if (offset + 4 >= section->size)
+ if (to_underlying (sect_off) + 4 >= section->size)
{
dwarf2_statement_list_fits_in_line_number_section_complaint ();
return 0;
line_header_up lh (new line_header ());
- lh->offset.sect_off = offset;
+ lh->sect_off = sect_off;
lh->offset_in_dwz = cu->per_cu->is_dwz;
- line_ptr = section->buffer + offset;
+ line_ptr = section->buffer + to_underlying (sect_off);
/* Read in the header. */
lh->total_length =
/* Read directory table. */
read_formatted_entries (abfd, &line_ptr, lh.get (), &cu->header,
[] (struct line_header *lh, const char *name,
- unsigned int dir_index, unsigned int mod_time,
+ dir_index d_index, unsigned int mod_time,
unsigned int length)
{
lh->add_include_dir (name);
/* Read file name table. */
read_formatted_entries (abfd, &line_ptr, lh.get (), &cu->header,
[] (struct line_header *lh, const char *name,
- unsigned int dir_index, unsigned int mod_time,
+ dir_index d_index, unsigned int mod_time,
unsigned int length)
{
- lh->add_file_name (name, dir_index, mod_time, length);
+ lh->add_file_name (name, d_index, mod_time, length);
});
}
else
/* Read file name table. */
while ((cur_file = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL)
{
- unsigned int dir_index, mod_time, length;
+ unsigned int mod_time, length;
+ dir_index d_index;
line_ptr += bytes_read;
- dir_index = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ d_index = (dir_index) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
mod_time = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
length = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
- lh->add_file_name (cur_file, dir_index, mod_time, length);
+ lh->add_file_name (cur_file, d_index, mod_time, length);
}
line_ptr += bytes_read;
}
/* State machine to track the state of the line number program. */
-struct lnp_state_machine
+class lnp_state_machine
{
+public:
+ /* Initialize a machine state for the start of a line number
+ program. */
+ lnp_state_machine (gdbarch *arch, line_header *lh, bool record_lines_p);
+
file_entry *current_file ()
{
/* lh->file_names is 0-based, but the file name numbers in the
statement program are 1-based. */
- return the_line_header->file_name_at (file - 1);
+ return m_line_header->file_name_at (m_file);
+ }
+
+ /* Record the line in the state machine. END_SEQUENCE is true if
+ we're processing the end of a sequence. */
+ void record_line (bool end_sequence);
+
+ /* Check address and if invalid nop-out the rest of the lines in this
+ sequence. */
+ void check_line_address (struct dwarf2_cu *cu,
+ const gdb_byte *line_ptr,
+ CORE_ADDR lowpc, CORE_ADDR address);
+
+ void handle_set_discriminator (unsigned int discriminator)
+ {
+ m_discriminator = discriminator;
+ m_line_has_non_zero_discriminator |= discriminator != 0;
+ }
+
+ /* Handle DW_LNE_set_address. */
+ void handle_set_address (CORE_ADDR baseaddr, CORE_ADDR address)
+ {
+ m_op_index = 0;
+ address += baseaddr;
+ m_address = gdbarch_adjust_dwarf2_line (m_gdbarch, address, false);
}
+ /* Handle DW_LNS_advance_pc. */
+ void handle_advance_pc (CORE_ADDR adjust);
+
+ /* Handle a special opcode. */
+ void handle_special_opcode (unsigned char op_code);
+
+ /* Handle DW_LNS_advance_line. */
+ void handle_advance_line (int line_delta)
+ {
+ advance_line (line_delta);
+ }
+
+ /* Handle DW_LNS_set_file. */
+ void handle_set_file (file_name_index file);
+
+ /* Handle DW_LNS_negate_stmt. */
+ void handle_negate_stmt ()
+ {
+ m_is_stmt = !m_is_stmt;
+ }
+
+ /* Handle DW_LNS_const_add_pc. */
+ void handle_const_add_pc ();
+
+ /* Handle DW_LNS_fixed_advance_pc. */
+ void handle_fixed_advance_pc (CORE_ADDR addr_adj)
+ {
+ m_address += gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true);
+ m_op_index = 0;
+ }
+
+ /* Handle DW_LNS_copy. */
+ void handle_copy ()
+ {
+ record_line (false);
+ m_discriminator = 0;
+ }
+
+ /* Handle DW_LNE_end_sequence. */
+ void handle_end_sequence ()
+ {
+ m_record_line_callback = ::record_line;
+ }
+
+private:
+ /* Advance the line by LINE_DELTA. */
+ void advance_line (int line_delta)
+ {
+ m_line += line_delta;
+
+ if (line_delta != 0)
+ m_line_has_non_zero_discriminator = m_discriminator != 0;
+ }
+
+ gdbarch *m_gdbarch;
+
+ /* True if we're recording lines.
+ Otherwise we're building partial symtabs and are just interested in
+ finding include files mentioned by the line number program. */
+ bool m_record_lines_p;
+
/* The line number header. */
- line_header *the_line_header;
+ line_header *m_line_header;
- /* These are part of the standard DWARF line number state machine. */
+ /* These are part of the standard DWARF line number state machine,
+ and initialized according to the DWARF spec. */
- unsigned char op_index;
+ unsigned char m_op_index = 0;
/* The line table index (1-based) of the current file. */
- unsigned int file;
- unsigned int line;
- CORE_ADDR address;
- int is_stmt;
- unsigned int discriminator;
+ file_name_index m_file = (file_name_index) 1;
+ unsigned int m_line = 1;
+
+ /* These are initialized in the constructor. */
+
+ CORE_ADDR m_address;
+ bool m_is_stmt;
+ unsigned int m_discriminator;
/* Additional bits of state we need to track. */
/* The last file that we called dwarf2_start_subfile for.
This is only used for TLLs. */
- unsigned int last_file;
+ unsigned int m_last_file = 0;
/* The last file a line number was recorded for. */
- struct subfile *last_subfile;
+ struct subfile *m_last_subfile = NULL;
/* The function to call to record a line. */
- record_line_ftype *record_line;
+ record_line_ftype *m_record_line_callback = NULL;
/* The last line number that was recorded, used to coalesce
consecutive entries for the same line. This can happen, for
example, when discriminators are present. PR 17276. */
- unsigned int last_line;
- int line_has_non_zero_discriminator;
+ unsigned int m_last_line = 0;
+ bool m_line_has_non_zero_discriminator = false;
};
-/* There's a lot of static state to pass to dwarf_record_line.
- This keeps it all together. */
+void
+lnp_state_machine::handle_advance_pc (CORE_ADDR adjust)
+{
+ CORE_ADDR addr_adj = (((m_op_index + adjust)
+ / m_line_header->maximum_ops_per_instruction)
+ * m_line_header->minimum_instruction_length);
+ m_address += gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true);
+ m_op_index = ((m_op_index + adjust)
+ % m_line_header->maximum_ops_per_instruction);
+}
+
+void
+lnp_state_machine::handle_special_opcode (unsigned char op_code)
+{
+ unsigned char adj_opcode = op_code - m_line_header->opcode_base;
+ CORE_ADDR addr_adj = (((m_op_index
+ + (adj_opcode / m_line_header->line_range))
+ / m_line_header->maximum_ops_per_instruction)
+ * m_line_header->minimum_instruction_length);
+ m_address += gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true);
+ m_op_index = ((m_op_index + (adj_opcode / m_line_header->line_range))
+ % m_line_header->maximum_ops_per_instruction);
+
+ int line_delta = (m_line_header->line_base
+ + (adj_opcode % m_line_header->line_range));
+ advance_line (line_delta);
+ record_line (false);
+ m_discriminator = 0;
+}
-typedef struct
+void
+lnp_state_machine::handle_set_file (file_name_index file)
{
- /* The gdbarch. */
- struct gdbarch *gdbarch;
+ m_file = file;
- /* The line number header. */
- struct line_header *line_header;
+ const file_entry *fe = current_file ();
+ if (fe == NULL)
+ dwarf2_debug_line_missing_file_complaint ();
+ else if (m_record_lines_p)
+ {
+ const char *dir = fe->include_dir (m_line_header);
- /* Non-zero if we're recording lines.
- Otherwise we're building partial symtabs and are just interested in
- finding include files mentioned by the line number program. */
- int record_lines_p;
-} lnp_reader_state;
+ m_last_subfile = current_subfile;
+ m_line_has_non_zero_discriminator = m_discriminator != 0;
+ dwarf2_start_subfile (fe->name, dir);
+ }
+}
+
+void
+lnp_state_machine::handle_const_add_pc ()
+{
+ CORE_ADDR adjust
+ = (255 - m_line_header->opcode_base) / m_line_header->line_range;
+
+ CORE_ADDR addr_adj
+ = (((m_op_index + adjust)
+ / m_line_header->maximum_ops_per_instruction)
+ * m_line_header->minimum_instruction_length);
+
+ m_address += gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true);
+ m_op_index = ((m_op_index + adjust)
+ % m_line_header->maximum_ops_per_instruction);
+}
/* Ignore this record_line request. */
dwarf_record_line_1 (gdbarch, subfile, 0, address, p_record_line);
}
-/* Record the line in STATE.
- END_SEQUENCE is non-zero if we're processing the end of a sequence. */
-
-static void
-dwarf_record_line (lnp_reader_state *reader, lnp_state_machine *state,
- int end_sequence)
+void
+lnp_state_machine::record_line (bool end_sequence)
{
- const struct line_header *lh = reader->line_header;
- unsigned int line, discriminator;
- int is_stmt;
-
- line = state->line;
- is_stmt = state->is_stmt;
- discriminator = state->discriminator;
-
if (dwarf_line_debug)
{
fprintf_unfiltered (gdb_stdlog,
"Processing actual line %u: file %u,"
" address %s, is_stmt %u, discrim %u\n",
- line, state->file,
- paddress (reader->gdbarch, state->address),
- is_stmt, discriminator);
+ m_line, to_underlying (m_file),
+ paddress (m_gdbarch, m_address),
+ m_is_stmt, m_discriminator);
}
- file_entry *fe = state->current_file ();
+ file_entry *fe = current_file ();
if (fe == NULL)
dwarf2_debug_line_missing_file_complaint ();
/* For now we ignore lines not starting on an instruction boundary.
But not when processing end_sequence for compatibility with the
previous version of the code. */
- else if (state->op_index == 0 || end_sequence)
+ else if (m_op_index == 0 || end_sequence)
{
fe->included_p = 1;
- if (reader->record_lines_p && is_stmt)
+ if (m_record_lines_p && m_is_stmt)
{
- if (state->last_subfile != current_subfile || end_sequence)
+ if (m_last_subfile != current_subfile || end_sequence)
{
- dwarf_finish_line (reader->gdbarch, state->last_subfile,
- state->address, state->record_line);
+ dwarf_finish_line (m_gdbarch, m_last_subfile,
+ m_address, m_record_line_callback);
}
if (!end_sequence)
{
- if (dwarf_record_line_p (line, state->last_line,
- state->line_has_non_zero_discriminator,
- state->last_subfile))
+ if (dwarf_record_line_p (m_line, m_last_line,
+ m_line_has_non_zero_discriminator,
+ m_last_subfile))
{
- dwarf_record_line_1 (reader->gdbarch, current_subfile,
- line, state->address,
- state->record_line);
+ dwarf_record_line_1 (m_gdbarch, current_subfile,
+ m_line, m_address,
+ m_record_line_callback);
}
- state->last_subfile = current_subfile;
- state->last_line = line;
+ m_last_subfile = current_subfile;
+ m_last_line = m_line;
}
}
}
}
-/* Initialize STATE for the start of a line number program. */
-
-static void
-init_lnp_state_machine (lnp_state_machine *state,
- const lnp_reader_state *reader)
+lnp_state_machine::lnp_state_machine (gdbarch *arch, line_header *lh,
+ bool record_lines_p)
{
- memset (state, 0, sizeof (*state));
+ m_gdbarch = arch;
+ m_record_lines_p = record_lines_p;
+ m_line_header = lh;
- /* Just starting, there is no "last file". */
- state->last_file = 0;
- state->last_subfile = NULL;
+ m_record_line_callback = ::record_line;
- state->record_line = record_line;
-
- state->last_line = 0;
- state->line_has_non_zero_discriminator = 0;
-
- /* Initialize these according to the DWARF spec. */
- state->op_index = 0;
- state->file = 1;
- state->line = 1;
/* Call `gdbarch_adjust_dwarf2_line' on the initial 0 address as if there
was a line entry for it so that the backend has a chance to adjust it
and also record it in case it needs it. This is currently used by MIPS
code, cf. `mips_adjust_dwarf2_line'. */
- state->address = gdbarch_adjust_dwarf2_line (reader->gdbarch, 0, 0);
- state->is_stmt = reader->line_header->default_is_stmt;
- state->discriminator = 0;
- state->the_line_header = reader->line_header;
+ m_address = gdbarch_adjust_dwarf2_line (arch, 0, 0);
+ m_is_stmt = lh->default_is_stmt;
+ m_discriminator = 0;
}
-/* Check address and if invalid nop-out the rest of the lines in this
- sequence. */
-
-static void
-check_line_address (struct dwarf2_cu *cu, lnp_state_machine *state,
- const gdb_byte *line_ptr,
- CORE_ADDR lowpc, CORE_ADDR address)
+void
+lnp_state_machine::check_line_address (struct dwarf2_cu *cu,
+ const gdb_byte *line_ptr,
+ CORE_ADDR lowpc, CORE_ADDR address)
{
/* If address < lowpc then it's not a usable value, it's outside the
pc range of the CU. However, we restrict the test to only address
complaint (&symfile_complaints,
_(".debug_line address at offset 0x%lx is 0 [in module %s]"),
line_offset, objfile_name (objfile));
- state->record_line = noop_record_line;
- /* Note: sm.record_line is left as noop_record_line
- until we see DW_LNE_end_sequence. */
+ m_record_line_callback = noop_record_line;
+ /* Note: record_line_callback is left as noop_record_line until
+ we see DW_LNE_end_sequence. */
}
}
struct objfile *objfile = cu->objfile;
bfd *abfd = objfile->obfd;
struct gdbarch *gdbarch = get_objfile_arch (objfile);
- /* Non-zero if we're recording line info (as opposed to building partial
- symtabs). */
- int record_lines_p = !decode_for_pst_p;
- /* A collection of things we need to pass to dwarf_record_line. */
- lnp_reader_state reader_state;
+ /* True if we're recording line info (as opposed to building partial
+ symtabs and just interested in finding include files mentioned by
+ the line number program). */
+ bool record_lines_p = !decode_for_pst_p;
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
line_ptr = lh->statement_program_start;
line_end = lh->statement_program_end;
- reader_state.gdbarch = gdbarch;
- reader_state.line_header = lh;
- reader_state.record_lines_p = record_lines_p;
-
/* Read the statement sequences until there's nothing left. */
while (line_ptr < line_end)
{
- /* The DWARF line number program state machine. */
- lnp_state_machine state_machine;
- int end_sequence = 0;
-
- /* Reset the state machine at the start of each sequence. */
- init_lnp_state_machine (&state_machine, &reader_state);
+ /* The DWARF line number program state machine. Reset the state
+ machine at the start of each sequence. */
+ lnp_state_machine state_machine (gdbarch, lh, record_lines_p);
+ bool end_sequence = false;
if (record_lines_p)
{
if (op_code >= lh->opcode_base)
{
/* Special opcode. */
- unsigned char adj_opcode;
- CORE_ADDR addr_adj;
- int line_delta;
-
- adj_opcode = op_code - lh->opcode_base;
- addr_adj = (((state_machine.op_index
- + (adj_opcode / lh->line_range))
- / lh->maximum_ops_per_instruction)
- * lh->minimum_instruction_length);
- state_machine.address
- += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1);
- state_machine.op_index = ((state_machine.op_index
- + (adj_opcode / lh->line_range))
- % lh->maximum_ops_per_instruction);
- line_delta = lh->line_base + (adj_opcode % lh->line_range);
- state_machine.line += line_delta;
- if (line_delta != 0)
- state_machine.line_has_non_zero_discriminator
- = state_machine.discriminator != 0;
-
- dwarf_record_line (&reader_state, &state_machine, 0);
- state_machine.discriminator = 0;
+ state_machine.handle_special_opcode (op_code);
}
else switch (op_code)
{
switch (extended_op)
{
case DW_LNE_end_sequence:
- state_machine.record_line = record_line;
- end_sequence = 1;
+ state_machine.handle_end_sequence ();
+ end_sequence = true;
break;
case DW_LNE_set_address:
{
CORE_ADDR address
= read_address (abfd, line_ptr, cu, &bytes_read);
-
line_ptr += bytes_read;
- check_line_address (cu, &state_machine, line_ptr,
- lowpc, address);
- state_machine.op_index = 0;
- address += baseaddr;
- state_machine.address
- = gdbarch_adjust_dwarf2_line (gdbarch, address, 0);
+
+ state_machine.check_line_address (cu, line_ptr,
+ lowpc, address);
+ state_machine.handle_set_address (baseaddr, address);
}
break;
case DW_LNE_define_file:
{
const char *cur_file;
- unsigned int dir_index, mod_time, length;
+ unsigned int mod_time, length;
+ dir_index dindex;
cur_file = read_direct_string (abfd, line_ptr,
&bytes_read);
line_ptr += bytes_read;
- dir_index =
+ dindex = (dir_index)
read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
mod_time =
length =
read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
- lh->add_file_name (cur_file, dir_index, mod_time, length);
+ lh->add_file_name (cur_file, dindex, mod_time, length);
}
break;
case DW_LNE_set_discriminator:
- /* The discriminator is not interesting to the debugger;
- just ignore it. We still need to check its value though:
- if there are consecutive entries for the same
- (non-prologue) line we want to coalesce them.
- PR 17276. */
- state_machine.discriminator
- = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
- state_machine.line_has_non_zero_discriminator
- |= state_machine.discriminator != 0;
- line_ptr += bytes_read;
+ {
+ /* The discriminator is not interesting to the
+ debugger; just ignore it. We still need to
+ check its value though:
+ if there are consecutive entries for the same
+ (non-prologue) line we want to coalesce them.
+ PR 17276. */
+ unsigned int discr
+ = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ line_ptr += bytes_read;
+
+ state_machine.handle_set_discriminator (discr);
+ }
break;
default:
complaint (&symfile_complaints,
}
break;
case DW_LNS_copy:
- dwarf_record_line (&reader_state, &state_machine, 0);
- state_machine.discriminator = 0;
+ state_machine.handle_copy ();
break;
case DW_LNS_advance_pc:
{
CORE_ADDR adjust
= read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
- CORE_ADDR addr_adj;
-
- addr_adj = (((state_machine.op_index + adjust)
- / lh->maximum_ops_per_instruction)
- * lh->minimum_instruction_length);
- state_machine.address
- += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1);
- state_machine.op_index = ((state_machine.op_index + adjust)
- % lh->maximum_ops_per_instruction);
line_ptr += bytes_read;
+
+ state_machine.handle_advance_pc (adjust);
}
break;
case DW_LNS_advance_line:
{
int line_delta
= read_signed_leb128 (abfd, line_ptr, &bytes_read);
-
- state_machine.line += line_delta;
- if (line_delta != 0)
- state_machine.line_has_non_zero_discriminator
- = state_machine.discriminator != 0;
line_ptr += bytes_read;
+
+ state_machine.handle_advance_line (line_delta);
}
break;
case DW_LNS_set_file:
{
- state_machine.file = read_unsigned_leb128 (abfd, line_ptr,
- &bytes_read);
+ file_name_index file
+ = (file_name_index) read_unsigned_leb128 (abfd, line_ptr,
+ &bytes_read);
line_ptr += bytes_read;
- const file_entry *fe = state_machine.current_file ();
- if (fe == NULL)
- dwarf2_debug_line_missing_file_complaint ();
- else
- {
- if (record_lines_p)
- {
- const char *dir = fe->include_dir (lh);
-
- state_machine.last_subfile = current_subfile;
- state_machine.line_has_non_zero_discriminator
- = state_machine.discriminator != 0;
- dwarf2_start_subfile (fe->name, dir);
- }
- }
+ state_machine.handle_set_file (file);
}
break;
case DW_LNS_set_column:
line_ptr += bytes_read;
break;
case DW_LNS_negate_stmt:
- state_machine.is_stmt = (!state_machine.is_stmt);
+ state_machine.handle_negate_stmt ();
break;
case DW_LNS_set_basic_block:
break;
instruction length since special opcode 255 would have
scaled the increment. */
case DW_LNS_const_add_pc:
- {
- CORE_ADDR adjust = (255 - lh->opcode_base) / lh->line_range;
- CORE_ADDR addr_adj;
-
- addr_adj = (((state_machine.op_index + adjust)
- / lh->maximum_ops_per_instruction)
- * lh->minimum_instruction_length);
- state_machine.address
- += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1);
- state_machine.op_index = ((state_machine.op_index + adjust)
- % lh->maximum_ops_per_instruction);
- }
+ state_machine.handle_const_add_pc ();
break;
case DW_LNS_fixed_advance_pc:
{
- CORE_ADDR addr_adj;
-
- addr_adj = read_2_bytes (abfd, line_ptr);
- state_machine.address
- += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1);
- state_machine.op_index = 0;
+ CORE_ADDR addr_adj = read_2_bytes (abfd, line_ptr);
line_ptr += 2;
+
+ state_machine.handle_fixed_advance_pc (addr_adj);
}
break;
default:
/* We got a DW_LNE_end_sequence (or we ran off the end of the buffer,
in which case we still finish recording the last line). */
- dwarf_record_line (&reader_state, &state_machine, 1);
+ state_machine.record_line (true);
}
}
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);
cu);
if (attr)
{
- unsigned int file_index = DW_UNSND (attr);
+ file_name_index file_index = (file_name_index) DW_UNSND (attr);
struct file_entry *fe;
- if (cu->line_header != NULL && file_index > 0)
- fe = cu->line_header->file_name_at (file_index - 1);
+ if (cu->line_header != NULL)
+ fe = cu->line_header->file_name_at (file_index);
else
fe = NULL;
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;
message = xstrprintf (_("<unknown type in %s, CU 0x%x, DIE 0x%x>"),
objfile_name (objfile),
- cu->header.offset.sect_off,
- die->offset.sect_off);
+ to_underlying (cu->header.sect_off),
+ to_underlying (die->sect_off));
saved = (char *) obstack_copy0 (&objfile->objfile_obstack,
message, strlen (message));
xfree (message);
if (attr->form == DW_FORM_GNU_ref_alt)
{
struct dwarf2_per_cu_data *per_cu;
- sect_offset offset = dwarf2_get_ref_die_offset (attr);
+ sect_offset sect_off = dwarf2_get_ref_die_offset (attr);
- per_cu = dwarf2_find_containing_comp_unit (offset, 1, cu->objfile);
- this_type = get_die_type_at_offset (offset, per_cu);
+ per_cu = dwarf2_find_containing_comp_unit (sect_off, 1, cu->objfile);
+ this_type = get_die_type_at_offset (sect_off, per_cu);
}
else if (attr_form_is_ref (attr))
{
- sect_offset offset = dwarf2_get_ref_die_offset (attr);
+ sect_offset sect_off = dwarf2_get_ref_die_offset (attr);
- this_type = get_die_type_at_offset (offset, cu->per_cu);
+ this_type = get_die_type_at_offset (sect_off, cu->per_cu);
}
else if (attr->form == DW_FORM_ref_sig8)
{
complaint (&symfile_complaints,
_("Dwarf Error: Bad type attribute %s in DIE"
" at 0x%x [in module %s]"),
- dwarf_attr_name (attr->name), die->offset.sect_off,
+ dwarf_attr_name (attr->name), to_underlying (die->sect_off),
objfile_name (objfile));
return build_error_marker_type (cu, die);
}
{
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
prefix part in such case. See
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47510. */
-static char *
+static const char *
anonymous_struct_prefix (struct die_info *die, struct dwarf2_cu *cu)
{
struct attribute *attr;
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;
struct die_info *parent, *spec_die;
struct dwarf2_cu *spec_cu;
struct type *parent_type;
- char *retval;
+ const char *retval;
if (cu->language != language_cplus
&& cu->language != language_fortran && cu->language != language_d
{
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;
return name;
}
-static char *
+static const char *
dwarf_bool_name (unsigned mybool)
{
if (mybool)
print_spaces (indent, f);
fprintf_unfiltered (f, "Die: %s (abbrev %d, offset 0x%x)\n",
- dwarf_tag_name (die->tag), die->abbrev, die->offset.sect_off);
+ dwarf_tag_name (die->tag), die->abbrev,
+ to_underlying (die->sect_off));
if (die->parent != NULL)
{
print_spaces (indent, f);
fprintf_unfiltered (f, " parent at offset: 0x%x\n",
- die->parent->offset.sect_off);
+ to_underlying (die->parent->sect_off));
}
print_spaces (indent, f);
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);
{
void **slot;
- slot = htab_find_slot_with_hash (cu->die_hash, die, die->offset.sect_off,
+ slot = htab_find_slot_with_hash (cu->die_hash, die,
+ to_underlying (die->sect_off),
INSERT);
*slot = die;
static sect_offset
dwarf2_get_ref_die_offset (const struct attribute *attr)
{
- sect_offset retval = { DW_UNSND (attr) };
-
if (attr_form_is_ref (attr))
- return retval;
+ return (sect_offset) DW_UNSND (attr);
- retval.sect_off = 0;
complaint (&symfile_complaints,
_("unsupported die ref attribute form: '%s'"),
dwarf_form_name (attr->form));
- return retval;
+ return {};
}
/* Return the constant value held by ATTR. Return DEFAULT_VALUE if
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
Returns NULL if OFFSET is invalid. */
static struct die_info *
-follow_die_offset (sect_offset offset, int offset_in_dwz,
+follow_die_offset (sect_offset sect_off, int offset_in_dwz,
struct dwarf2_cu **ref_cu)
{
struct die_info temp_die;
/* .debug_types CUs cannot reference anything outside their CU.
If they need to, they have to reference a signatured type via
DW_FORM_ref_sig8. */
- if (! offset_in_cu_p (&cu->header, offset))
+ if (!offset_in_cu_p (&cu->header, sect_off))
return NULL;
}
else if (offset_in_dwz != cu->per_cu->is_dwz
- || ! offset_in_cu_p (&cu->header, offset))
+ || !offset_in_cu_p (&cu->header, sect_off))
{
struct dwarf2_per_cu_data *per_cu;
- per_cu = dwarf2_find_containing_comp_unit (offset, offset_in_dwz,
+ per_cu = dwarf2_find_containing_comp_unit (sect_off, offset_in_dwz,
cu->objfile);
/* If necessary, add it to the queue and load its DIEs. */
}
*ref_cu = target_cu;
- temp_die.offset = offset;
+ temp_die.sect_off = sect_off;
return (struct die_info *) htab_find_with_hash (target_cu->die_hash,
- &temp_die, offset.sect_off);
+ &temp_die,
+ to_underlying (sect_off));
}
/* Follow reference attribute ATTR of SRC_DIE.
follow_die_ref (struct die_info *src_die, const struct attribute *attr,
struct dwarf2_cu **ref_cu)
{
- sect_offset offset = dwarf2_get_ref_die_offset (attr);
+ sect_offset sect_off = dwarf2_get_ref_die_offset (attr);
struct dwarf2_cu *cu = *ref_cu;
struct die_info *die;
- die = follow_die_offset (offset,
+ die = follow_die_offset (sect_off,
(attr->form == DW_FORM_GNU_ref_alt
|| cu->per_cu->is_dwz),
ref_cu);
if (!die)
error (_("Dwarf Error: Cannot find DIE at 0x%x referenced from DIE "
"at 0x%x [in module %s]"),
- offset.sect_off, src_die->offset.sect_off,
+ to_underlying (sect_off), to_underlying (src_die->sect_off),
objfile_name (cu->objfile));
return die;
}
-/* Return DWARF block referenced by DW_AT_location of DIE at OFFSET at PER_CU.
+/* Return DWARF block referenced by DW_AT_location of DIE at SECT_OFF at PER_CU.
Returned value is intended for DW_OP_call*. Returned
dwarf2_locexpr_baton->data has lifetime of PER_CU->OBJFILE. */
struct dwarf2_locexpr_baton
-dwarf2_fetch_die_loc_sect_off (sect_offset offset,
+dwarf2_fetch_die_loc_sect_off (sect_offset sect_off,
struct dwarf2_per_cu_data *per_cu,
CORE_ADDR (*get_frame_pc) (void *baton),
void *baton)
/* We shouldn't get here for a dummy CU, but don't crash on the user.
Instead just throw an error, not much else we can do. */
error (_("Dwarf Error: Dummy CU at 0x%x referenced in module %s"),
- offset.sect_off, objfile_name (per_cu->objfile));
+ to_underlying (sect_off), objfile_name (per_cu->objfile));
}
- die = follow_die_offset (offset, per_cu->is_dwz, &cu);
+ die = follow_die_offset (sect_off, per_cu->is_dwz, &cu);
if (!die)
error (_("Dwarf Error: Cannot find DIE at 0x%x referenced in module %s"),
- offset.sect_off, objfile_name (per_cu->objfile));
+ to_underlying (sect_off), objfile_name (per_cu->objfile));
attr = dwarf2_attr (die, DW_AT_location, cu);
if (!attr)
if (!attr_form_is_block (attr))
error (_("Dwarf Error: DIE at 0x%x referenced in module %s "
"is neither DW_FORM_block* nor DW_FORM_exprloc"),
- offset.sect_off, objfile_name (per_cu->objfile));
+ to_underlying (sect_off), objfile_name (per_cu->objfile));
retval.data = DW_BLOCK (attr)->data;
retval.size = DW_BLOCK (attr)->size;
CORE_ADDR (*get_frame_pc) (void *baton),
void *baton)
{
- sect_offset offset = { per_cu->offset.sect_off + offset_in_cu.cu_off };
+ sect_offset sect_off = per_cu->sect_off + to_underlying (offset_in_cu);
- return dwarf2_fetch_die_loc_sect_off (offset, per_cu, get_frame_pc, baton);
+ return dwarf2_fetch_die_loc_sect_off (sect_off, per_cu, get_frame_pc, baton);
}
/* Write a constant of a given type as target-ordered bytes into
does not have a DW_AT_const_value, return NULL. */
const gdb_byte *
-dwarf2_fetch_constant_bytes (sect_offset offset,
+dwarf2_fetch_constant_bytes (sect_offset sect_off,
struct dwarf2_per_cu_data *per_cu,
struct obstack *obstack,
LONGEST *len)
/* We shouldn't get here for a dummy CU, but don't crash on the user.
Instead just throw an error, not much else we can do. */
error (_("Dwarf Error: Dummy CU at 0x%x referenced in module %s"),
- offset.sect_off, objfile_name (per_cu->objfile));
+ to_underlying (sect_off), objfile_name (per_cu->objfile));
}
- die = follow_die_offset (offset, per_cu->is_dwz, &cu);
+ die = follow_die_offset (sect_off, per_cu->is_dwz, &cu);
if (!die)
error (_("Dwarf Error: Cannot find DIE at 0x%x referenced in module %s"),
- offset.sect_off, objfile_name (per_cu->objfile));
+ to_underlying (sect_off), objfile_name (per_cu->objfile));
attr = dwarf2_attr (die, DW_AT_const_value, cu);
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);
valid type for this die is found. */
struct type *
-dwarf2_fetch_die_type_sect_off (sect_offset offset,
+dwarf2_fetch_die_type_sect_off (sect_offset sect_off,
struct dwarf2_per_cu_data *per_cu)
{
struct dwarf2_cu *cu;
if (!cu)
return NULL;
- die = follow_die_offset (offset, per_cu->is_dwz, &cu);
+ die = follow_die_offset (sect_off, per_cu->is_dwz, &cu);
if (!die)
return NULL;
dwarf2_get_die_type (cu_offset die_offset,
struct dwarf2_per_cu_data *per_cu)
{
- sect_offset die_offset_sect;
-
dw2_setup (per_cu->objfile);
- die_offset_sect.sect_off = per_cu->offset.sect_off + die_offset.cu_off;
+ sect_offset die_offset_sect = per_cu->sect_off + to_underlying (die_offset);
return get_die_type_at_offset (die_offset_sect, per_cu);
}
sig_cu = sig_type->per_cu.cu;
gdb_assert (sig_cu != NULL);
- gdb_assert (sig_type->type_offset_in_section.sect_off != 0);
- temp_die.offset = sig_type->type_offset_in_section;
+ gdb_assert (to_underlying (sig_type->type_offset_in_section) != 0);
+ temp_die.sect_off = sig_type->type_offset_in_section;
die = (struct die_info *) htab_find_with_hash (sig_cu->die_hash, &temp_die,
- temp_die.offset.sect_off);
+ to_underlying (temp_die.sect_off));
if (die)
{
/* For .gdb_index version 7 keep track of included TUs.
{
error (_("Dwarf Error: Cannot find signatured DIE %s referenced"
" from DIE at 0x%x [in module %s]"),
- hex_string (signature), src_die->offset.sect_off,
+ hex_string (signature), to_underlying (src_die->sect_off),
objfile_name ((*ref_cu)->objfile));
}
dump_die_for_error (src_die);
error (_("Dwarf Error: Problem reading signatured DIE %s referenced"
" from DIE at 0x%x [in module %s]"),
- hex_string (signature), src_die->offset.sect_off,
+ hex_string (signature), to_underlying (src_die->sect_off),
objfile_name ((*ref_cu)->objfile));
}
complaint (&symfile_complaints,
_("Dwarf Error: Cannot find signatured DIE %s referenced"
" from DIE at 0x%x [in module %s]"),
- hex_string (signature), die->offset.sect_off,
+ hex_string (signature), to_underlying (die->sect_off),
objfile_name (dwarf2_per_objfile->objfile));
return build_error_marker_type (cu, die);
}
complaint (&symfile_complaints,
_("Dwarf Error: Cannot build signatured type %s"
" referenced from DIE at 0x%x [in module %s]"),
- hex_string (signature), die->offset.sect_off,
+ hex_string (signature), to_underlying (die->sect_off),
objfile_name (dwarf2_per_objfile->objfile));
type = build_error_marker_type (cu, die);
}
complaint (&symfile_complaints,
_("Dwarf Error: Problem reading signatured DIE %s referenced"
" from DIE at 0x%x [in module %s]"),
- hex_string (signature), die->offset.sect_off,
+ hex_string (signature), to_underlying (die->sect_off),
objfile_name (dwarf2_per_objfile->objfile));
type = build_error_marker_type (cu, die);
}
complaint (&symfile_complaints,
_("Dwarf Error: DW_AT_signature has bad form %s in DIE"
" at 0x%x [in module %s]"),
- dwarf_form_name (attr->form), die->offset.sect_off,
+ dwarf_form_name (attr->form), to_underlying (die->sect_off),
objfile_name (dwarf2_per_objfile->objfile));
return build_error_marker_type (cu, die);
}
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;
if (per_cu->cu)
return &per_cu->cu->header;
- info_ptr = per_cu->section->buffer + per_cu->offset.sect_off;
+ info_ptr = per_cu->section->buffer + to_underlying (per_cu->sect_off);
memset (cu_headerp, 0, sizeof (*cu_headerp));
read_comp_unit_head (cu_headerp, info_ptr, per_cu->section,
the DIE at OFFSET. Raises an error on failure. */
static struct dwarf2_per_cu_data *
-dwarf2_find_containing_comp_unit (sect_offset offset,
+dwarf2_find_containing_comp_unit (sect_offset sect_off,
unsigned int offset_in_dwz,
struct objfile *objfile)
{
int mid = low + (high - low) / 2;
mid_cu = dwarf2_per_objfile->all_comp_units[mid];
- cu_off = &mid_cu->offset;
+ cu_off = &mid_cu->sect_off;
if (mid_cu->is_dwz > offset_in_dwz
- || (mid_cu->is_dwz == offset_in_dwz
- && cu_off->sect_off >= offset.sect_off))
+ || (mid_cu->is_dwz == offset_in_dwz && *cu_off >= sect_off))
high = mid;
else
low = mid + 1;
}
gdb_assert (low == high);
this_cu = dwarf2_per_objfile->all_comp_units[low];
- cu_off = &this_cu->offset;
- if (this_cu->is_dwz != offset_in_dwz || cu_off->sect_off > offset.sect_off)
+ cu_off = &this_cu->sect_off;
+ if (this_cu->is_dwz != offset_in_dwz || *cu_off > sect_off)
{
if (low == 0 || this_cu->is_dwz != offset_in_dwz)
error (_("Dwarf Error: could not find partial DIE containing "
- "offset 0x%lx [in module %s]"),
- (long) offset.sect_off, bfd_get_filename (objfile->obfd));
+ "offset 0x%x [in module %s]"),
+ to_underlying (sect_off), bfd_get_filename (objfile->obfd));
- gdb_assert (dwarf2_per_objfile->all_comp_units[low-1]->offset.sect_off
- <= offset.sect_off);
+ gdb_assert (dwarf2_per_objfile->all_comp_units[low-1]->sect_off
+ <= sect_off);
return dwarf2_per_objfile->all_comp_units[low-1];
}
else
{
this_cu = dwarf2_per_objfile->all_comp_units[low];
if (low == dwarf2_per_objfile->n_comp_units - 1
- && offset.sect_off >= this_cu->offset.sect_off + this_cu->length)
- error (_("invalid dwarf2 offset %u"), offset.sect_off);
- gdb_assert (offset.sect_off < this_cu->offset.sect_off + this_cu->length);
+ && sect_off >= this_cu->sect_off + this_cu->length)
+ error (_("invalid dwarf2 offset %u"), to_underlying (sect_off));
+ gdb_assert (sect_off < this_cu->sect_off + this_cu->length);
return this_cu;
}
}
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.
struct dwarf2_per_cu_offset_and_type
{
const struct dwarf2_per_cu_data *per_cu;
- sect_offset offset;
+ sect_offset sect_off;
struct type *type;
};
const struct dwarf2_per_cu_offset_and_type *ofs
= (const struct dwarf2_per_cu_offset_and_type *) item;
- return (uintptr_t) ofs->per_cu + ofs->offset.sect_off;
+ return (uintptr_t) ofs->per_cu + to_underlying (ofs->sect_off);
}
/* Equality function for a dwarf2_per_cu_offset_and_type. */
= (const struct dwarf2_per_cu_offset_and_type *) item_rhs;
return (ofs_lhs->per_cu == ofs_rhs->per_cu
- && ofs_lhs->offset.sect_off == ofs_rhs->offset.sect_off);
+ && ofs_lhs->sect_off == ofs_rhs->sect_off);
}
/* Set the type associated with DIE to TYPE. Save it in CU's hash
else if (attr != NULL)
{
complaint (&symfile_complaints,
- _("DW_AT_allocated has the wrong form (%s) at DIE 0x%x"),
- (attr != NULL ? dwarf_form_name (attr->form) : "n/a"),
- die->offset.sect_off);
+ _("DW_AT_allocated has the wrong form (%s) at DIE 0x%x"),
+ (attr != NULL ? dwarf_form_name (attr->form) : "n/a"),
+ to_underlying (die->sect_off));
}
/* Read DW_AT_associated and set in type. */
else if (attr != NULL)
{
complaint (&symfile_complaints,
- _("DW_AT_associated has the wrong form (%s) at DIE 0x%x"),
- (attr != NULL ? dwarf_form_name (attr->form) : "n/a"),
- die->offset.sect_off);
+ _("DW_AT_associated has the wrong form (%s) at DIE 0x%x"),
+ (attr != NULL ? dwarf_form_name (attr->form) : "n/a"),
+ to_underlying (die->sect_off));
}
/* Read DW_AT_data_location and set in type. */
}
ofs.per_cu = cu->per_cu;
- ofs.offset = die->offset;
+ ofs.sect_off = die->sect_off;
ofs.type = type;
slot = (struct dwarf2_per_cu_offset_and_type **)
htab_find_slot (dwarf2_per_objfile->die_type_hash, &ofs, INSERT);
if (*slot)
complaint (&symfile_complaints,
_("A problem internal to GDB: DIE 0x%x has type already set"),
- die->offset.sect_off);
+ to_underlying (die->sect_off));
*slot = XOBNEW (&objfile->objfile_obstack,
struct dwarf2_per_cu_offset_and_type);
**slot = ofs;
return type;
}
-/* Look up the type for the die at OFFSET in PER_CU in die_type_hash,
+/* Look up the type for the die at SECT_OFF in PER_CU in die_type_hash,
or return NULL if the die does not have a saved type. */
static struct type *
-get_die_type_at_offset (sect_offset offset,
+get_die_type_at_offset (sect_offset sect_off,
struct dwarf2_per_cu_data *per_cu)
{
struct dwarf2_per_cu_offset_and_type *slot, ofs;
return NULL;
ofs.per_cu = per_cu;
- ofs.offset = offset;
+ ofs.sect_off = sect_off;
slot = ((struct dwarf2_per_cu_offset_and_type *)
htab_find (dwarf2_per_objfile->die_type_hash, &ofs));
if (slot)
static struct type *
get_die_type (struct die_info *die, struct dwarf2_cu *cu)
{
- return get_die_type_at_offset (die->offset, cu->per_cu);
+ return get_die_type_at_offset (die->sect_off, cu->per_cu);
}
/* Add a dependence relationship from CU to REF_PER_CU. */
const struct partial_die_info *part_die
= (const struct partial_die_info *) item;
- return part_die->offset.sect_off;
+ return to_underlying (part_die->sect_off);
}
/* Trivial comparison function for partial_die_info structures: two DIEs
const struct partial_die_info *part_die_rhs
= (const struct partial_die_info *) item_rhs;
- return part_die_lhs->offset.sect_off == part_die_rhs->offset.sect_off;
+ return part_die_lhs->sect_off == part_die_rhs->sect_off;
}
static struct cmd_list_element *set_dwarf_cmdlist;
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
/* 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;
-
- symtab->size *= 2;
- symtab->data = XCNEWVEC (struct symtab_index_entry *, symtab->size);
+ auto old_entries = std::move (symtab->data);
- 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];
- }
- }
+ symtab->data.clear ();
+ symtab->data.resize (old_entries.size () * 2);
- 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);
+ }
+};
+
+/* 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 obstack OUTPUT, with
- constant pool entries going into the obstack CPOOL. */
+/* 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,
- 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);
- store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE,
- entry->per_cu.offset.sect_off);
- obstack_grow (info->types_list, val, 8);
- store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE,
- entry->type_offset_in_tu.cu_off);
- 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;
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);
}
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);
+ error (_("Can't open `%s' for writing"), filename.c_str ());
- obstack_init (&cu_list);
- make_cleanup_obstack_free (&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);
- obstack_init (&types_cu_list);
- make_cleanup_obstack_free (&types_cu_list);
-
- 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,
- per_cu->offset.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)
{
&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
}