#include "filestuff.h"
#include "build-id.h"
#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 "common/hash_enum.h"
+#include "filename-seen-cache.h"
+#include "producer.h"
#include <fcntl.h>
#include <sys/types.h>
#include <algorithm>
+#include <unordered_set>
+#include <unordered_map>
+#include "selftest.h"
+#include <cmath>
+#include <set>
+#include <forward_list>
typedef struct symbol *symbolp;
DEF_VEC_P (symbolp);
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;
+};
+
+/* Base class containing bits shared by both .gdb_index and
+ .debug_name indexes. */
+
+struct mapped_index_base
+{
+ /* 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;
+
+ /* Return the number of names in the symbol table. */
+ virtual size_t symbol_name_count () const = 0;
+
+ /* Get the name of the symbol at IDX in the symbol table. */
+ virtual const char *symbol_name_at (offset_type idx) const = 0;
+
+ /* Return whether the name at IDX in the symbol table should be
+ ignored. */
+ virtual bool symbol_name_slot_invalid (offset_type idx) const
+ {
+ return false;
+ }
+
+ /* 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;
+
+ /* Prevent deleting/destroying via a base class pointer. */
+protected:
+ ~mapped_index_base() = default;
+};
+
/* A description of the mapped index. The file format is described in
a comment by the code that writes the index. */
-struct mapped_index
+struct mapped_index : public mapped_index_base
{
+ /* A slot/bucket in the symbol table hash. */
+ struct symbol_table_slot
+ {
+ const offset_type name;
+ const offset_type vec;
+ };
+
/* Index data format version. */
int version;
/* The total length of the buffer. */
off_t total_size;
- /* A pointer to the address table data. */
- const gdb_byte *address_table;
-
- /* Size of the address table data in bytes. */
- offset_type address_table_size;
+ /* The address table data. */
+ gdb::array_view<const gdb_byte> address_table;
/* The symbol table, implemented as a hash table. */
- const offset_type *symbol_table;
-
- /* Size in slots, each slot is 2 offset_types. */
- offset_type symbol_table_slots;
+ gdb::array_view<symbol_table_slot> symbol_table;
/* A pointer to the constant pool. */
const char *constant_pool;
+
+ bool symbol_name_slot_invalid (offset_type idx) const override
+ {
+ const auto &bucket = this->symbol_table[idx];
+ return bucket.name == 0 && bucket.vec;
+ }
+
+ /* 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 override
+ { return this->constant_pool + MAYBE_SWAP (this->symbol_table[idx].name); }
+
+ size_t symbol_name_count () const override
+ { return this->symbol_table.size (); }
+};
+
+/* A description of the mapped .debug_names.
+ Uninitialized map has CU_COUNT 0. */
+struct mapped_debug_names : public mapped_index_base
+{
+ bfd_endian dwarf5_byte_order;
+ bool dwarf5_is_dwarf64;
+ bool augmentation_is_gdb;
+ uint8_t offset_size;
+ uint32_t cu_count = 0;
+ uint32_t tu_count, bucket_count, name_count;
+ const gdb_byte *cu_table_reordered, *tu_table_reordered;
+ const uint32_t *bucket_table_reordered, *hash_table_reordered;
+ const gdb_byte *name_table_string_offs_reordered;
+ const gdb_byte *name_table_entry_offs_reordered;
+ const gdb_byte *entry_pool;
+
+ struct index_val
+ {
+ ULONGEST dwarf_tag;
+ struct attr
+ {
+ /* Attribute name DW_IDX_*. */
+ ULONGEST dw_idx;
+
+ /* Attribute form DW_FORM_*. */
+ ULONGEST form;
+
+ /* Value if FORM is DW_FORM_implicit_const. */
+ LONGEST implicit_const;
+ };
+ std::vector<attr> attr_vec;
+ };
+
+ std::unordered_map<ULONGEST, index_val> abbrev_map;
+
+ const char *namei_to_name (uint32_t namei) const;
+
+ /* Implementation of the mapped_index_base virtual interface, for
+ the name_components cache. */
+
+ const char *symbol_name_at (offset_type idx) const override
+ { return namei_to_name (idx); }
+
+ size_t symbol_name_count () const override
+ { return this->name_count; }
};
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 macinfo;
- struct dwarf2_section_info macro;
- struct dwarf2_section_info str;
- struct dwarf2_section_info ranges;
- 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 {};
+ dwarf2_section_info debug_names {};
+ dwarf2_section_info debug_aranges {};
+
+ 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;
+
+ /* The mapped index, or NULL if .debug_names is missing or not being used. */
+ std::unique_ptr<mapped_debug_names> debug_names_table;
/* 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;
{ ".debug_abbrev", ".zdebug_abbrev" },
{ ".debug_line", ".zdebug_line" },
{ ".debug_loc", ".zdebug_loc" },
+ { ".debug_loclists", ".zdebug_loclists" },
{ ".debug_macinfo", ".zdebug_macinfo" },
{ ".debug_macro", ".zdebug_macro" },
{ ".debug_str", ".zdebug_str" },
+ { ".debug_line_str", ".zdebug_line_str" },
{ ".debug_ranges", ".zdebug_ranges" },
+ { ".debug_rnglists", ".zdebug_rnglists" },
{ ".debug_types", ".zdebug_types" },
{ ".debug_addr", ".zdebug_addr" },
{ ".debug_frame", ".zdebug_frame" },
{ ".eh_frame", NULL },
{ ".gdb_index", ".zgdb_index" },
+ { ".debug_names", ".zdebug_names" },
+ { ".debug_aranges", ".zdebug_aranges" },
23
};
struct dwarf2_section_names info_dwo;
struct dwarf2_section_names line_dwo;
struct dwarf2_section_names loc_dwo;
+ struct dwarf2_section_names loclists_dwo;
struct dwarf2_section_names macinfo_dwo;
struct dwarf2_section_names macro_dwo;
struct dwarf2_section_names str_dwo;
{ ".debug_info.dwo", ".zdebug_info.dwo" },
{ ".debug_line.dwo", ".zdebug_line.dwo" },
{ ".debug_loc.dwo", ".zdebug_loc.dwo" },
+ { ".debug_loclists.dwo", ".zdebug_loclists.dwo" },
{ ".debug_macinfo.dwo", ".zdebug_macinfo.dwo" },
{ ".debug_macro.dwo", ".zdebug_macro.dwo" },
{ ".debug_str.dwo", ".zdebug_str.dwo" },
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;
/* Size of the length field; either 4 or 12. */
unsigned int initial_length_size;
+ enum dwarf_unit_type unit_type;
+
/* 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_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). */
+ short dwarf_version;
+
/* Flag indicating this compilation unit will be read in before
any of the current compilation units are processed. */
unsigned int queued : 1;
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
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;
/* 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. */
struct dwarf2_section_info line;
struct dwarf2_section_info macro;
struct dwarf2_section_info gdb_index;
+ struct dwarf2_section_info debug_names;
/* The dwz's BFD. */
bfd *dwz_bfd;
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
{
- const char *name;
- unsigned int dir_index;
- unsigned int mod_time;
- unsigned int length;
- /* Non-zero if referenced by the Line Number Program. */
- int included_p;
+ file_entry () = default;
+
+ file_entry (const char *name_, dir_index d_index_,
+ unsigned int mod_time_, unsigned int length_)
+ : name (name_),
+ d_index (d_index_),
+ mod_time (mod_time_),
+ length (length_)
+ {}
+
+ /* 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
+ owned by debug_line_buffer. */
+ const char *name {};
+
+ /* The directory index (1-based). */
+ dir_index d_index {};
+
+ unsigned int mod_time {};
+
+ unsigned int length {};
+
+ /* True if referenced by the Line Number Program. */
+ bool included_p {};
+
/* The associated symbol table, if any. */
- struct symtab *symtab;
+ struct symtab *symtab {};
};
/* The line number information for a compilation unit (found in the
which contains the following information. */
struct line_header
{
+ line_header ()
+ : offset_in_dwz {}
+ {}
+
+ /* Add an entry to the include directory table. */
+ void add_include_dir (const char *include_dir);
+
+ /* Add an entry to the file name table. */
+ void add_file_name (const char *name, dir_index d_index,
+ unsigned int mod_time, unsigned int length);
+
+ /* Return the include dir at INDEX (1-based). Returns NULL if INDEX
+ is out of bounds. */
+ const char *include_dir_at (dir_index index) const
+ {
+ /* 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[vec_index];
+ }
+
+ /* Return the file name at INDEX (1-based). Returns NULL if INDEX
+ is out of bounds. */
+ file_entry *file_name_at (file_name_index index)
+ {
+ /* 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[vec_index];
+ }
+
+ /* Const version of the above. */
+ const file_entry *file_name_at (unsigned int index) const
+ {
+ if (index >= file_names.size ())
+ return NULL;
+ return &file_names[index];
+ }
+
/* 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;
-
- unsigned int total_length;
- unsigned short version;
- unsigned int header_length;
- unsigned char minimum_instruction_length;
- unsigned char maximum_ops_per_instruction;
- unsigned char default_is_stmt;
- int line_base;
- unsigned char line_range;
- unsigned char opcode_base;
+ unsigned offset_in_dwz : 1; /* Can't initialize bitfields in-class. */
+
+ unsigned int total_length {};
+ unsigned short version {};
+ unsigned int header_length {};
+ unsigned char minimum_instruction_length {};
+ unsigned char maximum_ops_per_instruction {};
+ unsigned char default_is_stmt {};
+ int line_base {};
+ unsigned char line_range {};
+ unsigned char opcode_base {};
/* standard_opcode_lengths[i] is the number of operands for the
standard opcode whose value is i. This means that
standard_opcode_lengths[0] is unused, and the last meaningful
element is standard_opcode_lengths[opcode_base - 1]. */
- unsigned char *standard_opcode_lengths;
+ std::unique_ptr<unsigned char[]> standard_opcode_lengths;
- /* The include_directories table. NOTE! These strings are not
- allocated with xmalloc; instead, they are pointers into
- debug_line_buffer. If you try to free them, `free' will get
- indigestion. */
- unsigned int num_include_dirs, include_dirs_size;
- const char **include_dirs;
+ /* The include_directories table. Note these are observing
+ pointers. The memory is owned by debug_line_buffer. */
+ std::vector<const char *> include_dirs;
- /* The file_names table. NOTE! These strings are not allocated
- with xmalloc; instead, they are pointers into debug_line_buffer.
- Don't try to free them directly. */
- unsigned int num_file_names, file_names_size;
- struct file_entry *file_names;
+ /* The file_names table. */
+ std::vector<file_entry> file_names;
/* The start and end of the statement program following this
header. These point into dwarf2_per_objfile->line_buffer. */
- const gdb_byte *statement_program_start, *statement_program_end;
+ const gdb_byte *statement_program_start {}, *statement_program_end {};
};
+typedef std::unique_ptr<line_header> line_header_up;
+
+const char *
+file_entry::include_dir (const line_header *lh) const
+{
+ return lh->include_dir_at (d_index);
+}
+
/* When we construct a partial symbol table entry we only
need this much information. */
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. */
{
ENUM_BITFIELD(dwarf_attribute) name : 16;
ENUM_BITFIELD(dwarf_form) form : 16;
+
+ /* It is valid only if FORM is DW_FORM_implicit_const. */
+ LONGEST implicit_const;
};
/* Size of abbrev_table.abbrev_hash_table. */
{
/* 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 *,
const struct comp_unit_head *,
unsigned int *);
-static const char *read_indirect_string_from_dwz (struct dwz_file *, LONGEST);
+static const char *read_indirect_line_string (bfd *, const gdb_byte *,
+ const struct comp_unit_head *,
+ unsigned int *);
+
+static const char *read_indirect_string_at_offset (bfd *abfd,
+ LONGEST str_offset);
-static ULONGEST read_unsigned_leb128 (bfd *, const gdb_byte *, unsigned int *);
+static const char *read_indirect_string_from_dwz (struct dwz_file *, LONGEST);
static LONGEST read_signed_leb128 (bfd *, const gdb_byte *, unsigned int *);
static struct die_info *die_specification (struct die_info *die,
struct dwarf2_cu **);
-static void free_line_header (struct line_header *lh);
-
-static struct line_header *dwarf_decode_line_header (unsigned int offset,
- struct dwarf2_cu *cu);
+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 *,
struct dwarf2_cu *, struct partial_symtab *,
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 void process_queue (void);
-static void find_file_and_directory (struct die_info *die,
- struct dwarf2_cu *cu,
- const char **name, const char **comp_dir);
+/* The return type of find_file_and_directory. Note, the enclosed
+ string pointers are only valid while this object is valid. */
+
+struct file_and_directory
+{
+ /* The filename. This is never NULL. */
+ const char *name;
+
+ /* The compilation directory. NULL if not known. If we needed to
+ compute a new string, this points to COMP_DIR_STORAGE, otherwise,
+ points directly to the DW_AT_comp_dir string attribute owned by
+ the obstack that owns the DIE. */
+ const char *comp_dir;
+
+ /* If we needed to build a new string for comp_dir, this is what
+ owns the storage. */
+ std::string comp_dir_storage;
+};
+
+static file_and_directory find_file_and_directory (struct die_info *die,
+ struct dwarf2_cu *cu);
static char *file_full_name (int file, struct line_header *lh,
const char *comp_dir);
+/* Expected enum dwarf_unit_type for read_comp_unit_head. */
+enum class rcuh_kind { COMPILE, TYPE };
+
static const gdb_byte *read_and_check_comp_unit_head
(struct comp_unit_head *header,
struct dwarf2_section_info *section,
struct dwarf2_section_info *abbrev_section, const gdb_byte *info_ptr,
- int is_debug_types_section);
+ rcuh_kind section_kind);
static void init_cutu_and_read_dies
(struct dwarf2_per_cu_data *this_cu, struct abbrev_table *abbrev_table,
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"
+#define INDEX4_SUFFIX ".gdb-index"
+#define INDEX5_SUFFIX ".debug_names"
+#define DEBUG_STR_SUFFIX ".debug_str"
+
+/* 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.
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))
+ {
+ this->info.s.section = sectp;
+ this->info.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names.abbrev))
+ {
+ this->abbrev.s.section = sectp;
+ this->abbrev.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names.line))
+ {
+ this->line.s.section = sectp;
+ this->line.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names.loc))
{
- dwarf2_per_objfile->info.s.section = sectp;
- dwarf2_per_objfile->info.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->abbrev))
+ else if (section_is_p (sectp->name, &names.loclists))
{
- dwarf2_per_objfile->abbrev.s.section = sectp;
- dwarf2_per_objfile->abbrev.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->line))
+ else if (section_is_p (sectp->name, &names.macinfo))
{
- dwarf2_per_objfile->line.s.section = sectp;
- dwarf2_per_objfile->line.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->loc))
+ else if (section_is_p (sectp->name, &names.macro))
{
- dwarf2_per_objfile->loc.s.section = sectp;
- dwarf2_per_objfile->loc.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->macinfo))
+ else if (section_is_p (sectp->name, &names.str))
{
- dwarf2_per_objfile->macinfo.s.section = sectp;
- dwarf2_per_objfile->macinfo.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->macro))
+ else if (section_is_p (sectp->name, &names.line_str))
{
- dwarf2_per_objfile->macro.s.section = sectp;
- dwarf2_per_objfile->macro.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->str))
+ else if (section_is_p (sectp->name, &names.addr))
{
- dwarf2_per_objfile->str.s.section = sectp;
- dwarf2_per_objfile->str.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->addr))
+ else if (section_is_p (sectp->name, &names.frame))
{
- dwarf2_per_objfile->addr.s.section = sectp;
- dwarf2_per_objfile->addr.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->frame))
+ else if (section_is_p (sectp->name, &names.eh_frame))
{
- dwarf2_per_objfile->frame.s.section = sectp;
- dwarf2_per_objfile->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->eh_frame))
+ else if (section_is_p (sectp->name, &names.ranges))
{
- dwarf2_per_objfile->eh_frame.s.section = sectp;
- dwarf2_per_objfile->eh_frame.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->ranges))
+ else if (section_is_p (sectp->name, &names.rnglists))
{
- dwarf2_per_objfile->ranges.s.section = sectp;
- dwarf2_per_objfile->ranges.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))
+ {
+ this->gdb_index.s.section = sectp;
+ this->gdb_index.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names.debug_names))
+ {
+ this->debug_names.s.section = sectp;
+ this->debug_names.size = bfd_get_section_size (sectp);
+ }
+ else if (section_is_p (sectp->name, &names.debug_aranges))
{
- dwarf2_per_objfile->gdb_index.s.section = sectp;
- dwarf2_per_objfile->gdb_index.size = bfd_get_section_size (sectp);
+ this->debug_aranges.s.section = sectp;
+ this->debug_aranges.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,
dwz_file->gdb_index.s.section = sectp;
dwz_file->gdb_index.size = bfd_get_section_size (sectp);
}
+ else if (section_is_p (sectp->name, &dwarf2_elf_names.debug_names))
+ {
+ dwz_file->debug_names.s.section = sectp;
+ dwz_file->debug_names.size = bfd_get_section_size (sectp);
+ }
}
/* Open the separate '.dwz' debug file, if needed. Return NULL if
static struct dwz_file *
dwarf2_get_dwz_file (void)
{
- bfd *dwz_bfd;
- 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));
- char *rel;
+ gdb::unique_xmalloc_ptr<char> abs
+ = gdb_realpath (objfile_name (dwarf2_per_objfile->objfile));
- make_cleanup (xfree, abs);
- abs = ldirname (abs);
- make_cleanup (xfree, abs);
-
- rel = concat (abs, SLASH_STRING, filename, (char *) NULL);
- make_cleanup (xfree, rel);
- filename = rel;
+ abs_storage = ldirname (abs.get ()) + SLASH_STRING + filename;
+ filename = abs_storage.c_str ();
}
/* First try the file name given in the section. If that doesn't
work, try to use the build-id instead. */
- dwz_bfd = gdb_bfd_open (filename, gnutarget, -1);
+ gdb_bfd_ref_ptr dwz_bfd (gdb_bfd_open (filename, gnutarget, -1));
if (dwz_bfd != NULL)
{
- if (!build_id_verify (dwz_bfd, buildid_len, buildid))
- {
- gdb_bfd_unref (dwz_bfd);
- dwz_bfd = NULL;
- }
+ if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid))
+ dwz_bfd.release ();
}
if (dwz_bfd == NULL)
result = OBSTACK_ZALLOC (&dwarf2_per_objfile->objfile->objfile_obstack,
struct dwz_file);
- result->dwz_bfd = dwz_bfd;
-
- bfd_map_over_sections (dwz_bfd, locate_dwz_sections, result);
+ result->dwz_bfd = dwz_bfd.release ();
- do_cleanups (cleanup);
+ bfd_map_over_sections (result->dwz_bfd, locate_dwz_sections, result);
- gdb_bfd_record_inclusion (dwarf2_per_objfile->objfile->obfd, dwz_bfd);
+ 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);
return dwarf2_per_objfile->all_comp_units[index];
}
+/* Return a new dwarf2_per_cu_data allocated on OBJFILE's
+ objfile_obstack, and constructed with the specified field
+ values. */
+
+static dwarf2_per_cu_data *
+create_cu_from_index_list (struct objfile *objfile,
+ struct dwarf2_section_info *section,
+ int is_dwz,
+ sect_offset sect_off, ULONGEST length)
+{
+ 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;
+ the_cu->v.quick = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+ struct dwarf2_per_cu_quick_data);
+ the_cu->is_dwz = is_dwz;
+ return the_cu;
+}
+
/* A helper for create_cus_from_index that handles a given list of
CUs. */
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;
- the_cu->length = length;
- the_cu->objfile = objfile;
- the_cu->section = section;
- the_cu->v.quick = OBSTACK_ZALLOC (&objfile->objfile_obstack,
- struct dwarf2_per_cu_quick_data);
- the_cu->is_dwz = is_dwz;
- dwarf2_per_objfile->all_comp_units[base_offset + i / 2] = the_cu;
+ dwarf2_per_objfile->all_comp_units[base_offset + i / 2]
+ = create_cu_from_index_list (objfile, section, is_dwz, sect_off, length);
}
}
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,
dwarf2_per_objfile->signatured_types = sig_types_hash;
}
+/* Create the signatured type hash table from .debug_names. */
+
+static void
+create_signatured_type_table_from_debug_names
+ (struct objfile *objfile,
+ const mapped_debug_names &map,
+ struct dwarf2_section_info *section,
+ struct dwarf2_section_info *abbrev_section)
+{
+ dwarf2_read_section (objfile, section);
+ dwarf2_read_section (objfile, abbrev_section);
+
+ dwarf2_per_objfile->n_type_units
+ = dwarf2_per_objfile->n_allocated_type_units
+ = map.tu_count;
+ dwarf2_per_objfile->all_type_units
+ = XNEWVEC (struct signatured_type *, dwarf2_per_objfile->n_type_units);
+
+ htab_t sig_types_hash = allocate_signatured_type_table (objfile);
+
+ for (uint32_t i = 0; i < map.tu_count; ++i)
+ {
+ struct signatured_type *sig_type;
+ ULONGEST signature;
+ void **slot;
+ cu_offset type_offset_in_tu;
+
+ sect_offset sect_off
+ = (sect_offset) (extract_unsigned_integer
+ (map.tu_table_reordered + i * map.offset_size,
+ map.offset_size,
+ map.dwarf5_byte_order));
+
+ comp_unit_head cu_header;
+ read_and_check_comp_unit_head (&cu_header, section, abbrev_section,
+ section->buffer + to_underlying (sect_off),
+ rcuh_kind::TYPE);
+
+ sig_type = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+ struct signatured_type);
+ sig_type->signature = cu_header.signature;
+ sig_type->type_offset_in_tu = cu_header.type_cu_offset_in_tu;
+ sig_type->per_cu.is_debug_types = 1;
+ sig_type->per_cu.section = section;
+ 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 dwarf2_per_cu_quick_data);
+
+ slot = htab_find_slot (sig_types_hash, sig_type, INSERT);
+ *slot = sig_type;
+
+ dwarf2_per_objfile->all_type_units[i] = sig_type;
+ }
+
+ dwarf2_per_objfile->signatured_types = sig_types_hash;
+}
+
/* Read the address map data from the mapped index, and use it to
populate the objfile's psymtabs_addrmap. */
{
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;
- end = iter + index->address_table_size;
+ iter = index->address_table.data ();
+ end = iter + index->address_table.size ();
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
objfile->psymtabs_addrmap = addrmap_create_fixed (mutable_map,
&objfile->objfile_obstack);
- do_cleanups (cleanup);
+}
+
+/* Read the address map data from DWARF-5 .debug_aranges, and use it to
+ populate the objfile's psymtabs_addrmap. */
+
+static void
+create_addrmap_from_aranges (struct objfile *objfile,
+ struct dwarf2_section_info *section)
+{
+ bfd *abfd = objfile->obfd;
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+ const CORE_ADDR baseaddr = ANOFFSET (objfile->section_offsets,
+ SECT_OFF_TEXT (objfile));
+
+ auto_obstack temp_obstack;
+ addrmap *mutable_map = addrmap_create_mutable (&temp_obstack);
+
+ std::unordered_map<sect_offset,
+ dwarf2_per_cu_data *,
+ gdb::hash_enum<sect_offset>>
+ debug_info_offset_to_per_cu;
+ for (int cui = 0; cui < dwarf2_per_objfile->n_comp_units; ++cui)
+ {
+ dwarf2_per_cu_data *per_cu = dw2_get_cutu (cui);
+ const auto insertpair
+ = debug_info_offset_to_per_cu.emplace (per_cu->sect_off, per_cu);
+ if (!insertpair.second)
+ {
+ warning (_("Section .debug_aranges in %s has duplicate "
+ "debug_info_offset %u, ignoring .debug_aranges."),
+ objfile_name (objfile), to_underlying (per_cu->sect_off));
+ return;
+ }
+ }
+
+ dwarf2_read_section (objfile, section);
+
+ const bfd_endian dwarf5_byte_order = gdbarch_byte_order (gdbarch);
+
+ const gdb_byte *addr = section->buffer;
+
+ while (addr < section->buffer + section->size)
+ {
+ const gdb_byte *const entry_addr = addr;
+ unsigned int bytes_read;
+
+ const LONGEST entry_length = read_initial_length (abfd, addr,
+ &bytes_read);
+ addr += bytes_read;
+
+ const gdb_byte *const entry_end = addr + entry_length;
+ const bool dwarf5_is_dwarf64 = bytes_read != 4;
+ const uint8_t offset_size = dwarf5_is_dwarf64 ? 8 : 4;
+ if (addr + entry_length > section->buffer + section->size)
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "length %s exceeds section length %s, "
+ "ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer,
+ plongest (bytes_read + entry_length),
+ pulongest (section->size));
+ return;
+ }
+
+ /* The version number. */
+ const uint16_t version = read_2_bytes (abfd, addr);
+ addr += 2;
+ if (version != 2)
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "has unsupported version %d, ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer,
+ version);
+ return;
+ }
+
+ const uint64_t debug_info_offset
+ = extract_unsigned_integer (addr, offset_size, dwarf5_byte_order);
+ addr += offset_size;
+ const auto per_cu_it
+ = debug_info_offset_to_per_cu.find (sect_offset (debug_info_offset));
+ if (per_cu_it == debug_info_offset_to_per_cu.cend ())
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "debug_info_offset %s does not exists, "
+ "ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer,
+ pulongest (debug_info_offset));
+ return;
+ }
+ dwarf2_per_cu_data *const per_cu = per_cu_it->second;
+
+ const uint8_t address_size = *addr++;
+ if (address_size < 1 || address_size > 8)
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "address_size %u is invalid, ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer,
+ address_size);
+ return;
+ }
+
+ const uint8_t segment_selector_size = *addr++;
+ if (segment_selector_size != 0)
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "segment_selector_size %u is not supported, "
+ "ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer,
+ segment_selector_size);
+ return;
+ }
+
+ /* Must pad to an alignment boundary that is twice the address
+ size. It is undocumented by the DWARF standard but GCC does
+ use it. */
+ for (size_t padding = ((-(addr - section->buffer))
+ & (2 * address_size - 1));
+ padding > 0; padding--)
+ if (*addr++ != 0)
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "padding is not zero, ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer);
+ return;
+ }
+
+ for (;;)
+ {
+ if (addr + 2 * address_size > entry_end)
+ {
+ warning (_("Section .debug_aranges in %s entry at offset %zu "
+ "address list is not properly terminated, "
+ "ignoring .debug_aranges."),
+ objfile_name (objfile), entry_addr - section->buffer);
+ return;
+ }
+ ULONGEST start = extract_unsigned_integer (addr, address_size,
+ dwarf5_byte_order);
+ addr += address_size;
+ ULONGEST length = extract_unsigned_integer (addr, address_size,
+ dwarf5_byte_order);
+ addr += address_size;
+ if (start == 0 && length == 0)
+ break;
+ if (start == 0 && !dwarf2_per_objfile->has_section_at_zero)
+ {
+ /* Symbol was eliminated due to a COMDAT group. */
+ continue;
+ }
+ ULONGEST end = start + length;
+ start = gdbarch_adjust_dwarf2_addr (gdbarch, start + baseaddr);
+ end = gdbarch_adjust_dwarf2_addr (gdbarch, end + baseaddr);
+ addrmap_set_empty (mutable_map, start, end - 1, per_cu);
+ }
+ }
+
+ objfile->psymtabs_addrmap = addrmap_create_fixed (mutable_map,
+ &objfile->objfile_obstack);
}
/* 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 ();
}
}
? 5 : index->version),
name);
- slot = hash & (index->symbol_table_slots - 1);
- step = ((hash * 17) & (index->symbol_table_slots - 1)) | 1;
+ slot = hash & (index->symbol_table.size () - 1);
+ step = ((hash * 17) & (index->symbol_table.size () - 1)) | 1;
cmp = (case_sensitivity == case_sensitive_on ? strcmp : strcasecmp);
for (;;)
{
- /* Convert a slot number to an offset into the table. */
- 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;
- }
- str = index->constant_pool + MAYBE_SWAP (index->symbol_table[i]);
+ const auto &bucket = index->symbol_table[slot];
+ if (bucket.name == 0 && bucket.vec == 0)
+ return false;
+
+ str = index->constant_pool + MAYBE_SWAP (bucket.name);
if (!cmp (name, str))
{
*vec_out = (offset_type *) (index->constant_pool
- + MAYBE_SWAP (index->symbol_table[i + 1]));
- do_cleanups (back_to);
- return 1;
+ + MAYBE_SWAP (bucket.vec));
+ return true;
}
- slot = (slot + step) & (index->symbol_table_slots - 1);
+ slot = (slot + step) & (index->symbol_table.size () - 1);
}
}
/ 8);
++i;
- map->address_table = addr + MAYBE_SWAP (metadata[i]);
- map->address_table_size = (MAYBE_SWAP (metadata[i + 1])
- - MAYBE_SWAP (metadata[i]));
+ const gdb_byte *address_table = addr + MAYBE_SWAP (metadata[i]);
+ const gdb_byte *address_table_end = addr + MAYBE_SWAP (metadata[i + 1]);
+ map->address_table
+ = gdb::array_view<const gdb_byte> (address_table, address_table_end);
++i;
- map->symbol_table = (offset_type *) (addr + MAYBE_SWAP (metadata[i]));
- map->symbol_table_slots = ((MAYBE_SWAP (metadata[i + 1])
- - MAYBE_SWAP (metadata[i]))
- / (2 * sizeof (offset_type)));
- ++i;
+ const gdb_byte *symbol_table = addr + MAYBE_SWAP (metadata[i]);
+ const gdb_byte *symbol_table_end = addr + MAYBE_SWAP (metadata[i + 1]);
+ map->symbol_table
+ = gdb::array_view<mapped_index::symbol_table_slot>
+ ((mapped_index::symbol_table_slot *) symbol_table,
+ (mapped_index::symbol_table_slot *) symbol_table_end);
+ ++i;
map->constant_pool = (char *) (addr + MAYBE_SWAP (metadata[i]));
return 1;
}
-
-/* Read the index file. If everything went ok, initialize the "quick"
+/* Read .gdb_index. If everything went ok, initialize the "quick"
elements of all the CUs and return 1. Otherwise, return 0. */
static int
return 0;
/* Don't use the index if it's empty. */
- if (local_map.symbol_table_slots == 0)
+ if (local_map.symbol_table.empty ())
return 0;
/* If there is a .dwz file, read it so we can get its CU list as
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;
struct dwarf2_per_cu_data *this_cu = cu->per_cu;
struct objfile *objfile = dwarf2_per_objfile->objfile;
struct dwarf2_per_cu_data *lh_cu;
- struct line_header *lh;
struct attribute *attr;
int i;
- const char *name, *comp_dir;
void **slot;
struct quick_file_names *qfn;
- unsigned int line_offset;
gdb_assert (! this_cu->is_debug_types);
}
lh_cu = this_cu;
- lh = NULL;
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;
- find_file_and_directory (comp_unit_die, cu, &name, &comp_dir);
+ file_and_directory fnd = find_file_and_directory (comp_unit_die, cu);
- qfn->num_file_names = lh->num_file_names;
+ qfn->num_file_names = lh->file_names.size ();
qfn->file_names =
- XOBNEWVEC (&objfile->objfile_obstack, const char *, lh->num_file_names);
- for (i = 0; i < lh->num_file_names; ++i)
- qfn->file_names[i] = file_full_name (i + 1, lh, comp_dir);
+ XOBNEWVEC (&objfile->objfile_obstack, const char *, lh->file_names.size ());
+ for (i = 0; i < lh->file_names.size (); ++i)
+ qfn->file_names[i] = file_full_name (i + 1, lh.get (), fnd.comp_dir);
qfn->real_names = NULL;
- free_line_header (lh);
-
lh_cu->v.quick->file_names = 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_map_expand_apply (struct objfile *objfile,
struct dwarf2_per_cu_data *per_cu,
const char *name, const char *real_path,
- int (*callback) (struct symtab *, void *),
- void *data)
+ gdb::function_view<bool (symtab *)> callback)
{
struct compunit_symtab *last_made = objfile->compunit_symtabs;
all of them. */
dw2_instantiate_symtab (per_cu);
- return iterate_over_some_symtabs (name, real_path, callback, data,
- objfile->compunit_symtabs, last_made);
+ return iterate_over_some_symtabs (name, real_path, objfile->compunit_symtabs,
+ last_made, callback);
}
/* Implementation of the map_symtabs_matching_filename method. */
-static int
-dw2_map_symtabs_matching_filename (struct objfile *objfile, const char *name,
- const char *real_path,
- int (*callback) (struct symtab *, void *),
- void *data)
+static bool
+dw2_map_symtabs_matching_filename
+ (struct objfile *objfile, const char *name, const char *real_path,
+ gdb::function_view<bool (symtab *)> callback)
{
int i;
const char *name_basename = lbasename (name);
if (compare_filenames_for_search (this_name, name))
{
if (dw2_map_expand_apply (objfile, per_cu, name, real_path,
- callback, data))
- return 1;
+ callback))
+ return true;
continue;
}
if (compare_filenames_for_search (this_real_name, name))
{
if (dw2_map_expand_apply (objfile, per_cu, name, real_path,
- callback, data))
- return 1;
+ callback))
+ return true;
continue;
}
&& FILENAME_CMP (real_path, this_real_name) == 0)
{
if (dw2_map_expand_apply (objfile, per_cu, name, real_path,
- callback, data))
- return 1;
+ callback))
+ return true;
continue;
}
}
}
}
- return 0;
+ return false;
}
/* Struct used to manage iterating over all CUs looking for a symbol. */
dw2_setup (objfile);
+ lookup_name_info lookup_name (name, symbol_name_match_type::FULL);
+
index = dwarf2_per_objfile->index_table;
/* index is NULL if OBJF_READNOW. */
information (but NAME might contain it). */
if (sym != NULL
- && strcmp_iw (SYMBOL_SEARCH_NAME (sym), name) == 0)
+ && SYMBOL_MATCHES_SEARCH_NAME (sym, lookup_name))
return stab;
if (with_opaque != NULL
- && strcmp_iw (SYMBOL_SEARCH_NAME (with_opaque), name) == 0)
+ && SYMBOL_MATCHES_SEARCH_NAME (with_opaque, lookup_name))
stab_best = stab;
/* Keep looking through other CUs. */
int global,
int (*callback) (struct block *,
struct symbol *, void *),
- void *data, symbol_compare_ftype *match,
+ void *data, symbol_name_match_type match,
symbol_compare_ftype *ordered_compare)
{
/* Currently unimplemented; used for Ada. The function can be called if the
does not look for non-Ada symbols this function should just return. */
}
-static void
-dw2_expand_symtabs_matching
- (struct objfile *objfile,
- expand_symtabs_file_matcher_ftype *file_matcher,
- expand_symtabs_symbol_matcher_ftype *symbol_matcher,
- expand_symtabs_exp_notify_ftype *expansion_notify,
- enum search_domain kind,
- void *data)
-{
- int i;
- offset_type iter;
- struct mapped_index *index;
+/* Symbol name matcher for .gdb_index names.
- dw2_setup (objfile);
+ Symbol names in .gdb_index have a few particularities:
- /* index_table is NULL if OBJF_READNOW. */
- if (!dwarf2_per_objfile->index_table)
- return;
- index = dwarf2_per_objfile->index_table;
+ - There's no indication of which is the language of each symbol.
- if (file_matcher != NULL)
- {
- htab_up visited_found (htab_create_alloc (10, htab_hash_pointer,
- htab_eq_pointer,
- NULL, xcalloc, xfree));
- htab_up visited_not_found (htab_create_alloc (10, htab_hash_pointer,
- htab_eq_pointer,
- NULL, xcalloc, xfree));
+ 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.
- /* The rule is CUs specify all the files, including those used by
- any TU, so there's no need to scan TUs here. */
+ - 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.
- 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;
+ 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);
- QUIT;
+ /* Walk all the matcher routines and match SYMBOL_NAME against them.
+ Returns true if any matcher matches. */
+ bool matches (const char *symbol_name);
- per_cu->v.quick->mark = 0;
+private:
+ /* A reference to the lookup name we're matching against. */
+ const lookup_name_info &m_lookup_name;
- /* We only need to look at symtabs not already expanded. */
- if (per_cu->v.quick->compunit_symtab)
- continue;
+ /* A vector holding all the different symbol name matchers, for all
+ languages. */
+ std::vector<symbol_name_matcher_ftype *> m_symbol_name_matcher_funcs;
+};
- file_data = dw2_get_file_names (per_cu);
- if (file_data == NULL)
- continue;
+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);
- if (htab_find (visited_not_found.get (), file_data) != NULL)
- continue;
- else if (htab_find (visited_found.get (), file_data) != NULL)
- {
- per_cu->v.quick->mark = 1;
- continue;
- }
+ matchers.push_back (default_symbol_name_matcher);
- for (j = 0; j < file_data->num_file_names; ++j)
- {
- const char *this_real_name;
+ 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);
+ }
+ }
+}
- if (file_matcher (file_data->file_names[j], data, 0))
- {
- per_cu->v.quick->mark = 1;
- break;
- }
+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;
- /* Before we invoke realpath, which can get expensive when many
- files are involved, do a quick comparison of the basenames. */
- if (!basenames_may_differ
- && !file_matcher (lbasename (file_data->file_names[j]),
- data, 1))
- continue;
+ return false;
+}
- this_real_name = dw2_get_real_path (objfile, file_data, j);
- if (file_matcher (this_real_name, data, 0))
- {
- per_cu->v.quick->mark = 1;
- break;
- }
- }
+/* 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. */
- slot = htab_find_slot (per_cu->v.quick->mark
- ? visited_found.get ()
- : visited_not_found.get (),
- file_data, INSERT);
- *slot = file_data;
- }
- }
+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.
- 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;
+ Some examples of this operation:
- QUIT;
+ SEARCH_NAME => "+1" RESULT
- if (index->symbol_table[idx] == 0 && index->symbol_table[idx + 1] == 0)
- continue;
+ "abc" => "abd"
+ "ab\xff" => "ac"
+ "\xff" "a" "\xff" => "\xff" "b"
+ "\xff" => ""
+ "\xff\xff" => ""
+ "" => ""
- name = index->constant_pool + MAYBE_SWAP (index->symbol_table[idx]);
+ Then, with these symbols for example:
- if (! (*symbol_matcher) (name, data))
- continue;
+ func
+ func1
+ fund
- /* 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);
+ 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".
- /* Work around gold/15646. */
- if (attrs_valid)
- {
- if (!is_static && global_seen)
- continue;
- if (!is_static)
- global_seen = 1;
- }
+ And with:
- /* 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;
- }
- }
+ funcÿ (Latin1 'ÿ' [0xff])
+ funcÿ1
+ fund
- /* 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;
- }
+ completing "funcÿ" looks for symbols between "funcÿ" and "fund"
+ (exclusive), which finds "funcÿ" and "funcÿ1", but not "fund".
- 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);
+ And with:
- dw2_instantiate_symtab (per_cu);
+ ÿÿ (Latin1 'ÿ' [0xff])
+ ÿÿ1
- if (expansion_notify != NULL
- && symtab_was_null
- && per_cu->v.quick->compunit_symtab != NULL)
- {
- expansion_notify (per_cu->v.quick->compunit_symtab,
- data);
- }
- }
- }
- }
+ 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;
}
-/* A helper for dw2_find_pc_sect_compunit_symtab which finds the most specific
- symtab. */
+/* See declaration. */
-static struct compunit_symtab *
-recursively_find_pc_sect_compunit_symtab (struct compunit_symtab *cust,
- CORE_ADDR pc)
+std::pair<std::vector<name_component>::const_iterator,
+ std::vector<name_component>::const_iterator>
+mapped_index_base::find_name_components_bounds
+ (const lookup_name_info &lookup_name_without_params) const
{
- int i;
+ auto *name_cmp
+ = this->name_components_casing == case_sensitive_on ? strcmp : strcasecmp;
- if (COMPUNIT_BLOCKVECTOR (cust) != NULL
- && blockvector_contains_pc (COMPUNIT_BLOCKVECTOR (cust), pc))
- return cust;
+ const char *cplus
+ = lookup_name_without_params.cplus ().lookup_name ().c_str ();
- if (cust->includes == NULL)
- return NULL;
+ /* 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;
+ };
- for (i = 0; cust->includes[i]; ++i)
+ /* Comparison function object for upper_bound that matches against a
+ given symbol name. */
+ auto lookup_compare_upper = [&] (const char *name,
+ const name_component &elem)
{
- struct compunit_symtab *s = cust->includes[i];
+ 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;
+ };
- s = recursively_find_pc_sect_compunit_symtab (s, pc);
- if (s != NULL)
- return s;
- }
+ auto begin = this->name_components.begin ();
+ auto end = this->name_components.end ();
- return NULL;
+ /* 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};
}
-static struct compunit_symtab *
-dw2_find_pc_sect_compunit_symtab (struct objfile *objfile,
- struct bound_minimal_symbol msymbol,
- CORE_ADDR pc,
- struct obj_section *section,
- int warn_if_readin)
+/* See declaration. */
+
+void
+mapped_index_base::build_name_components ()
{
- struct dwarf2_per_cu_data *data;
- struct compunit_symtab *result;
+ if (!this->name_components.empty ())
+ return;
- dw2_setup (objfile);
+ 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. */
+ auto count = this->symbol_name_count ();
+ for (offset_type idx = 0; idx < count; idx++)
+ {
+ if (this->symbol_name_slot_invalid (idx))
+ continue;
- if (!objfile->psymtabs_addrmap)
- return NULL;
+ const char *name = this->symbol_name_at (idx);
- data = (struct dwarf2_per_cu_data *) addrmap_find (objfile->psymtabs_addrmap,
- pc);
- if (!data)
- return NULL;
+ /* 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});
+ }
- if (warn_if_readin && data->v.quick->compunit_symtab)
- warning (_("(Internal error: pc %s in read in CU, but not in symtab.)"),
- paddress (get_objfile_arch (objfile), pc));
+ /* 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);
- result
- = recursively_find_pc_sect_compunit_symtab (dw2_instantiate_symtab (data),
- pc);
- gdb_assert (result != NULL);
- return result;
+ 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_base 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_base. For each
+ symbol name that matches, calls MATCH_CALLBACK, passing it the
+ symbol's index in the mapped_index_base symbol table. */
+
static void
-dw2_map_symbol_filenames (struct objfile *objfile, symbol_filename_ftype *fun,
- void *data, int need_fullname)
+dw2_expand_symtabs_matching_symbol
+ (mapped_index_base &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)
{
- int i;
- htab_up visited (htab_create_alloc (10, htab_hash_pointer, htab_eq_pointer,
- NULL, xcalloc, xfree));
-
- dw2_setup (objfile);
+ 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);
- /* 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. */
+ /* Build the symbol name component sorted vector, if we haven't
+ yet. */
+ index.build_name_components ();
- for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
- {
- struct dwarf2_per_cu_data *per_cu = dw2_get_cutu (i);
+ auto bounds = index.find_name_components_bounds (lookup_name_without_params);
- if (per_cu->v.quick->compunit_symtab)
- {
- void **slot = htab_find_slot (visited.get (),
- per_cu->v.quick->file_names,
- INSERT);
+ /* Now for each symbol name in range, check to see if we have a name
+ match, and if so, call the MATCH_CALLBACK callback. */
- *slot = per_cu->v.quick->file_names;
- }
- }
+ /* 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 (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ for (; bounds.first != bounds.second; ++bounds.first)
{
- int j;
- struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i);
- struct quick_file_names *file_data;
- void **slot;
+ const char *qualified = index.symbol_name_at (bounds.first->idx);
- /* We only need to look at symtabs not already expanded. */
- if (per_cu->v.quick->compunit_symtab)
+ if (!lookup_name_matcher.matches (qualified)
+ || (symbol_matcher != NULL && !symbol_matcher (qualified)))
continue;
- file_data = dw2_get_file_names (per_cu);
- if (file_data == NULL)
- continue;
+ matches.push_back (bounds.first->idx);
+ }
- slot = htab_find_slot (visited.get (), file_data, INSERT);
- if (*slot)
+ std::sort (matches.begin (), matches.end ());
+
+ /* Finally call the callback, once per match. */
+ ULONGEST prev = -1;
+ for (offset_type idx : matches)
+ {
+ if (prev != idx)
{
- /* Already visited. */
- continue;
+ match_callback (idx);
+ prev = idx;
}
- *slot = file_data;
+ }
+
+ /* 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 mock .gdb_index/.debug_names-like name index table, enough to
+ exercise dw2_expand_symtabs_matching_symbol, which works with the
+ mapped_index_base interface. Builds an index from the symbol list
+ passed as parameter to the constructor. */
+class mock_mapped_index : public mapped_index_base
+{
+public:
+ mock_mapped_index (gdb::array_view<const char *> symbols)
+ : m_symbol_table (symbols)
+ {}
+
+ DISABLE_COPY_AND_ASSIGN (mock_mapped_index);
+
+ /* Return the number of names in the symbol table. */
+ virtual size_t symbol_name_count () const
+ {
+ return m_symbol_table.size ();
+ }
+
+ /* Get the name of the symbol at IDX in the symbol table. */
+ virtual const char *symbol_name_at (offset_type idx) const
+ {
+ return m_symbol_table[idx];
+ }
+
+private:
+ gdb::array_view<const char *> m_symbol_table;
+};
+
+/* 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, lookup_name,
+ NULL, ALL_DOMAIN,
+ [&] (offset_type idx)
+ {
+ const char *matched_name = mock_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_base::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_base &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.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,
+ "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,
+ "\377", expected_syms1));
+
+ static const char *expected_syms2[] = {
+ "\377\377123",
+ };
+ SELF_CHECK (check_find_bounds_finds (mock_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 */
+
+/* If FILE_MATCHER is NULL or if PER_CU has
+ dwarf2_per_cu_quick_data::MARK set (see
+ dw_expand_symtabs_matching_file_matcher), expand the CU and call
+ EXPANSION_NOTIFY on it. */
+
+static void
+dw2_expand_symtabs_matching_one
+ (struct dwarf2_per_cu_data *per_cu,
+ gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
+ gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify)
+{
+ if (file_matcher == NULL || per_cu->v.quick->mark)
+ {
+ bool symtab_was_null
+ = (per_cu->v.quick->compunit_symtab == NULL);
+
+ dw2_instantiate_symtab (per_cu);
+
+ if (expansion_notify != NULL
+ && symtab_was_null
+ && per_cu->v.quick->compunit_symtab != NULL)
+ expansion_notify (per_cu->v.quick->compunit_symtab);
+ }
+}
+
+/* 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].vec));
+ 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);
+ dw2_expand_symtabs_matching_one (per_cu, file_matcher,
+ expansion_notify);
+ }
+}
+
+/* If FILE_MATCHER is non-NULL, set all the
+ dwarf2_per_cu_quick_data::MARK of the current DWARF2_PER_OBJFILE
+ that match FILE_MATCHER. */
+
+static void
+dw_expand_symtabs_matching_file_matcher
+ (gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher)
+{
+ if (file_matcher == NULL)
+ return;
+
+ objfile *const objfile = dwarf2_per_objfile->objfile;
+
+ htab_up visited_found (htab_create_alloc (10, htab_hash_pointer,
+ htab_eq_pointer,
+ NULL, xcalloc, xfree));
+ htab_up visited_not_found (htab_create_alloc (10, htab_hash_pointer,
+ htab_eq_pointer,
+ NULL, xcalloc, xfree));
+
+ /* The rule is CUs specify all the files, including those used by
+ any TU, so there's no need to scan TUs here. */
+
+ for (int 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;
+
+ QUIT;
+
+ per_cu->v.quick->mark = 0;
+
+ /* 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;
+
+ if (htab_find (visited_not_found.get (), file_data) != NULL)
+ continue;
+ else if (htab_find (visited_found.get (), file_data) != NULL)
+ {
+ per_cu->v.quick->mark = 1;
+ continue;
+ }
+
+ for (j = 0; j < file_data->num_file_names; ++j)
+ {
+ const char *this_real_name;
+
+ if (file_matcher (file_data->file_names[j], false))
+ {
+ per_cu->v.quick->mark = 1;
+ break;
+ }
+
+ /* Before we invoke realpath, which can get expensive when many
+ files are involved, do a quick comparison of the basenames. */
+ if (!basenames_may_differ
+ && !file_matcher (lbasename (file_data->file_names[j]),
+ true))
+ continue;
+
+ this_real_name = dw2_get_real_path (objfile, file_data, j);
+ if (file_matcher (this_real_name, false))
+ {
+ per_cu->v.quick->mark = 1;
+ break;
+ }
+ }
+
+ slot = htab_find_slot (per_cu->v.quick->mark
+ ? visited_found.get ()
+ : visited_not_found.get (),
+ file_data, INSERT);
+ *slot = file_data;
+ }
+}
+
+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)
+{
+ dw2_setup (objfile);
+
+ /* index_table is NULL if OBJF_READNOW. */
+ if (!dwarf2_per_objfile->index_table)
+ return;
+
+ dw_expand_symtabs_matching_file_matcher (file_matcher);
+
+ mapped_index &index = *dwarf2_per_objfile->index_table;
+
+ 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
+ symtab. */
+
+static struct compunit_symtab *
+recursively_find_pc_sect_compunit_symtab (struct compunit_symtab *cust,
+ CORE_ADDR pc)
+{
+ int i;
+
+ if (COMPUNIT_BLOCKVECTOR (cust) != NULL
+ && blockvector_contains_pc (COMPUNIT_BLOCKVECTOR (cust), pc))
+ return cust;
+
+ if (cust->includes == NULL)
+ return NULL;
+
+ for (i = 0; cust->includes[i]; ++i)
+ {
+ struct compunit_symtab *s = cust->includes[i];
+
+ s = recursively_find_pc_sect_compunit_symtab (s, pc);
+ if (s != NULL)
+ return s;
+ }
+
+ return NULL;
+}
+
+static struct compunit_symtab *
+dw2_find_pc_sect_compunit_symtab (struct objfile *objfile,
+ struct bound_minimal_symbol msymbol,
+ CORE_ADDR pc,
+ struct obj_section *section,
+ int warn_if_readin)
+{
+ struct dwarf2_per_cu_data *data;
+ struct compunit_symtab *result;
+
+ dw2_setup (objfile);
+
+ if (!objfile->psymtabs_addrmap)
+ return NULL;
+
+ data = (struct dwarf2_per_cu_data *) addrmap_find (objfile->psymtabs_addrmap,
+ pc);
+ if (!data)
+ return NULL;
+
+ if (warn_if_readin && data->v.quick->compunit_symtab)
+ warning (_("(Internal error: pc %s in read in CU, but not in symtab.)"),
+ paddress (get_objfile_arch (objfile), pc));
+
+ result
+ = recursively_find_pc_sect_compunit_symtab (dw2_instantiate_symtab (data),
+ pc);
+ gdb_assert (result != NULL);
+ return result;
+}
+
+static void
+dw2_map_symbol_filenames (struct objfile *objfile, symbol_filename_ftype *fun,
+ void *data, int need_fullname)
+{
+ dw2_setup (objfile);
+
+ if (!dwarf2_per_objfile->filenames_cache)
+ {
+ dwarf2_per_objfile->filenames_cache.emplace ();
+
+ htab_up visited (htab_create_alloc (10,
+ htab_hash_pointer, htab_eq_pointer,
+ NULL, xcalloc, xfree));
+
+ /* 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 (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ {
+ 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);
+
+ *slot = per_cu->v.quick->file_names;
+ }
+ }
+
+ for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ {
+ struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i);
+ struct quick_file_names *file_data;
+ void **slot;
+
+ /* 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_has_symbols (struct objfile *objfile)
+{
+ return 1;
+}
+
+const struct quick_symbol_functions dwarf2_gdb_index_functions =
+{
+ dw2_has_symbols,
+ dw2_find_last_source_symtab,
+ dw2_forget_cached_source_info,
+ dw2_map_symtabs_matching_filename,
+ dw2_lookup_symbol,
+ dw2_print_stats,
+ dw2_dump,
+ dw2_relocate,
+ dw2_expand_symtabs_for_function,
+ dw2_expand_all_symtabs,
+ dw2_expand_symtabs_with_fullname,
+ dw2_map_matching_symbols,
+ dw2_expand_symtabs_matching,
+ dw2_find_pc_sect_compunit_symtab,
+ NULL,
+ dw2_map_symbol_filenames
+};
+
+/* DWARF-5 debug_names reader. */
+
+/* DWARF-5 augmentation string for GDB's DW_IDX_GNU_* extension. */
+static const gdb_byte dwarf5_augmentation[] = { 'G', 'D', 'B', 0 };
+
+/* A helper function that reads the .debug_names section in SECTION
+ and fills in MAP. FILENAME is the name of the file containing the
+ section; it is used for error reporting.
+
+ Returns true if all went well, false otherwise. */
+
+static bool
+read_debug_names_from_section (struct objfile *objfile,
+ const char *filename,
+ struct dwarf2_section_info *section,
+ mapped_debug_names &map)
+{
+ if (dwarf2_section_empty_p (section))
+ return false;
+
+ /* Older elfutils strip versions could keep the section in the main
+ executable while splitting it for the separate debug info file. */
+ if ((get_section_flags (section) & SEC_HAS_CONTENTS) == 0)
+ return false;
+
+ dwarf2_read_section (objfile, section);
+
+ map.dwarf5_byte_order = gdbarch_byte_order (get_objfile_arch (objfile));
+
+ const gdb_byte *addr = section->buffer;
+
+ bfd *const abfd = get_section_bfd_owner (section);
+
+ unsigned int bytes_read;
+ LONGEST length = read_initial_length (abfd, addr, &bytes_read);
+ addr += bytes_read;
+
+ map.dwarf5_is_dwarf64 = bytes_read != 4;
+ map.offset_size = map.dwarf5_is_dwarf64 ? 8 : 4;
+ if (bytes_read + length != section->size)
+ {
+ /* There may be multiple per-CU indices. */
+ warning (_("Section .debug_names in %s length %s does not match "
+ "section length %s, ignoring .debug_names."),
+ filename, plongest (bytes_read + length),
+ pulongest (section->size));
+ return false;
+ }
+
+ /* The version number. */
+ uint16_t version = read_2_bytes (abfd, addr);
+ addr += 2;
+ if (version != 5)
+ {
+ warning (_("Section .debug_names in %s has unsupported version %d, "
+ "ignoring .debug_names."),
+ filename, version);
+ return false;
+ }
+
+ /* Padding. */
+ uint16_t padding = read_2_bytes (abfd, addr);
+ addr += 2;
+ if (padding != 0)
+ {
+ warning (_("Section .debug_names in %s has unsupported padding %d, "
+ "ignoring .debug_names."),
+ filename, padding);
+ return false;
+ }
+
+ /* comp_unit_count - The number of CUs in the CU list. */
+ map.cu_count = read_4_bytes (abfd, addr);
+ addr += 4;
+
+ /* local_type_unit_count - The number of TUs in the local TU
+ list. */
+ map.tu_count = read_4_bytes (abfd, addr);
+ addr += 4;
+
+ /* foreign_type_unit_count - The number of TUs in the foreign TU
+ list. */
+ uint32_t foreign_tu_count = read_4_bytes (abfd, addr);
+ addr += 4;
+ if (foreign_tu_count != 0)
+ {
+ warning (_("Section .debug_names in %s has unsupported %lu foreign TUs, "
+ "ignoring .debug_names."),
+ filename, static_cast<unsigned long> (foreign_tu_count));
+ return false;
+ }
+
+ /* bucket_count - The number of hash buckets in the hash lookup
+ table. */
+ map.bucket_count = read_4_bytes (abfd, addr);
+ addr += 4;
+
+ /* name_count - The number of unique names in the index. */
+ map.name_count = read_4_bytes (abfd, addr);
+ addr += 4;
+
+ /* abbrev_table_size - The size in bytes of the abbreviations
+ table. */
+ uint32_t abbrev_table_size = read_4_bytes (abfd, addr);
+ addr += 4;
+
+ /* augmentation_string_size - The size in bytes of the augmentation
+ string. This value is rounded up to a multiple of 4. */
+ uint32_t augmentation_string_size = read_4_bytes (abfd, addr);
+ addr += 4;
+ map.augmentation_is_gdb = ((augmentation_string_size
+ == sizeof (dwarf5_augmentation))
+ && memcmp (addr, dwarf5_augmentation,
+ sizeof (dwarf5_augmentation)) == 0);
+ augmentation_string_size += (-augmentation_string_size) & 3;
+ addr += augmentation_string_size;
+
+ /* List of CUs */
+ map.cu_table_reordered = addr;
+ addr += map.cu_count * map.offset_size;
+
+ /* List of Local TUs */
+ map.tu_table_reordered = addr;
+ addr += map.tu_count * map.offset_size;
+
+ /* Hash Lookup Table */
+ map.bucket_table_reordered = reinterpret_cast<const uint32_t *> (addr);
+ addr += map.bucket_count * 4;
+ map.hash_table_reordered = reinterpret_cast<const uint32_t *> (addr);
+ addr += map.name_count * 4;
+
+ /* Name Table */
+ map.name_table_string_offs_reordered = addr;
+ addr += map.name_count * map.offset_size;
+ map.name_table_entry_offs_reordered = addr;
+ addr += map.name_count * map.offset_size;
+
+ const gdb_byte *abbrev_table_start = addr;
+ for (;;)
+ {
+ unsigned int bytes_read;
+ const ULONGEST index_num = read_unsigned_leb128 (abfd, addr, &bytes_read);
+ addr += bytes_read;
+ if (index_num == 0)
+ break;
+
+ const auto insertpair
+ = map.abbrev_map.emplace (index_num, mapped_debug_names::index_val ());
+ if (!insertpair.second)
+ {
+ warning (_("Section .debug_names in %s has duplicate index %s, "
+ "ignoring .debug_names."),
+ filename, pulongest (index_num));
+ return false;
+ }
+ mapped_debug_names::index_val &indexval = insertpair.first->second;
+ indexval.dwarf_tag = read_unsigned_leb128 (abfd, addr, &bytes_read);
+ addr += bytes_read;
+
+ for (;;)
+ {
+ mapped_debug_names::index_val::attr attr;
+ attr.dw_idx = read_unsigned_leb128 (abfd, addr, &bytes_read);
+ addr += bytes_read;
+ attr.form = read_unsigned_leb128 (abfd, addr, &bytes_read);
+ addr += bytes_read;
+ if (attr.form == DW_FORM_implicit_const)
+ {
+ attr.implicit_const = read_signed_leb128 (abfd, addr,
+ &bytes_read);
+ addr += bytes_read;
+ }
+ if (attr.dw_idx == 0 && attr.form == 0)
+ break;
+ indexval.attr_vec.push_back (std::move (attr));
+ }
+ }
+ if (addr != abbrev_table_start + abbrev_table_size)
+ {
+ warning (_("Section .debug_names in %s has abbreviation_table "
+ "of size %zu vs. written as %u, ignoring .debug_names."),
+ filename, addr - abbrev_table_start, abbrev_table_size);
+ return false;
+ }
+ map.entry_pool = addr;
+
+ return true;
+}
+
+/* A helper for create_cus_from_debug_names that handles the MAP's CU
+ list. */
+
+static void
+create_cus_from_debug_names_list (struct objfile *objfile,
+ const mapped_debug_names &map,
+ dwarf2_section_info §ion,
+ bool is_dwz, int base_offset)
+{
+ sect_offset sect_off_prev;
+ for (uint32_t i = 0; i <= map.cu_count; ++i)
+ {
+ sect_offset sect_off_next;
+ if (i < map.cu_count)
+ {
+ sect_off_next
+ = (sect_offset) (extract_unsigned_integer
+ (map.cu_table_reordered + i * map.offset_size,
+ map.offset_size,
+ map.dwarf5_byte_order));
+ }
+ else
+ sect_off_next = (sect_offset) section.size;
+ if (i >= 1)
+ {
+ const ULONGEST length = sect_off_next - sect_off_prev;
+ dwarf2_per_objfile->all_comp_units[base_offset + (i - 1)]
+ = create_cu_from_index_list (objfile, §ion, is_dwz,
+ sect_off_prev, length);
+ }
+ sect_off_prev = sect_off_next;
+ }
+}
+
+/* Read the CU list from the mapped index, and use it to create all
+ the CU objects for this objfile. */
+
+static void
+create_cus_from_debug_names (struct objfile *objfile,
+ const mapped_debug_names &map,
+ const mapped_debug_names &dwz_map)
+{
+
+ dwarf2_per_objfile->n_comp_units = map.cu_count + dwz_map.cu_count;
+ dwarf2_per_objfile->all_comp_units
+ = XOBNEWVEC (&objfile->objfile_obstack, struct dwarf2_per_cu_data *,
+ dwarf2_per_objfile->n_comp_units);
+
+ create_cus_from_debug_names_list (objfile, map, dwarf2_per_objfile->info,
+ false /* is_dwz */,
+ 0 /* base_offset */);
+
+ if (dwz_map.cu_count == 0)
+ return;
+
+ dwz_file *dwz = dwarf2_get_dwz_file ();
+ create_cus_from_debug_names_list (objfile, dwz_map, dwz->info,
+ true /* is_dwz */,
+ map.cu_count /* base_offset */);
+}
+
+/* Read .debug_names. If everything went ok, initialize the "quick"
+ elements of all the CUs and return true. Otherwise, return false. */
+
+static bool
+dwarf2_read_debug_names (struct objfile *objfile)
+{
+ mapped_debug_names local_map, dwz_map;
+
+ if (!read_debug_names_from_section (objfile, objfile_name (objfile),
+ &dwarf2_per_objfile->debug_names,
+ local_map))
+ return false;
+
+ /* Don't use the index if it's empty. */
+ if (local_map.name_count == 0)
+ return false;
+
+ /* If there is a .dwz file, read it so we can get its CU list as
+ well. */
+ dwz_file *dwz = dwarf2_get_dwz_file ();
+ if (dwz != NULL)
+ {
+ if (!read_debug_names_from_section (objfile,
+ bfd_get_filename (dwz->dwz_bfd),
+ &dwz->debug_names, dwz_map))
+ {
+ warning (_("could not read '.debug_names' section from %s; skipping"),
+ bfd_get_filename (dwz->dwz_bfd));
+ return false;
+ }
+ }
+
+ create_cus_from_debug_names (objfile, local_map, dwz_map);
+
+ if (local_map.tu_count != 0)
+ {
+ /* We can only handle a single .debug_types when we have an
+ index. */
+ if (VEC_length (dwarf2_section_info_def, dwarf2_per_objfile->types) != 1)
+ return false;
+
+ dwarf2_section_info *section = VEC_index (dwarf2_section_info_def,
+ dwarf2_per_objfile->types, 0);
+
+ create_signatured_type_table_from_debug_names
+ (objfile, local_map, section, &dwarf2_per_objfile->abbrev);
+ }
+
+ create_addrmap_from_aranges (objfile, &dwarf2_per_objfile->debug_aranges);
+
+ dwarf2_per_objfile->debug_names_table.reset (new mapped_debug_names);
+ *dwarf2_per_objfile->debug_names_table = std::move (local_map);
+ dwarf2_per_objfile->using_index = 1;
+ dwarf2_per_objfile->quick_file_names_table =
+ create_quick_file_names_table (dwarf2_per_objfile->n_comp_units);
+
+ return true;
+}
+
+/* Symbol name hashing function as specified by DWARF-5. */
+
+static uint32_t
+dwarf5_djb_hash (const char *str_)
+{
+ const unsigned char *str = (const unsigned char *) str_;
+
+ /* Note: tolower here ignores UTF-8, which isn't fully compliant.
+ See http://dwarfstd.org/ShowIssue.php?issue=161027.1. */
+
+ uint32_t hash = 5381;
+ while (int c = *str++)
+ hash = hash * 33 + tolower (c);
+ return hash;
+}
+
+/* Type used to manage iterating over all CUs looking for a symbol for
+ .debug_names. */
+
+class dw2_debug_names_iterator
+{
+public:
+ /* If WANT_SPECIFIC_BLOCK is true, only look for symbols in block
+ BLOCK_INDEX. Otherwise BLOCK_INDEX is ignored. */
+ dw2_debug_names_iterator (const mapped_debug_names &map,
+ bool want_specific_block,
+ block_enum block_index, domain_enum domain,
+ const char *name)
+ : m_map (map), m_want_specific_block (want_specific_block),
+ m_block_index (block_index), m_domain (domain),
+ m_addr (find_vec_in_debug_names (map, name))
+ {}
+
+ dw2_debug_names_iterator (const mapped_debug_names &map,
+ search_domain search, uint32_t namei)
+ : m_map (map),
+ m_search (search),
+ m_addr (find_vec_in_debug_names (map, namei))
+ {}
+
+ /* Return the next matching CU or NULL if there are no more. */
+ dwarf2_per_cu_data *next ();
+
+private:
+ static const gdb_byte *find_vec_in_debug_names (const mapped_debug_names &map,
+ const char *name);
+ static const gdb_byte *find_vec_in_debug_names (const mapped_debug_names &map,
+ uint32_t namei);
+
+ /* The internalized form of .debug_names. */
+ const mapped_debug_names &m_map;
+
+ /* If true, only look for symbols that match BLOCK_INDEX. */
+ const bool m_want_specific_block = false;
+
+ /* One of GLOBAL_BLOCK or STATIC_BLOCK.
+ Unused if !WANT_SPECIFIC_BLOCK - FIRST_LOCAL_BLOCK is an invalid
+ value. */
+ const block_enum m_block_index = FIRST_LOCAL_BLOCK;
+
+ /* The kind of symbol we're looking for. */
+ const domain_enum m_domain = UNDEF_DOMAIN;
+ const search_domain m_search = ALL_DOMAIN;
+
+ /* The list of CUs from the index entry of the symbol, or NULL if
+ not found. */
+ const gdb_byte *m_addr;
+};
+
+const char *
+mapped_debug_names::namei_to_name (uint32_t namei) const
+{
+ const ULONGEST namei_string_offs
+ = extract_unsigned_integer ((name_table_string_offs_reordered
+ + namei * offset_size),
+ offset_size,
+ dwarf5_byte_order);
+ return read_indirect_string_at_offset
+ (dwarf2_per_objfile->objfile->obfd, namei_string_offs);
+}
+
+/* Find a slot in .debug_names for the object named NAME. If NAME is
+ found, return pointer to its pool data. If NAME cannot be found,
+ return NULL. */
+
+const gdb_byte *
+dw2_debug_names_iterator::find_vec_in_debug_names
+ (const mapped_debug_names &map, const char *name)
+{
+ int (*cmp) (const char *, const char *);
+
+ if (current_language->la_language == language_cplus
+ || current_language->la_language == language_fortran
+ || current_language->la_language == language_d)
+ {
+ /* NAME is already canonical. Drop any qualifiers as
+ .debug_names does not contain any. */
+
+ if (strchr (name, '(') != NULL)
+ {
+ gdb::unique_xmalloc_ptr<char> without_params
+ = cp_remove_params (name);
+
+ if (without_params != NULL)
+ {
+ name = without_params.get();
+ }
+ }
+ }
+
+ cmp = (case_sensitivity == case_sensitive_on ? strcmp : strcasecmp);
+
+ const uint32_t full_hash = dwarf5_djb_hash (name);
+ uint32_t namei
+ = extract_unsigned_integer (reinterpret_cast<const gdb_byte *>
+ (map.bucket_table_reordered
+ + (full_hash % map.bucket_count)), 4,
+ map.dwarf5_byte_order);
+ if (namei == 0)
+ return NULL;
+ --namei;
+ if (namei >= map.name_count)
+ {
+ complaint (&symfile_complaints,
+ _("Wrong .debug_names with name index %u but name_count=%u "
+ "[in module %s]"),
+ namei, map.name_count,
+ objfile_name (dwarf2_per_objfile->objfile));
+ return NULL;
+ }
+
+ for (;;)
+ {
+ const uint32_t namei_full_hash
+ = extract_unsigned_integer (reinterpret_cast<const gdb_byte *>
+ (map.hash_table_reordered + namei), 4,
+ map.dwarf5_byte_order);
+ if (full_hash % map.bucket_count != namei_full_hash % map.bucket_count)
+ return NULL;
+
+ if (full_hash == namei_full_hash)
+ {
+ const char *const namei_string = map.namei_to_name (namei);
+
+#if 0 /* An expensive sanity check. */
+ if (namei_full_hash != dwarf5_djb_hash (namei_string))
+ {
+ complaint (&symfile_complaints,
+ _("Wrong .debug_names hash for string at index %u "
+ "[in module %s]"),
+ namei, objfile_name (dwarf2_per_objfile->objfile));
+ return NULL;
+ }
+#endif
+
+ if (cmp (namei_string, name) == 0)
+ {
+ const ULONGEST namei_entry_offs
+ = extract_unsigned_integer ((map.name_table_entry_offs_reordered
+ + namei * map.offset_size),
+ map.offset_size, map.dwarf5_byte_order);
+ return map.entry_pool + namei_entry_offs;
+ }
+ }
+
+ ++namei;
+ if (namei >= map.name_count)
+ return NULL;
+ }
+}
+
+const gdb_byte *
+dw2_debug_names_iterator::find_vec_in_debug_names
+ (const mapped_debug_names &map, uint32_t namei)
+{
+ if (namei >= map.name_count)
+ {
+ complaint (&symfile_complaints,
+ _("Wrong .debug_names with name index %u but name_count=%u "
+ "[in module %s]"),
+ namei, map.name_count,
+ objfile_name (dwarf2_per_objfile->objfile));
+ return NULL;
+ }
- for (j = 0; j < file_data->num_file_names; ++j)
+ const ULONGEST namei_entry_offs
+ = extract_unsigned_integer ((map.name_table_entry_offs_reordered
+ + namei * map.offset_size),
+ map.offset_size, map.dwarf5_byte_order);
+ return map.entry_pool + namei_entry_offs;
+}
+
+/* See dw2_debug_names_iterator. */
+
+dwarf2_per_cu_data *
+dw2_debug_names_iterator::next ()
+{
+ if (m_addr == NULL)
+ return NULL;
+
+ bfd *const abfd = dwarf2_per_objfile->objfile->obfd;
+
+ again:
+
+ unsigned int bytes_read;
+ const ULONGEST abbrev = read_unsigned_leb128 (abfd, m_addr, &bytes_read);
+ m_addr += bytes_read;
+ if (abbrev == 0)
+ return NULL;
+
+ const auto indexval_it = m_map.abbrev_map.find (abbrev);
+ if (indexval_it == m_map.abbrev_map.cend ())
+ {
+ complaint (&symfile_complaints,
+ _("Wrong .debug_names undefined abbrev code %s "
+ "[in module %s]"),
+ pulongest (abbrev), objfile_name (dwarf2_per_objfile->objfile));
+ return NULL;
+ }
+ const mapped_debug_names::index_val &indexval = indexval_it->second;
+ bool have_is_static = false;
+ bool is_static;
+ dwarf2_per_cu_data *per_cu = NULL;
+ for (const mapped_debug_names::index_val::attr &attr : indexval.attr_vec)
+ {
+ ULONGEST ull;
+ switch (attr.form)
{
- const char *this_real_name;
+ case DW_FORM_implicit_const:
+ ull = attr.implicit_const;
+ break;
+ case DW_FORM_flag_present:
+ ull = 1;
+ break;
+ case DW_FORM_udata:
+ ull = read_unsigned_leb128 (abfd, m_addr, &bytes_read);
+ m_addr += bytes_read;
+ break;
+ default:
+ complaint (&symfile_complaints,
+ _("Unsupported .debug_names form %s [in module %s]"),
+ dwarf_form_name (attr.form),
+ objfile_name (dwarf2_per_objfile->objfile));
+ return NULL;
+ }
+ switch (attr.dw_idx)
+ {
+ case DW_IDX_compile_unit:
+ /* Don't crash on bad data. */
+ if (ull >= dwarf2_per_objfile->n_comp_units)
+ {
+ complaint (&symfile_complaints,
+ _(".debug_names entry has bad CU index %s"
+ " [in module %s]"),
+ pulongest (ull),
+ objfile_name (dwarf2_per_objfile->objfile));
+ continue;
+ }
+ per_cu = dw2_get_cutu (ull);
+ break;
+ case DW_IDX_type_unit:
+ /* Don't crash on bad data. */
+ if (ull >= dwarf2_per_objfile->n_type_units)
+ {
+ complaint (&symfile_complaints,
+ _(".debug_names entry has bad TU index %s"
+ " [in module %s]"),
+ pulongest (ull),
+ objfile_name (dwarf2_per_objfile->objfile));
+ continue;
+ }
+ per_cu = dw2_get_cutu (dwarf2_per_objfile->n_comp_units + ull);
+ break;
+ case DW_IDX_GNU_internal:
+ if (!m_map.augmentation_is_gdb)
+ break;
+ have_is_static = true;
+ is_static = true;
+ break;
+ case DW_IDX_GNU_external:
+ if (!m_map.augmentation_is_gdb)
+ break;
+ have_is_static = true;
+ is_static = false;
+ break;
+ }
+ }
- 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);
+ /* Skip if already read in. */
+ if (per_cu->v.quick->compunit_symtab)
+ goto again;
+
+ /* Check static vs global. */
+ if (have_is_static)
+ {
+ const bool want_static = m_block_index != GLOBAL_BLOCK;
+ if (m_want_specific_block && want_static != is_static)
+ goto again;
+ }
+
+ /* Match dw2_symtab_iter_next, symbol_kind
+ and debug_names::psymbol_tag. */
+ switch (m_domain)
+ {
+ case VAR_DOMAIN:
+ switch (indexval.dwarf_tag)
+ {
+ case DW_TAG_variable:
+ case DW_TAG_subprogram:
+ /* Some types are also in VAR_DOMAIN. */
+ case DW_TAG_typedef:
+ case DW_TAG_structure_type:
+ break;
+ default:
+ goto again;
+ }
+ break;
+ case STRUCT_DOMAIN:
+ switch (indexval.dwarf_tag)
+ {
+ case DW_TAG_typedef:
+ case DW_TAG_structure_type:
+ break;
+ default:
+ goto again;
+ }
+ break;
+ case LABEL_DOMAIN:
+ switch (indexval.dwarf_tag)
+ {
+ case 0:
+ case DW_TAG_variable:
+ break;
+ default:
+ goto again;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Match dw2_expand_symtabs_matching, symbol_kind and
+ debug_names::psymbol_tag. */
+ switch (m_search)
+ {
+ case VARIABLES_DOMAIN:
+ switch (indexval.dwarf_tag)
+ {
+ case DW_TAG_variable:
+ break;
+ default:
+ goto again;
+ }
+ break;
+ case FUNCTIONS_DOMAIN:
+ switch (indexval.dwarf_tag)
+ {
+ case DW_TAG_subprogram:
+ break;
+ default:
+ goto again;
+ }
+ break;
+ case TYPES_DOMAIN:
+ switch (indexval.dwarf_tag)
+ {
+ case DW_TAG_typedef:
+ case DW_TAG_structure_type:
+ break;
+ default:
+ goto again;
}
+ break;
+ default:
+ break;
}
+
+ return per_cu;
}
-static int
-dw2_has_symbols (struct objfile *objfile)
+static struct compunit_symtab *
+dw2_debug_names_lookup_symbol (struct objfile *objfile, int block_index_int,
+ const char *name, domain_enum domain)
{
- return 1;
+ const block_enum block_index = static_cast<block_enum> (block_index_int);
+ dw2_setup (objfile);
+
+ const auto &mapp = dwarf2_per_objfile->debug_names_table;
+ if (!mapp)
+ {
+ /* index is NULL if OBJF_READNOW. */
+ return NULL;
+ }
+ const auto &map = *mapp;
+
+ dw2_debug_names_iterator iter (map, true /* want_specific_block */,
+ block_index, domain, name);
+
+ struct compunit_symtab *stab_best = NULL;
+ struct dwarf2_per_cu_data *per_cu;
+ while ((per_cu = iter.next ()) != NULL)
+ {
+ struct symbol *sym, *with_opaque = NULL;
+ struct compunit_symtab *stab = dw2_instantiate_symtab (per_cu);
+ const struct blockvector *bv = COMPUNIT_BLOCKVECTOR (stab);
+ struct block *block = BLOCKVECTOR_BLOCK (bv, block_index);
+
+ sym = block_find_symbol (block, name, domain,
+ block_find_non_opaque_type_preferred,
+ &with_opaque);
+
+ /* Some caution must be observed with overloaded functions and
+ methods, since the index will not contain any overload
+ information (but NAME might contain it). */
+
+ if (sym != NULL
+ && strcmp_iw (SYMBOL_SEARCH_NAME (sym), name) == 0)
+ return stab;
+ if (with_opaque != NULL
+ && strcmp_iw (SYMBOL_SEARCH_NAME (with_opaque), name) == 0)
+ stab_best = stab;
+
+ /* Keep looking through other CUs. */
+ }
+
+ return stab_best;
}
-const struct quick_symbol_functions dwarf2_gdb_index_functions =
+/* This dumps minimal information about .debug_names. It is called
+ via "mt print objfiles". The gdb.dwarf2/gdb-index.exp testcase
+ uses this to verify that .debug_names has been loaded. */
+
+static void
+dw2_debug_names_dump (struct objfile *objfile)
+{
+ dw2_setup (objfile);
+ gdb_assert (dwarf2_per_objfile->using_index);
+ printf_filtered (".debug_names:");
+ if (dwarf2_per_objfile->debug_names_table)
+ printf_filtered (" exists\n");
+ else
+ printf_filtered (" faked for \"readnow\"\n");
+ printf_filtered ("\n");
+}
+
+static void
+dw2_debug_names_expand_symtabs_for_function (struct objfile *objfile,
+ const char *func_name)
+{
+ dw2_setup (objfile);
+
+ /* dwarf2_per_objfile->debug_names_table is NULL if OBJF_READNOW. */
+ if (dwarf2_per_objfile->debug_names_table)
+ {
+ const mapped_debug_names &map = *dwarf2_per_objfile->debug_names_table;
+
+ /* Note: It doesn't matter what we pass for block_index here. */
+ dw2_debug_names_iterator iter (map, false /* want_specific_block */,
+ GLOBAL_BLOCK, VAR_DOMAIN, func_name);
+
+ struct dwarf2_per_cu_data *per_cu;
+ while ((per_cu = iter.next ()) != NULL)
+ dw2_instantiate_symtab (per_cu);
+ }
+}
+
+static void
+dw2_debug_names_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)
+{
+ dw2_setup (objfile);
+
+ /* debug_names_table is NULL if OBJF_READNOW. */
+ if (!dwarf2_per_objfile->debug_names_table)
+ return;
+
+ dw_expand_symtabs_matching_file_matcher (file_matcher);
+
+ mapped_debug_names &map = *dwarf2_per_objfile->debug_names_table;
+
+ dw2_expand_symtabs_matching_symbol (map, lookup_name,
+ symbol_matcher,
+ kind, [&] (offset_type namei)
+ {
+ /* The name was matched, now expand corresponding CUs that were
+ marked. */
+ dw2_debug_names_iterator iter (map, kind, namei);
+
+ struct dwarf2_per_cu_data *per_cu;
+ while ((per_cu = iter.next ()) != NULL)
+ dw2_expand_symtabs_matching_one (per_cu, file_matcher,
+ expansion_notify);
+ });
+}
+
+const struct quick_symbol_functions dwarf2_debug_names_functions =
{
dw2_has_symbols,
dw2_find_last_source_symtab,
dw2_forget_cached_source_info,
dw2_map_symtabs_matching_filename,
- dw2_lookup_symbol,
+ dw2_debug_names_lookup_symbol,
dw2_print_stats,
- dw2_dump,
+ dw2_debug_names_dump,
dw2_relocate,
- dw2_expand_symtabs_for_function,
+ dw2_debug_names_expand_symtabs_for_function,
dw2_expand_all_symtabs,
dw2_expand_symtabs_with_fullname,
dw2_map_matching_symbols,
- dw2_expand_symtabs_matching,
+ dw2_debug_names_expand_symtabs_matching,
dw2_find_pc_sect_compunit_symtab,
+ NULL,
dw2_map_symbol_filenames
};
-/* Initialize for reading DWARF for this objfile. Return 0 if this
- file will use psymtabs, or 1 if using the GNU index. */
+/* See symfile.h. */
-int
-dwarf2_initialize_objfile (struct objfile *objfile)
+bool
+dwarf2_initialize_objfile (struct objfile *objfile, dw_index_kind *index_kind)
{
/* If we're about to read full symbols, don't bother with the
indices. In this case we also don't care if some other debug
/* Return 1 so that gdb sees the "quick" functions. However,
these functions will be no-ops because we will have expanded
all symtabs. */
- return 1;
+ *index_kind = dw_index_kind::GDB_INDEX;
+ return true;
+ }
+
+ if (dwarf2_read_debug_names (objfile))
+ {
+ *index_kind = dw_index_kind::DEBUG_NAMES;
+ return true;
}
if (dwarf2_read_index (objfile))
- return 1;
+ {
+ *index_kind = dw_index_kind::GDB_INDEX;
+ return true;
+ }
- return 0;
+ return false;
}
\f
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
{
/* This isn't really ideal: all the data we allocate on the
objfile's obstack is still uselessly kept around. However,
freeing it seems unsafe. */
- struct cleanup *cleanups = make_cleanup_discard_psymtabs (objfile);
-
+ psymtab_discarder psymtabs (objfile);
dwarf2_build_psymtabs_hard (objfile);
- discard_cleanups (cleanups);
+ psymtabs.keep ();
}
CATCH (except, RETURN_MASK_ERROR)
{
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
}
/* Read in the comp unit header information from the debug_info at info_ptr.
+ Use rcuh_kind::COMPILE as the default type if not known by the caller.
NOTE: This leaves members offset, first_die_offset to be filled in
by the caller. */
static const gdb_byte *
read_comp_unit_head (struct comp_unit_head *cu_header,
- const gdb_byte *info_ptr, bfd *abfd)
+ const gdb_byte *info_ptr,
+ struct dwarf2_section_info *section,
+ rcuh_kind section_kind)
{
int signed_addr;
unsigned int bytes_read;
+ const char *filename = get_section_file_name (section);
+ bfd *abfd = get_section_bfd_owner (section);
cu_header->length = read_initial_length (abfd, info_ptr, &bytes_read);
cu_header->initial_length_size = bytes_read;
info_ptr += bytes_read;
cu_header->version = read_2_bytes (abfd, info_ptr);
info_ptr += 2;
- cu_header->abbrev_offset.sect_off = read_offset (abfd, info_ptr, cu_header,
- &bytes_read);
+ if (cu_header->version < 5)
+ switch (section_kind)
+ {
+ case rcuh_kind::COMPILE:
+ cu_header->unit_type = DW_UT_compile;
+ break;
+ case rcuh_kind::TYPE:
+ cu_header->unit_type = DW_UT_type;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("read_comp_unit_head: invalid section_kind"));
+ }
+ else
+ {
+ cu_header->unit_type = static_cast<enum dwarf_unit_type>
+ (read_1_byte (abfd, info_ptr));
+ info_ptr += 1;
+ switch (cu_header->unit_type)
+ {
+ case DW_UT_compile:
+ if (section_kind != rcuh_kind::COMPILE)
+ error (_("Dwarf Error: wrong unit_type in compilation unit header "
+ "(is DW_UT_compile, should be DW_UT_type) [in module %s]"),
+ filename);
+ break;
+ case DW_UT_type:
+ section_kind = rcuh_kind::TYPE;
+ break;
+ default:
+ error (_("Dwarf Error: wrong unit_type in compilation unit header "
+ "(is %d, should be %d or %d) [in module %s]"),
+ cu_header->unit_type, DW_UT_compile, DW_UT_type, filename);
+ }
+
+ cu_header->addr_size = read_1_byte (abfd, info_ptr);
+ info_ptr += 1;
+ }
+ cu_header->abbrev_sect_off = (sect_offset) read_offset (abfd, info_ptr,
+ cu_header,
+ &bytes_read);
info_ptr += bytes_read;
- cu_header->addr_size = read_1_byte (abfd, info_ptr);
- info_ptr += 1;
+ if (cu_header->version < 5)
+ {
+ cu_header->addr_size = read_1_byte (abfd, info_ptr);
+ info_ptr += 1;
+ }
signed_addr = bfd_get_sign_extend_vma (abfd);
if (signed_addr < 0)
internal_error (__FILE__, __LINE__,
_("read_comp_unit_head: dwarf from non elf file"));
cu_header->signed_addr_p = signed_addr;
+ if (section_kind == rcuh_kind::TYPE)
+ {
+ LONGEST type_offset;
+
+ cu_header->signature = read_8_bytes (abfd, info_ptr);
+ info_ptr += 8;
+
+ type_offset = read_offset (abfd, info_ptr, cu_header, &bytes_read);
+ info_ptr += bytes_read;
+ 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);
+ }
+
return info_ptr;
}
{
const char *filename = get_section_file_name (section);
- if (header->version != 2 && header->version != 3 && header->version != 4)
+ if (header->version < 2 || header->version > 5)
error (_("Dwarf Error: wrong version in compilation unit header "
- "(is %d, should be 2, 3, or 4) [in module %s]"), header->version,
+ "(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);
}
struct dwarf2_section_info *section,
struct dwarf2_section_info *abbrev_section,
const gdb_byte *info_ptr,
- int is_debug_types_section)
-{
- 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;
-
- info_ptr = read_comp_unit_head (header, info_ptr, abfd);
-
- /* If we're reading a type unit, skip over the signature and
- type_offset fields. */
- if (is_debug_types_section)
- info_ptr += 8 /*signature*/ + header->offset_size;
-
- header->first_die_offset.cu_off = info_ptr - beg_of_comp_unit;
-
- error_check_comp_unit_head (header, section, abbrev_section);
-
- return info_ptr;
-}
-
-/* Read in the types comp unit header information from .debug_types entry at
- types_ptr. The result is a pointer to one past the end of the header. */
-
-static const gdb_byte *
-read_and_check_type_unit_head (struct comp_unit_head *header,
- struct dwarf2_section_info *section,
- struct dwarf2_section_info *abbrev_section,
- const gdb_byte *info_ptr,
- ULONGEST *signature,
- cu_offset *type_offset_in_tu)
+ 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, abfd);
+ info_ptr = read_comp_unit_head (header, info_ptr, section, section_kind);
- /* If we're reading a type unit, skip over the signature and
- type_offset fields. */
- if (signature != NULL)
- *signature = read_8_bytes (abfd, info_ptr);
- info_ptr += 8;
- if (type_offset_in_tu != NULL)
- type_offset_in_tu->cu_off = read_offset_1 (abfd, info_ptr,
- header->offset_size);
- info_ptr += header->offset_size;
-
- 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 + 2 /*version*/;
- abbrev_offset.sect_off = read_offset_1 (abfd, info_ptr, offset_size);
- return abbrev_offset;
+ info_ptr += initial_length_size;
+
+ version = read_2_bytes (abfd, info_ptr);
+ info_ptr += 2;
+ if (version >= 5)
+ {
+ /* Skip unit type and address size. */
+ info_ptr += 2;
+ }
+
+ return (sect_offset) read_offset_1 (abfd, info_ptr, offset_size);
}
/* Allocate a new partial symtab for file named NAME and mark this new
struct die_info *die,
struct partial_symtab *pst)
{
- struct line_header *lh = NULL;
+ line_header_up lh;
struct attribute *attr;
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. */
/* NOTE: pst->dirname is DW_AT_comp_dir (if present). */
- dwarf_decode_lines (lh, pst->dirname, cu, pst, pst->textlow, 1);
-
- free_line_header (lh);
+ dwarf_decode_lines (lh.get (), pst->dirname, cu, pst, pst->textlow, 1);
}
static hashval_t
return 1;
}
-/* Create the hash table of all entries in the .debug_types
- (or .debug_types.dwo) section(s).
- If reading a DWO file, then DWO_FILE is a pointer to the DWO file object,
- otherwise it is NULL.
-
- The result is a pointer to the hash table or NULL if there are no types.
-
- Note: This function processes DWO files only, not DWP files. */
+/* A helper for create_debug_types_hash_table. Read types from SECTION
+ and fill them into TYPES_HTAB. It will process only type units,
+ therefore DW_UT_type. */
-static htab_t
-create_debug_types_hash_table (struct dwo_file *dwo_file,
- VEC (dwarf2_section_info_def) *types)
+static void
+create_debug_type_hash_table (struct dwo_file *dwo_file,
+ dwarf2_section_info *section, htab_t &types_htab,
+ rcuh_kind section_kind)
{
struct objfile *objfile = dwarf2_per_objfile->objfile;
- htab_t types_htab = NULL;
- int ix;
- struct dwarf2_section_info *section;
struct dwarf2_section_info *abbrev_section;
-
- if (VEC_empty (dwarf2_section_info_def, types))
- return NULL;
+ bfd *abfd;
+ const gdb_byte *info_ptr, *end_ptr;
abbrev_section = (dwo_file != NULL
? &dwo_file->sections.abbrev
: &dwarf2_per_objfile->abbrev);
if (dwarf_read_debug)
- fprintf_unfiltered (gdb_stdlog, "Reading .debug_types%s for %s:\n",
- dwo_file ? ".dwo" : "",
+ fprintf_unfiltered (gdb_stdlog, "Reading %s for %s:\n",
+ get_section_name (section),
get_section_file_name (abbrev_section));
- for (ix = 0;
- VEC_iterate (dwarf2_section_info_def, types, ix, section);
- ++ix)
- {
- bfd *abfd;
- const gdb_byte *info_ptr, *end_ptr;
+ dwarf2_read_section (objfile, section);
+ info_ptr = section->buffer;
- dwarf2_read_section (objfile, section);
- info_ptr = section->buffer;
+ if (info_ptr == NULL)
+ return;
- if (info_ptr == NULL)
- continue;
+ /* We can't set abfd until now because the section may be empty or
+ not present, in which case the bfd is unknown. */
+ abfd = get_section_bfd_owner (section);
- /* We can't set abfd until now because the section may be empty or
- not present, in which case the bfd is unknown. */
- abfd = get_section_bfd_owner (section);
+ /* We don't use init_cutu_and_read_dies_simple, or some such, here
+ because we don't need to read any dies: the signature is in the
+ header. */
- /* We don't use init_cutu_and_read_dies_simple, or some such, here
- because we don't need to read any dies: the signature is in the
- header. */
+ end_ptr = info_ptr + section->size;
+ while (info_ptr < end_ptr)
+ {
+ struct signatured_type *sig_type;
+ struct dwo_unit *dwo_tu;
+ void **slot;
+ const gdb_byte *ptr = info_ptr;
+ struct comp_unit_head header;
+ unsigned int length;
- end_ptr = info_ptr + section->size;
- while (info_ptr < end_ptr)
- {
- sect_offset offset;
- cu_offset type_offset_in_tu;
- ULONGEST signature;
- struct signatured_type *sig_type;
- struct dwo_unit *dwo_tu;
- void **slot;
- const gdb_byte *ptr = info_ptr;
- struct comp_unit_head header;
- unsigned int length;
+ sect_offset sect_off = (sect_offset) (ptr - section->buffer);
- offset.sect_off = ptr - section->buffer;
+ /* Initialize it due to a false compiler warning. */
+ header.signature = -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. */
+ /* We need to read the type's signature in order to build the hash
+ table, but we don't need anything else just yet. */
- ptr = read_and_check_type_unit_head (&header, section,
- abbrev_section, ptr,
- &signature, &type_offset_in_tu);
+ ptr = read_and_check_comp_unit_head (&header, section,
+ abbrev_section, ptr, section_kind);
- length = get_cu_length (&header);
+ length = get_cu_length (&header);
- /* Skip dummy type units. */
- if (ptr >= info_ptr + length
- || peek_abbrev_code (abfd, ptr) == 0)
- {
- info_ptr += length;
- continue;
- }
+ /* Skip dummy type units. */
+ if (ptr >= info_ptr + length
+ || peek_abbrev_code (abfd, ptr) == 0
+ || header.unit_type != DW_UT_type)
+ {
+ info_ptr += length;
+ continue;
+ }
- if (types_htab == NULL)
- {
- if (dwo_file)
- types_htab = allocate_dwo_unit_table (objfile);
- else
- types_htab = allocate_signatured_type_table (objfile);
- }
+ if (types_htab == NULL)
+ {
+ if (dwo_file)
+ types_htab = allocate_dwo_unit_table (objfile);
+ else
+ types_htab = allocate_signatured_type_table (objfile);
+ }
+
+ if (dwo_file)
+ {
+ sig_type = NULL;
+ dwo_tu = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+ struct dwo_unit);
+ dwo_tu->dwo_file = dwo_file;
+ dwo_tu->signature = header.signature;
+ dwo_tu->type_offset_in_tu = header.type_cu_offset_in_tu;
+ dwo_tu->section = section;
+ dwo_tu->sect_off = sect_off;
+ dwo_tu->length = length;
+ }
+ else
+ {
+ /* N.B.: type_offset is not usable if this type uses a DWO file.
+ The real type_offset is in the DWO file. */
+ dwo_tu = NULL;
+ sig_type = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+ struct signatured_type);
+ sig_type->signature = header.signature;
+ 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.sect_off = sect_off;
+ sig_type->per_cu.length = length;
+ }
+
+ slot = htab_find_slot (types_htab,
+ dwo_file ? (void*) dwo_tu : (void *) sig_type,
+ INSERT);
+ gdb_assert (slot != NULL);
+ if (*slot != NULL)
+ {
+ sect_offset dup_sect_off;
if (dwo_file)
{
- sig_type = NULL;
- dwo_tu = OBSTACK_ZALLOC (&objfile->objfile_obstack,
- struct dwo_unit);
- dwo_tu->dwo_file = dwo_file;
- dwo_tu->signature = signature;
- dwo_tu->type_offset_in_tu = type_offset_in_tu;
- dwo_tu->section = section;
- dwo_tu->offset = offset;
- dwo_tu->length = length;
+ const struct dwo_unit *dup_tu
+ = (const struct dwo_unit *) *slot;
+
+ dup_sect_off = dup_tu->sect_off;
}
else
{
- /* N.B.: type_offset is not usable if this type uses a DWO file.
- The real type_offset is in the DWO file. */
- dwo_tu = NULL;
- sig_type = OBSTACK_ZALLOC (&objfile->objfile_obstack,
- struct signatured_type);
- sig_type->signature = signature;
- sig_type->type_offset_in_tu = type_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.length = length;
+ const struct signatured_type *dup_tu
+ = (const struct signatured_type *) *slot;
+
+ dup_sect_off = dup_tu->per_cu.sect_off;
}
- slot = htab_find_slot (types_htab,
- dwo_file ? (void*) dwo_tu : (void *) sig_type,
- INSERT);
- gdb_assert (slot != NULL);
- if (*slot != NULL)
- {
- sect_offset dup_offset;
+ complaint (&symfile_complaints,
+ _("debug type 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 (header.signature));
+ }
+ *slot = dwo_file ? (void *) dwo_tu : (void *) sig_type;
- if (dwo_file)
- {
- const struct dwo_unit *dup_tu
- = (const struct dwo_unit *) *slot;
+ if (dwarf_read_debug > 1)
+ fprintf_unfiltered (gdb_stdlog, " offset 0x%x, signature %s\n",
+ to_underlying (sect_off),
+ hex_string (header.signature));
- dup_offset = dup_tu->offset;
- }
- else
- {
- const struct signatured_type *dup_tu
- = (const struct signatured_type *) *slot;
+ info_ptr += length;
+ }
+}
- dup_offset = dup_tu->per_cu.offset;
- }
+/* Create the hash table of all entries in the .debug_types
+ (or .debug_types.dwo) section(s).
+ If reading a DWO file, then DWO_FILE is a pointer to the DWO file object,
+ otherwise it is NULL.
- 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,
- hex_string (signature));
- }
- *slot = dwo_file ? (void *) dwo_tu : (void *) sig_type;
+ The result is a pointer to the hash table or NULL if there are no types.
+
+ Note: This function processes DWO files only, not DWP files. */
- if (dwarf_read_debug > 1)
- fprintf_unfiltered (gdb_stdlog, " offset 0x%x, signature %s\n",
- offset.sect_off,
- hex_string (signature));
+static void
+create_debug_types_hash_table (struct dwo_file *dwo_file,
+ VEC (dwarf2_section_info_def) *types,
+ htab_t &types_htab)
+{
+ int ix;
+ struct dwarf2_section_info *section;
- info_ptr += length;
- }
- }
+ if (VEC_empty (dwarf2_section_info_def, types))
+ return;
- return types_htab;
+ for (ix = 0;
+ VEC_iterate (dwarf2_section_info_def, types, ix, section);
+ ++ix)
+ create_debug_type_hash_table (dwo_file, section, types_htab,
+ rcuh_kind::TYPE);
}
/* Create the hash table of all entries in the .debug_types section,
static int
create_all_type_units (struct objfile *objfile)
{
- htab_t types_htab;
+ htab_t types_htab = NULL;
struct signatured_type **iter;
- types_htab = create_debug_types_hash_table (NULL, dwarf2_per_objfile->types);
+ create_debug_type_hash_table (NULL, &dwarf2_per_objfile->info, types_htab,
+ rcuh_kind::COMPILE);
+ create_debug_types_hash_table (NULL, dwarf2_per_objfile->types, types_htab);
if (types_htab == NULL)
{
dwarf2_per_objfile->signatured_types = NULL;
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);
if (this_cu->is_debug_types)
{
- ULONGEST header_signature;
- cu_offset type_offset_in_tu;
struct signatured_type *sig_type = (struct signatured_type *) this_cu;
- info_ptr = read_and_check_type_unit_head (&cu->header, section,
+ info_ptr = read_and_check_comp_unit_head (&cu->header, section,
dwo_abbrev_section,
- info_ptr,
- &header_signature,
- &type_offset_in_tu);
+ info_ptr, rcuh_kind::TYPE);
/* This is not an assert because it can be caused by bad debug info. */
- if (sig_type->signature != header_signature)
+ if (sig_type->signature != cu->header.signature)
{
error (_("Dwarf Error: signature mismatch %s vs %s while reading"
" TU at offset 0x%x [in module %s]"),
hex_string (sig_type->signature),
- hex_string (header_signature),
- dwo_unit->offset.sect_off,
+ hex_string (cu->header.signature),
+ 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 = 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, 0);
- gdb_assert (dwo_unit->offset.sect_off == cu->header.offset.sect_off);
+ info_ptr, rcuh_kind::COMPILE);
+ 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
{
if (this_cu->is_debug_types)
{
- ULONGEST signature;
- cu_offset type_offset_in_tu;
-
- info_ptr = read_and_check_type_unit_head (&cu->header, section,
+ info_ptr = read_and_check_comp_unit_head (&cu->header, section,
abbrev_section, info_ptr,
- &signature,
- &type_offset_in_tu);
+ rcuh_kind::TYPE);
/* Since per_cu is the first member of struct signatured_type,
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 == signature);
- gdb_assert (sig_type->type_offset_in_tu.cu_off
- == type_offset_in_tu.cu_off);
- gdb_assert (this_cu->offset.sect_off == cu->header.offset.sect_off);
+ gdb_assert (sig_type->signature == cu->header.signature);
+ 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;
}
else
{
info_ptr = read_and_check_comp_unit_head (&cu->header, section,
abbrev_section,
- info_ptr, 0);
+ 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);
+ (this_cu->is_debug_types
+ ? rcuh_kind::TYPE
+ : rcuh_kind::COMPILE));
this_cu->length = get_cu_length (&cu.header);
}
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,
info_ptr += 1;
break;
case DW_FORM_flag_present:
+ case DW_FORM_implicit_const:
break;
case DW_FORM_data2:
case DW_FORM_ref2:
case DW_FORM_ref_sig8:
info_ptr += 8;
break;
+ case DW_FORM_data16:
+ info_ptr += 16;
+ break;
case DW_FORM_string:
read_direct_string (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
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)
{
case DW_TAG_catch_block:
read_lexical_block_scope (die, cu);
break;
+ case DW_TAG_call_site:
case DW_TAG_GNU_call_site:
read_call_site_scope (die, cu);
break;
case DW_TAG_pointer_type:
case DW_TAG_ptr_to_member_type:
case DW_TAG_reference_type:
+ case DW_TAG_rvalue_reference_type:
case DW_TAG_string_type:
break;
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. */
}
}
-/* Retrieve the last character from a mem_file. */
+/* 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 void
-do_ui_file_peek_last (void *object, const char *buffer, long length)
+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)
{
- char *last_char_p = (char *) object;
+ const char *linkage_name;
- if (length > 0)
- *last_char_p = buffer[length - 1];
+ 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,
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;
- struct ui_file *buf;
const char *canonical_name = NULL;
+ string_file buf;
+
prefix = determine_prefix (die, cu);
- buf = mem_fileopen ();
if (*prefix != '\0')
{
char *prefixed_name = typename_concat (NULL, prefix, name,
physname, cu);
- fputs_unfiltered (prefixed_name, buf);
+ buf.puts (prefixed_name);
xfree (prefixed_name);
}
else
- fputs_unfiltered (name, buf);
+ buf.puts (name);
/* Template parameters may be specified in the DIE's DW_AT_name, or
as children with DW_TAG_template_type_param or
if (first)
{
- fputs_unfiltered ("<", buf);
+ buf.puts ("<");
first = 0;
}
else
- fputs_unfiltered (", ", buf);
+ buf.puts (", ");
attr = dwarf2_attr (child, DW_AT_type, cu);
if (attr == NULL)
{
complaint (&symfile_complaints,
_("template parameter missing DW_AT_type"));
- fputs_unfiltered ("UNKNOWN_TYPE", buf);
+ buf.puts ("UNKNOWN_TYPE");
continue;
}
type = die_type (child, cu);
if (child->tag == DW_TAG_template_type_param)
{
- c_print_type (type, "", buf, -1, 0, &type_print_raw_options);
+ c_print_type (type, "", &buf, -1, 0, &type_print_raw_options);
continue;
}
complaint (&symfile_complaints,
_("template parameter missing "
"DW_AT_const_value"));
- fputs_unfiltered ("UNKNOWN_VALUE", buf);
+ buf.puts ("UNKNOWN_VALUE");
continue;
}
if (TYPE_NOSIGN (type))
/* GDB prints characters as NUMBER 'CHAR'. If that's
changed, this can use value_print instead. */
- c_printchar (value, type, buf);
+ c_printchar (value, type, &buf);
else
{
struct value_print_options opts;
the radix. */
get_formatted_print_options (&opts, 'd');
opts.raw = 1;
- value_print (v, buf, &opts);
+ value_print (v, &buf, &opts);
release_value (v);
value_free (v);
}
{
/* Close the argument list, with a space if necessary
(nested templates). */
- char last_char = '\0';
- ui_file_put (buf, do_ui_file_peek_last, &last_char);
- if (last_char == '>')
- fputs_unfiltered (" >", buf);
+ if (!buf.empty () && buf.string ().back () == '>')
+ buf.puts (" >");
else
- fputs_unfiltered (">", buf);
+ buf.puts (">");
}
}
{
struct type *type = read_type_die (die, cu);
- c_type_print_args (type, buf, 1, cu->language,
+ c_type_print_args (type, &buf, 1, cu->language,
&type_print_raw_options);
if (cu->language == language_cplus)
&& TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) == TYPE_CODE_PTR
&& TYPE_CONST (TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type,
0))))
- fputs_unfiltered (" const", buf);
+ buf.puts (" const");
}
}
- std::string intermediate_name = ui_file_as_string (buf);
- ui_file_delete (buf);
+ const std::string &intermediate_name = buf.string ();
if (cu->language == language_cplus)
canonical_name
{
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);
}
-/* Cleanup function for handle_DW_AT_stmt_list. */
+/* 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 void
-free_cu_line_header (void *arg)
+static int
+producer_is_icc_lt_14 (struct dwarf2_cu *cu)
{
- struct dwarf2_cu *cu = (struct dwarf2_cu *) arg;
+ if (!cu->checked_producer)
+ check_producer (cu);
- free_line_header (cu->line_header);
- cu->line_header = NULL;
+ return cu->producer_is_icc_lt_14;
}
/* Check for possibly missing DW_AT_comp_dir with relative .debug_line
return cu->producer_is_gcc_lt_4_3;
}
-static void
-find_file_and_directory (struct die_info *die, struct dwarf2_cu *cu,
- const char **name, const char **comp_dir)
+static file_and_directory
+find_file_and_directory (struct die_info *die, struct dwarf2_cu *cu)
{
+ file_and_directory res;
+
/* Find the filename. Do not use dwarf2_name here, since the filename
is not a source language identifier. */
- *name = dwarf2_string_attr (die, DW_AT_name, cu);
- *comp_dir = dwarf2_string_attr (die, DW_AT_comp_dir, cu);
+ res.name = dwarf2_string_attr (die, DW_AT_name, cu);
+ res.comp_dir = dwarf2_string_attr (die, DW_AT_comp_dir, cu);
- if (*comp_dir == NULL
- && producer_is_gcc_lt_4_3 (cu) && *name != NULL
- && IS_ABSOLUTE_PATH (*name))
+ if (res.comp_dir == NULL
+ && producer_is_gcc_lt_4_3 (cu) && res.name != NULL
+ && IS_ABSOLUTE_PATH (res.name))
{
- char *d = ldirname (*name);
-
- *comp_dir = d;
- if (d != NULL)
- make_cleanup (xfree, d);
+ res.comp_dir_storage = ldirname (res.name);
+ if (!res.comp_dir_storage.empty ())
+ res.comp_dir = res.comp_dir_storage.c_str ();
}
- if (*comp_dir != NULL)
+ if (res.comp_dir != NULL)
{
/* Irix 6.2 native cc prepends <machine>.: to the compilation
directory, get rid of it. */
- const char *cp = strchr (*comp_dir, ':');
+ const char *cp = strchr (res.comp_dir, ':');
- if (cp && cp != *comp_dir && cp[-1] == '.' && cp[1] == '/')
- *comp_dir = cp + 1;
+ if (cp && cp != res.comp_dir && cp[-1] == '.' && cp[1] == '/')
+ res.comp_dir = cp + 1;
}
- if (*name == NULL)
- *name = "<unknown>";
+ if (res.name == NULL)
+ res.name = "<unknown>";
+
+ return res;
}
/* Handle DW_AT_stmt_list for a compilation unit.
{
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)
/* dwarf_decode_line_header does not yet provide sufficient information.
We always have to call also dwarf_decode_lines for it. */
- cu->line_header = dwarf_decode_line_header (line_offset, cu);
- if (cu->line_header == NULL)
+ line_header_up lh = dwarf_decode_line_header (line_offset, cu);
+ if (lh == NULL)
return;
+ cu->line_header = lh.release ();
+ cu->line_header_die_owner = die;
+
if (dwarf2_per_objfile->line_header_hash == NULL)
slot = NULL;
else
/* 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
{
number information unit. And if we're not using line_header_hash
then this is what we want as well. */
gdb_assert (die->tag != DW_TAG_partial_unit);
- make_cleanup (free_cu_line_header, cu);
}
decode_mapping = (die->tag != DW_TAG_partial_unit);
dwarf_decode_lines (cu->line_header, comp_dir, cu, NULL, lowpc,
decode_mapping);
+
}
/* Process DW_TAG_compile_unit or DW_TAG_partial_unit. */
{
struct objfile *objfile = dwarf2_per_objfile->objfile;
struct gdbarch *gdbarch = get_objfile_arch (objfile);
- struct cleanup *back_to = make_cleanup (null_cleanup, 0);
CORE_ADDR lowpc = ((CORE_ADDR) -1);
CORE_ADDR highpc = ((CORE_ADDR) 0);
struct attribute *attr;
- const char *name = NULL;
- const char *comp_dir = NULL;
struct die_info *child_die;
CORE_ADDR baseaddr;
lowpc = highpc;
lowpc = gdbarch_adjust_dwarf2_addr (gdbarch, lowpc + baseaddr);
- find_file_and_directory (die, cu, &name, &comp_dir);
+ file_and_directory fnd = find_file_and_directory (die, cu);
prepare_one_comp_unit (cu, die, cu->language);
if (cu->producer && strstr (cu->producer, "GNU Go ") != NULL)
set_cu_language (DW_LANG_Go, cu);
- dwarf2_start_symtab (cu, name, comp_dir, lowpc);
+ dwarf2_start_symtab (cu, fnd.name, fnd.comp_dir, lowpc);
/* Decode line number information if present. We do this before
processing child DIEs, so that the line header table is available
for DW_AT_decl_file. */
- handle_DW_AT_stmt_list (die, cu, comp_dir, lowpc);
+ handle_DW_AT_stmt_list (die, cu, fnd.comp_dir, lowpc);
/* Process all dies in compilation unit. */
if (die->child != NULL)
refers to information in the line number info statement program
header, so we can only read it if we've read the header
successfully. */
- attr = dwarf2_attr (die, DW_AT_GNU_macros, cu);
+ attr = dwarf2_attr (die, DW_AT_macros, cu);
+ if (attr == NULL)
+ attr = dwarf2_attr (die, DW_AT_GNU_macros, cu);
if (attr && cu->line_header)
{
if (dwarf2_attr (die, DW_AT_macro_info, cu))
complaint (&symfile_complaints,
- _("CU refers to both DW_AT_GNU_macros and DW_AT_macro_info"));
+ _("CU refers to both DW_AT_macros and DW_AT_macro_info"));
dwarf_decode_macros (cu, DW_UNSND (attr), 1);
}
dwarf_decode_macros (cu, macro_offset, 0);
}
}
-
- do_cleanups (back_to);
}
/* TU version of handle_DW_AT_stmt_list for read_type_unit_scope.
struct dwarf2_per_cu_data *per_cu = cu->per_cu;
struct type_unit_group *tu_group;
int first_time;
- struct line_header *lh;
struct attribute *attr;
- unsigned int i, line_offset;
+ unsigned int i;
struct signatured_type *sig_type;
gdb_assert (per_cu->is_debug_types);
/* We have to handle the case of both a missing DW_AT_stmt_list or bad
debug info. */
- lh = NULL;
+ 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;
- make_cleanup (free_cu_line_header, cu);
+ 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->num_file_names;
- tu_group->symtabs = XNEWVEC (struct symtab *, lh->num_file_names);
+ 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->num_file_names; ++i)
+ for (i = 0; i < cu->line_header->file_names.size (); ++i)
{
- const char *dir = NULL;
- struct file_entry *fe = &lh->file_names[i];
+ file_entry &fe = cu->line_header->file_names[i];
- if (fe->dir_index && lh->include_dirs != NULL)
- dir = lh->include_dirs[fe->dir_index - 1];
- dwarf2_start_subfile (fe->name, dir);
+ 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);
}
- fe->symtab = current_subfile->symtab;
- tu_group->symtabs[i] = fe->symtab;
+ fe.symtab = current_subfile->symtab;
+ tu_group->symtabs[i] = fe.symtab;
}
}
else
{
restart_symtab (tu_group->compunit_symtab, "", 0);
- for (i = 0; i < lh->num_file_names; ++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];
}
}
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;
+
+ // If the unit could not be parsed, skip it.
+ if (create_dwo_cu_data.dwo_unit.dwo_file == NULL)
+ continue;
- init_cutu_and_read_dies_no_follow (&per_cu, dwo_file,
- create_dwo_cu_reader,
- &create_dwo_cu_data);
+ if (cus_htab == NULL)
+ cus_htab = allocate_dwo_unit_table (objfile);
- if (create_dwo_cu_data.dwo_unit.dwo_file != NULL)
+ dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
+ *dwo_unit = create_dwo_cu_data.dwo_unit;
+ slot = htab_find_slot (cus_htab, dwo_unit, INSERT);
+ gdb_assert (slot != NULL);
+ if (*slot != NULL)
{
- /* If we've already found one, complain. We only support one
- because having more than one requires hacking the dwo_name of
- each to match, which is highly unlikely to happen. */
- if (dwo_unit != NULL)
- {
- complaint (&symfile_complaints,
- _("Multiple CUs in DWO file %s [in module %s]"),
- dwo_file->dwo_name, objfile_name (objfile));
- break;
- }
+ const struct dwo_unit *dup_cu = (const struct dwo_unit *)*slot;
+ sect_offset dup_sect_off = dup_cu->sect_off;
- dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
- *dwo_unit = create_dwo_cu_data.dwo_unit;
+ complaint (&symfile_complaints,
+ _("debug cu entry at offset 0x%x is duplicate to"
+ " the entry at offset 0x%x, signature %s"),
+ to_underlying (sect_off), to_underlying (dup_sect_off),
+ hex_string (dwo_unit->signature));
}
-
- info_ptr += per_cu.length;
+ *slot = (void *)dwo_unit;
}
-
- return dwo_unit;
}
/* DWP file .debug_{cu,tu}_index section format:
struct dwo_unit *dwo_unit;
struct virtual_v1_dwo_sections sections;
void **dwo_file_slot;
- char *virtual_dwo_name;
- struct cleanup *cleanups;
int i;
gdb_assert (dwp_file->version == 1);
+ 1 /* trailing zero */)
memset (§ions, 0, sizeof (sections));
- cleanups = make_cleanup (null_cleanup, 0);
for (i = 0; i < MAX_NR_V1_DWO_SECTIONS; ++i)
{
(fewer struct dwo_file objects to allocate). Remember that for really
large apps there can be on the order of 8K CUs and 200K TUs, or more. */
- virtual_dwo_name =
- xstrprintf ("virtual-dwo/%d-%d-%d-%d",
- get_section_id (§ions.abbrev),
- get_section_id (§ions.line),
- get_section_id (§ions.loc),
- get_section_id (§ions.str_offsets));
- make_cleanup (xfree, virtual_dwo_name);
+ std::string virtual_dwo_name =
+ string_printf ("virtual-dwo/%d-%d-%d-%d",
+ get_section_id (§ions.abbrev),
+ get_section_id (§ions.line),
+ get_section_id (§ions.loc),
+ get_section_id (§ions.str_offsets));
/* Can we use an existing virtual DWO file? */
- dwo_file_slot = lookup_dwo_file_slot (virtual_dwo_name, comp_dir);
+ dwo_file_slot = lookup_dwo_file_slot (virtual_dwo_name.c_str (), comp_dir);
/* Create one if necessary. */
if (*dwo_file_slot == NULL)
{
if (dwarf_read_debug)
{
fprintf_unfiltered (gdb_stdlog, "Creating virtual DWO: %s\n",
- virtual_dwo_name);
+ virtual_dwo_name.c_str ());
}
dwo_file = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_file);
dwo_file->dwo_name
= (const char *) obstack_copy0 (&objfile->objfile_obstack,
- virtual_dwo_name,
- strlen (virtual_dwo_name));
+ virtual_dwo_name.c_str (),
+ virtual_dwo_name.size ());
dwo_file->comp_dir = comp_dir;
dwo_file->sections.abbrev = sections.abbrev;
dwo_file->sections.line = sections.line;
if (dwarf_read_debug)
{
fprintf_unfiltered (gdb_stdlog, "Using existing virtual DWO: %s\n",
- virtual_dwo_name);
+ virtual_dwo_name.c_str ());
}
dwo_file = (struct dwo_file *) *dwo_file_slot;
}
- do_cleanups (cleanups);
dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
dwo_unit->dwo_file = dwo_file;
if (sectp == NULL
|| offset + size > bfd_get_section_size (sectp))
{
- bfd *abfd = sectp->owner;
-
error (_("Dwarf Error: Bad DWP V2 section info, doesn't fit"
" in section %s [in module %s]"),
sectp ? bfd_section_name (abfd, sectp) : "<unknown>",
struct dwo_unit *dwo_unit;
struct virtual_v2_dwo_sections sections;
void **dwo_file_slot;
- char *virtual_dwo_name;
- struct cleanup *cleanups;
int i;
gdb_assert (dwp_file->version == 2);
/* Fetch the section offsets of this DWO unit. */
memset (§ions, 0, sizeof (sections));
- cleanups = make_cleanup (null_cleanup, 0);
for (i = 0; i < dwp_htab->nr_columns; ++i)
{
(fewer struct dwo_file objects to allocate). Remember that for really
large apps there can be on the order of 8K CUs and 200K TUs, or more. */
- virtual_dwo_name =
- xstrprintf ("virtual-dwo/%ld-%ld-%ld-%ld",
- (long) (sections.abbrev_size ? sections.abbrev_offset : 0),
- (long) (sections.line_size ? sections.line_offset : 0),
- (long) (sections.loc_size ? sections.loc_offset : 0),
- (long) (sections.str_offsets_size
- ? sections.str_offsets_offset : 0));
- make_cleanup (xfree, virtual_dwo_name);
+ std::string virtual_dwo_name =
+ string_printf ("virtual-dwo/%ld-%ld-%ld-%ld",
+ (long) (sections.abbrev_size ? sections.abbrev_offset : 0),
+ (long) (sections.line_size ? sections.line_offset : 0),
+ (long) (sections.loc_size ? sections.loc_offset : 0),
+ (long) (sections.str_offsets_size
+ ? sections.str_offsets_offset : 0));
/* Can we use an existing virtual DWO file? */
- dwo_file_slot = lookup_dwo_file_slot (virtual_dwo_name, comp_dir);
+ dwo_file_slot = lookup_dwo_file_slot (virtual_dwo_name.c_str (), comp_dir);
/* Create one if necessary. */
if (*dwo_file_slot == NULL)
{
if (dwarf_read_debug)
{
fprintf_unfiltered (gdb_stdlog, "Creating virtual DWO: %s\n",
- virtual_dwo_name);
+ virtual_dwo_name.c_str ());
}
dwo_file = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_file);
dwo_file->dwo_name
= (const char *) obstack_copy0 (&objfile->objfile_obstack,
- virtual_dwo_name,
- strlen (virtual_dwo_name));
+ virtual_dwo_name.c_str (),
+ virtual_dwo_name.size ());
dwo_file->comp_dir = comp_dir;
dwo_file->sections.abbrev =
create_dwp_v2_section (&dwp_file->sections.abbrev,
if (dwarf_read_debug)
{
fprintf_unfiltered (gdb_stdlog, "Using existing virtual DWO: %s\n",
- virtual_dwo_name);
+ virtual_dwo_name.c_str ());
}
dwo_file = (struct dwo_file *) *dwo_file_slot;
}
- do_cleanups (cleanups);
dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
dwo_unit->dwo_file = dwo_file;
If unable to find/open the file, return NULL.
NOTE: This function is derived from symfile_bfd_open. */
-static bfd *
+static gdb_bfd_ref_ptr
try_open_dwop_file (const char *file_name, int is_dwp, int search_cwd)
{
- bfd *sym_bfd;
int desc, flags;
char *absolute_name;
/* Blech. OPF_TRY_CWD_FIRST also disables searching the path list if
if (desc < 0)
return NULL;
- sym_bfd = gdb_bfd_open (absolute_name, gnutarget, desc);
+ gdb_bfd_ref_ptr sym_bfd (gdb_bfd_open (absolute_name, gnutarget, desc));
xfree (absolute_name);
if (sym_bfd == NULL)
return NULL;
- bfd_set_cacheable (sym_bfd, 1);
+ bfd_set_cacheable (sym_bfd.get (), 1);
- if (!bfd_check_format (sym_bfd, bfd_object))
- {
- gdb_bfd_unref (sym_bfd); /* This also closes desc. */
- return NULL;
- }
+ if (!bfd_check_format (sym_bfd.get (), bfd_object))
+ return NULL;
/* Success. Record the bfd as having been included by the objfile's bfd.
This is important because things like demangled_names_hash lives in the
objfile's per_bfd space and may have references to things like symbol
names that live in the DWO/DWP file's per_bfd space. PR 16426. */
- gdb_bfd_record_inclusion (dwarf2_per_objfile->objfile->obfd, sym_bfd);
+ gdb_bfd_record_inclusion (dwarf2_per_objfile->objfile->obfd, sym_bfd.get ());
return sym_bfd;
}
Upon success, the canonicalized path of the file is stored in the bfd,
same as symfile_bfd_open. */
-static bfd *
+static gdb_bfd_ref_ptr
open_dwo_file (const char *file_name, const char *comp_dir)
{
- bfd *abfd;
-
if (IS_ABSOLUTE_PATH (file_name))
return try_open_dwop_file (file_name, 0 /*is_dwp*/, 0 /*search_cwd*/);
/* NOTE: If comp_dir is a relative path, this will also try the
search path, which seems useful. */
- abfd = try_open_dwop_file (path_to_try, 0 /*is_dwp*/, 1 /*search_cwd*/);
+ gdb_bfd_ref_ptr abfd (try_open_dwop_file (path_to_try, 0 /*is_dwp*/,
+ 1 /*search_cwd*/));
xfree (path_to_try);
if (abfd != NULL)
return abfd;
{
struct objfile *objfile = dwarf2_per_objfile->objfile;
struct dwo_file *dwo_file;
- bfd *dbfd;
struct cleanup *cleanups;
- dbfd = open_dwo_file (dwo_name, comp_dir);
+ gdb_bfd_ref_ptr dbfd (open_dwo_file (dwo_name, comp_dir));
if (dbfd == NULL)
{
if (dwarf_read_debug)
dwo_file = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_file);
dwo_file->dwo_name = dwo_name;
dwo_file->comp_dir = comp_dir;
- dwo_file->dbfd = dbfd;
+ dwo_file->dbfd = dbfd.release ();
cleanups = make_cleanup (free_dwo_file_cleanup, dwo_file);
- bfd_map_over_sections (dbfd, dwarf2_locate_dwo_sections, &dwo_file->sections);
+ 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);
- dwo_file->tus = create_debug_types_hash_table (dwo_file,
- dwo_file->sections.types);
+ create_debug_types_hash_table (dwo_file, dwo_file->sections.types,
+ dwo_file->tus);
discard_cleanups (cleanups);
Upon success, the canonicalized path of the file is stored in the bfd,
same as symfile_bfd_open. */
-static bfd *
+static gdb_bfd_ref_ptr
open_dwp_file (const char *file_name)
{
- bfd *abfd;
-
- abfd = try_open_dwop_file (file_name, 1 /*is_dwp*/, 1 /*search_cwd*/);
+ gdb_bfd_ref_ptr abfd (try_open_dwop_file (file_name, 1 /*is_dwp*/,
+ 1 /*search_cwd*/));
if (abfd != NULL)
return abfd;
{
struct objfile *objfile = dwarf2_per_objfile->objfile;
struct dwp_file *dwp_file;
- char *dwp_name;
- bfd *dbfd;
- struct cleanup *cleanups = make_cleanup (null_cleanup, 0);
/* Try to find first .dwp for the binary file before any symbolic links
resolving. */
/* If the objfile is a debug file, find the name of the real binary
file and get the name of dwp file from there. */
+ std::string dwp_name;
if (objfile->separate_debug_objfile_backlink != NULL)
{
struct objfile *backlink = objfile->separate_debug_objfile_backlink;
const char *backlink_basename = lbasename (backlink->original_name);
- char *debug_dirname = ldirname (objfile->original_name);
- make_cleanup (xfree, debug_dirname);
- dwp_name = xstrprintf ("%s%s%s.dwp", debug_dirname,
- SLASH_STRING, backlink_basename);
+ dwp_name = ldirname (objfile->original_name) + SLASH_STRING + backlink_basename;
}
else
- dwp_name = xstrprintf ("%s.dwp", objfile->original_name);
- make_cleanup (xfree, dwp_name);
+ dwp_name = objfile->original_name;
- dbfd = open_dwp_file (dwp_name);
+ dwp_name += ".dwp";
+
+ gdb_bfd_ref_ptr dbfd (open_dwp_file (dwp_name.c_str ()));
if (dbfd == NULL
&& strcmp (objfile->original_name, objfile_name (objfile)) != 0)
{
/* Try to find .dwp for the binary file after gdb_realpath resolving. */
- dwp_name = xstrprintf ("%s.dwp", objfile_name (objfile));
- make_cleanup (xfree, dwp_name);
- dbfd = open_dwp_file (dwp_name);
+ dwp_name = objfile_name (objfile);
+ dwp_name += ".dwp";
+ dbfd = open_dwp_file (dwp_name.c_str ());
}
if (dbfd == NULL)
{
if (dwarf_read_debug)
- fprintf_unfiltered (gdb_stdlog, "DWP file not found: %s\n", dwp_name);
- do_cleanups (cleanups);
+ fprintf_unfiltered (gdb_stdlog, "DWP file not found: %s\n", dwp_name.c_str ());
return NULL;
}
dwp_file = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwp_file);
- dwp_file->name = bfd_get_filename (dbfd);
- dwp_file->dbfd = dbfd;
- do_cleanups (cleanups);
+ dwp_file->name = bfd_get_filename (dbfd.get ());
+ dwp_file->dbfd = dbfd.release ();
/* +1: section 0 is unused */
- dwp_file->num_sections = bfd_count_sections (dbfd) + 1;
+ dwp_file->num_sections = bfd_count_sections (dwp_file->dbfd) + 1;
dwp_file->elf_sections =
OBSTACK_CALLOC (&objfile->objfile_obstack,
dwp_file->num_sections, asection *);
- bfd_map_over_sections (dbfd, dwarf2_locate_common_dwp_sections, dwp_file);
+ bfd_map_over_sections (dwp_file->dbfd, dwarf2_locate_common_dwp_sections,
+ dwp_file);
dwp_file->cus = create_dwp_hash_table (dwp_file, 0);
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
error (_("Dwarf Error: DWP file CU version %s doesn't match"
" TU version %s [in DWP file %s]"),
pulongest (dwp_file->cus->version),
- pulongest (dwp_file->tus->version), dwp_name);
+ 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 (dbfd, dwarf2_locate_v2_dwp_sections, dwp_file);
+ bfd_map_over_sections (dwp_file->dbfd, dwarf2_locate_v2_dwp_sections,
+ dwp_file);
dwp_file->loaded_cus = allocate_dwp_loaded_cutus_table (objfile);
dwp_file->loaded_tus = allocate_dwp_loaded_cutus_table (objfile);
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))
struct dwarf2_cu *child_origin_cu;
/* We are trying to process concrete instance entries:
- DW_TAG_GNU_call_site DIEs indeed have a DW_AT_abstract_origin tag, but
+ DW_TAG_call_site DIEs indeed have a DW_AT_abstract_origin tag, but
it's not relevant to our analysis here. i.e. detecting DIEs that are
present in the abstract instance but not referenced in the concrete
one. */
- if (child_die->tag == DW_TAG_GNU_call_site)
+ if (child_die->tag == DW_TAG_call_site
+ || child_die->tag == DW_TAG_GNU_call_site)
continue;
/* For each CHILD_DIE, find the corresponding child of
&& 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
local_using_directives = newobj->local_using_directives;
}
-/* Read in DW_TAG_GNU_call_site and insert it to CU->call_site_htab. */
+/* Read in DW_TAG_call_site and insert it to CU->call_site_htab. */
static void
read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
- attr = dwarf2_attr (die, DW_AT_low_pc, cu);
+ attr = dwarf2_attr (die, DW_AT_call_return_pc, cu);
+ if (attr == NULL)
+ {
+ /* This was a pre-DWARF-5 GNU extension alias
+ for DW_AT_call_return_pc. */
+ attr = dwarf2_attr (die, DW_AT_low_pc, cu);
+ }
if (!attr)
{
complaint (&symfile_complaints,
- _("missing DW_AT_low_pc for DW_TAG_GNU_call_site "
+ _("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;
if (*slot != NULL)
{
complaint (&symfile_complaints,
- _("Duplicate PC %s for DW_TAG_GNU_call_site "
+ _("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;
}
for (child_die = die->child; child_die && child_die->tag;
child_die = sibling_die (child_die))
{
- if (child_die->tag != DW_TAG_GNU_call_site_parameter)
+ if (child_die->tag != DW_TAG_call_site_parameter
+ && child_die->tag != DW_TAG_GNU_call_site_parameter)
{
complaint (&symfile_complaints,
- _("Tag %d is not DW_TAG_GNU_call_site_parameter in "
- "DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"),
- child_die->tag, child_die->offset.sect_off,
+ _("Tag %d is not DW_TAG_call_site_parameter in "
+ "DW_TAG_call_site child DIE 0x%x [in module %s]"),
+ child_die->tag, to_underlying (child_die->sect_off),
objfile_name (objfile));
continue;
}
memset (call_site, 0, sizeof (*call_site) - sizeof (*call_site->parameter));
call_site->pc = pc;
- if (dwarf2_flag_true_p (die, DW_AT_GNU_tail_call, cu))
+ if (dwarf2_flag_true_p (die, DW_AT_call_tail_call, cu)
+ || dwarf2_flag_true_p (die, DW_AT_GNU_tail_call, cu))
{
struct die_info *func_die;
&& func_die->tag != DW_TAG_subroutine_type;
func_die = func_die->parent);
- /* DW_AT_GNU_all_call_sites is a superset
- of DW_AT_GNU_all_tail_call_sites. */
+ /* DW_AT_call_all_calls is a superset
+ of DW_AT_call_all_tail_calls. */
if (func_die
+ && !dwarf2_flag_true_p (func_die, DW_AT_call_all_calls, cu)
&& !dwarf2_flag_true_p (func_die, DW_AT_GNU_all_call_sites, cu)
+ && !dwarf2_flag_true_p (func_die, DW_AT_call_all_tail_calls, cu)
&& !dwarf2_flag_true_p (func_die, DW_AT_GNU_all_tail_call_sites, cu))
{
/* TYPE_TAIL_CALL_LIST is not interesting in functions where it is
}
else
complaint (&symfile_complaints,
- _("Cannot find function owning DW_TAG_GNU_call_site "
+ _("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));
}
}
- attr = dwarf2_attr (die, DW_AT_GNU_call_site_target, cu);
+ attr = dwarf2_attr (die, DW_AT_call_target, cu);
+ if (attr == NULL)
+ attr = dwarf2_attr (die, DW_AT_GNU_call_site_target, cu);
+ if (attr == NULL)
+ attr = dwarf2_attr (die, DW_AT_call_origin, cu);
if (attr == NULL)
- attr = dwarf2_attr (die, DW_AT_abstract_origin, cu);
+ {
+ /* This was a pre-DWARF-5 GNU extension alias for DW_AT_call_origin. */
+ attr = dwarf2_attr (die, DW_AT_abstract_origin, cu);
+ }
SET_FIELD_DWARF_BLOCK (call_site->target, NULL);
if (!attr || (attr_form_is_block (attr) && DW_BLOCK (attr)->size == 0))
/* Keep NULL DWARF_BLOCK. */;
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_GNU_call_site_target target DIE has invalid "
+ _("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);
}
if (dwarf2_get_pc_bounds (target_die, &lowpc, NULL, target_cu, NULL)
<= PC_BOUNDS_INVALID)
complaint (&symfile_complaints,
- _("DW_AT_GNU_call_site_target target DIE has invalid "
+ _("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);
}
else
complaint (&symfile_complaints,
- _("DW_TAG_GNU_call_site DW_AT_GNU_call_site_target is neither "
+ _("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;
struct call_site_parameter *parameter;
struct attribute *loc, *origin;
- if (child_die->tag != DW_TAG_GNU_call_site_parameter)
+ if (child_die->tag != DW_TAG_call_site_parameter
+ && child_die->tag != DW_TAG_GNU_call_site_parameter)
{
/* Already printed the complaint above. */
continue;
/* DW_AT_location specifies the register number or DW_AT_abstract_origin
specifies DW_TAG_formal_parameter. Value of the data assumed for the
- register is contained in DW_AT_GNU_call_site_value. */
+ register is contained in DW_AT_call_value. */
loc = dwarf2_attr (child_die, DW_AT_location, cu);
- origin = dwarf2_attr (child_die, DW_AT_abstract_origin, cu);
+ origin = dwarf2_attr (child_die, DW_AT_call_parameter, cu);
+ if (origin == NULL)
+ {
+ /* This was a pre-DWARF-5 GNU extension alias
+ for DW_AT_call_parameter. */
+ origin = dwarf2_attr (child_die, DW_AT_abstract_origin, 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
therefore cannot be even moved to DW_TAG_partial_unit. */
complaint (&symfile_complaints,
- _("DW_AT_abstract_origin offset is not in CU for "
- "DW_TAG_GNU_call_site child DIE 0x%x "
- "[in module %s]"),
- child_die->offset.sect_off, objfile_name (objfile));
+ _("DW_AT_call_parameter offset is not in CU for "
+ "DW_TAG_call_site child DIE 0x%x [in module %s]"),
+ 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_GNU_call_site child DIE 0x%x [in module %s]"),
- child_die->offset.sect_off, objfile_name (objfile));
+ "DW_TAG_call_site child DIE 0x%x [in module %s]"),
+ to_underlying (child_die->sect_off), objfile_name (objfile));
continue;
}
else
complaint (&symfile_complaints,
_("Only single DW_OP_reg or DW_OP_fbreg is supported "
"for DW_FORM_block* DW_AT_location is supported for "
- "DW_TAG_GNU_call_site child DIE 0x%x "
+ "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;
}
}
- attr = dwarf2_attr (child_die, DW_AT_GNU_call_site_value, cu);
+ attr = dwarf2_attr (child_die, DW_AT_call_value, cu);
+ if (attr == NULL)
+ attr = dwarf2_attr (child_die, DW_AT_GNU_call_site_value, cu);
if (!attr_form_is_block (attr))
{
complaint (&symfile_complaints,
- _("No DW_FORM_block* DW_AT_GNU_call_site_value for "
- "DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"),
- child_die->offset.sect_off, objfile_name (objfile));
+ _("No DW_FORM_block* DW_AT_call_value for "
+ "DW_TAG_call_site child DIE 0x%x [in module %s]"),
+ to_underlying (child_die->sect_off),
+ objfile_name (objfile));
continue;
}
parameter->value = DW_BLOCK (attr)->data;
parameter->data_value_size = 0;
call_site->parameter_count++;
- attr = dwarf2_attr (child_die, DW_AT_GNU_call_site_data_value, cu);
+ attr = dwarf2_attr (child_die, DW_AT_call_data_value, cu);
+ if (attr == NULL)
+ attr = dwarf2_attr (child_die, DW_AT_GNU_call_site_data_value, cu);
if (attr)
{
if (!attr_form_is_block (attr))
complaint (&symfile_complaints,
- _("No DW_FORM_block* DW_AT_GNU_call_site_data_value for "
- "DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"),
- child_die->offset.sect_off, objfile_name (objfile));
+ _("No DW_FORM_block* DW_AT_call_data_value for "
+ "DW_TAG_call_site child DIE 0x%x [in module %s]"),
+ to_underlying (child_die->sect_off),
+ objfile_name (objfile));
else
{
parameter->data_value = DW_BLOCK (attr)->data;
}
}
-/* Get low and high pc attributes from DW_AT_ranges attribute value OFFSET.
- Return 1 if the attributes are present and valid, otherwise, return 0.
- If RANGES_PST is not NULL we should setup `objfile->psymtabs_addrmap'. */
+/* 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:
+ void (CORE_ADDR range_beginning, CORE_ADDR range_end)
+ Return true if the attributes are present and valid, otherwise,
+ return false. */
+
+template <typename Callback>
+static bool
+dwarf2_rnglists_process (unsigned offset, struct dwarf2_cu *cu,
+ Callback &&callback)
+{
+ struct objfile *objfile = cu->objfile;
+ bfd *obfd = objfile->obfd;
+ /* Base address selection entry. */
+ CORE_ADDR base;
+ int found_base;
+ const gdb_byte *buffer;
+ CORE_ADDR baseaddr;
+ bool overflow = false;
+
+ found_base = cu->base_known;
+ base = cu->base_address;
+
+ dwarf2_read_section (objfile, &dwarf2_per_objfile->rnglists);
+ if (offset >= dwarf2_per_objfile->rnglists.size)
+ {
+ complaint (&symfile_complaints,
+ _("Offset %d out of bounds for DW_AT_ranges attribute"),
+ offset);
+ return false;
+ }
+ buffer = dwarf2_per_objfile->rnglists.buffer + offset;
+
+ baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ while (1)
+ {
+ /* Initialize it due to a false compiler warning. */
+ CORE_ADDR range_beginning = 0, range_end = 0;
+ const gdb_byte *buf_end = (dwarf2_per_objfile->rnglists.buffer
+ + dwarf2_per_objfile->rnglists.size);
+ unsigned int bytes_read;
+
+ if (buffer == buf_end)
+ {
+ overflow = true;
+ break;
+ }
+ const auto rlet = static_cast<enum dwarf_range_list_entry>(*buffer++);
+ switch (rlet)
+ {
+ case DW_RLE_end_of_list:
+ break;
+ case DW_RLE_base_address:
+ if (buffer + cu->header.addr_size > buf_end)
+ {
+ overflow = true;
+ break;
+ }
+ base = read_address (obfd, buffer, cu, &bytes_read);
+ found_base = 1;
+ buffer += bytes_read;
+ break;
+ case DW_RLE_start_length:
+ if (buffer + cu->header.addr_size > buf_end)
+ {
+ overflow = true;
+ break;
+ }
+ range_beginning = read_address (obfd, buffer, cu, &bytes_read);
+ buffer += bytes_read;
+ range_end = (range_beginning
+ + read_unsigned_leb128 (obfd, buffer, &bytes_read));
+ buffer += bytes_read;
+ if (buffer > buf_end)
+ {
+ overflow = true;
+ break;
+ }
+ break;
+ case DW_RLE_offset_pair:
+ range_beginning = read_unsigned_leb128 (obfd, buffer, &bytes_read);
+ buffer += bytes_read;
+ if (buffer > buf_end)
+ {
+ overflow = true;
+ break;
+ }
+ range_end = read_unsigned_leb128 (obfd, buffer, &bytes_read);
+ buffer += bytes_read;
+ if (buffer > buf_end)
+ {
+ overflow = true;
+ break;
+ }
+ break;
+ case DW_RLE_start_end:
+ if (buffer + 2 * cu->header.addr_size > buf_end)
+ {
+ overflow = true;
+ break;
+ }
+ range_beginning = read_address (obfd, buffer, cu, &bytes_read);
+ buffer += bytes_read;
+ range_end = read_address (obfd, buffer, cu, &bytes_read);
+ buffer += bytes_read;
+ break;
+ default:
+ complaint (&symfile_complaints,
+ _("Invalid .debug_rnglists data (no base address)"));
+ return false;
+ }
+ if (rlet == DW_RLE_end_of_list || overflow)
+ break;
+ if (rlet == DW_RLE_base_address)
+ continue;
+
+ if (!found_base)
+ {
+ /* We have no valid base address for the ranges
+ data. */
+ complaint (&symfile_complaints,
+ _("Invalid .debug_rnglists data (no base address)"));
+ return false;
+ }
+
+ if (range_beginning > range_end)
+ {
+ /* Inverted range entries are invalid. */
+ complaint (&symfile_complaints,
+ _("Invalid .debug_rnglists data (inverted range)"));
+ return false;
+ }
+
+ /* Empty range entries have no effect. */
+ if (range_beginning == range_end)
+ continue;
+
+ range_beginning += base;
+ range_end += base;
+
+ /* A not-uncommon case of bad debug info.
+ Don't pollute the addrmap with bad data. */
+ if (range_beginning + baseaddr == 0
+ && !dwarf2_per_objfile->has_section_at_zero)
+ {
+ complaint (&symfile_complaints,
+ _(".debug_rnglists entry has start address of zero"
+ " [in module %s]"), objfile_name (objfile));
+ continue;
+ }
+
+ callback (range_beginning, range_end);
+ }
+
+ if (overflow)
+ {
+ complaint (&symfile_complaints,
+ _("Offset %d is not terminated "
+ "for DW_AT_ranges attribute"),
+ offset);
+ return false;
+ }
+
+ return true;
+}
+/* Call CALLBACK from DW_AT_ranges attribute value OFFSET reading .debug_ranges.
+ Callback's type should be:
+ void (CORE_ADDR range_beginning, CORE_ADDR range_end)
+ Return 1 if the attributes are present and valid, otherwise, return 0. */
+
+template <typename Callback>
static int
-dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return,
- CORE_ADDR *high_return, struct dwarf2_cu *cu,
- struct partial_symtab *ranges_pst)
+dwarf2_ranges_process (unsigned offset, struct dwarf2_cu *cu,
+ 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;
int found_base;
unsigned int dummy;
const gdb_byte *buffer;
- int low_set;
- CORE_ADDR low = 0;
- CORE_ADDR high = 0;
CORE_ADDR baseaddr;
+ if (cu_header->version >= 5)
+ return dwarf2_rnglists_process (offset, cu, callback);
+
found_base = cu->base_known;
base = cu->base_address;
}
buffer = dwarf2_per_objfile->ranges.buffer + offset;
- low_set = 0;
-
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
while (1)
continue;
}
+ callback (range_beginning, range_end);
+ }
+
+ return 1;
+}
+
+/* Get low and high pc attributes from DW_AT_ranges attribute value OFFSET.
+ Return 1 if the attributes are present and valid, otherwise, return 0.
+ If RANGES_PST is not NULL we should setup `objfile->psymtabs_addrmap'. */
+
+static int
+dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return,
+ CORE_ADDR *high_return, struct dwarf2_cu *cu,
+ struct partial_symtab *ranges_pst)
+{
+ struct objfile *objfile = cu->objfile;
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+ const CORE_ADDR baseaddr = ANOFFSET (objfile->section_offsets,
+ SECT_OFF_TEXT (objfile));
+ int low_set = 0;
+ CORE_ADDR low = 0;
+ CORE_ADDR high = 0;
+ int retval;
+
+ retval = dwarf2_ranges_process (offset, cu,
+ [&] (CORE_ADDR range_beginning, CORE_ADDR range_end)
+ {
if (ranges_pst != NULL)
{
CORE_ADDR lowpc;
if (range_end > high)
high = range_end;
}
- }
+ });
+ if (!retval)
+ return 0;
if (! low_set)
/* If the first entry is an end-of-list marker, the range
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. */
CORE_ADDR base = cu->base_address;
int base_known = cu->base_known;
- dwarf2_read_section (objfile, &dwarf2_per_objfile->ranges);
- if (offset >= dwarf2_per_objfile->ranges.size)
- {
- complaint (&symfile_complaints,
- _("Offset %lu out of bounds for DW_AT_ranges attribute"),
- offset);
- return;
- }
- buffer = dwarf2_per_objfile->ranges.buffer + offset;
-
- for (;;)
- {
- unsigned int bytes_read;
- CORE_ADDR start, end;
-
- start = read_address (obfd, buffer, cu, &bytes_read);
- buffer += bytes_read;
- end = read_address (obfd, buffer, cu, &bytes_read);
- buffer += bytes_read;
-
- /* Did we find the end of the range list? */
- if (start == 0 && end == 0)
- break;
-
- /* Did we find a base address selection entry? */
- else if ((start & base_select_mask) == base_select_mask)
- {
- base = end;
- base_known = 1;
- }
-
- /* We found an ordinary address range. */
- else
- {
- if (!base_known)
- {
- complaint (&symfile_complaints,
- _("Invalid .debug_ranges data "
- "(no base address)"));
- return;
- }
-
- if (start > end)
- {
- /* Inverted range entries are invalid. */
- complaint (&symfile_complaints,
- _("Invalid .debug_ranges data "
- "(inverted range)"));
- return;
- }
-
- /* Empty range entries have no effect. */
- if (start == end)
- continue;
-
- start += base + baseaddr;
- end += base + baseaddr;
-
- /* A not-uncommon case of bad debug info.
- Don't pollute the addrmap with bad data. */
- if (start == 0 && !dwarf2_per_objfile->has_section_at_zero)
- {
- complaint (&symfile_complaints,
- _(".debug_ranges entry has start address of zero"
- " [in module %s]"), objfile_name (objfile));
- continue;
- }
-
- start = gdbarch_adjust_dwarf2_addr (gdbarch, start);
- end = gdbarch_adjust_dwarf2_addr (gdbarch, end);
- record_block_range (block, start, end - 1);
- }
- }
+ dwarf2_ranges_process (offset, cu,
+ [&] (CORE_ADDR start, CORE_ADDR end)
+ {
+ start += baseaddr;
+ end += baseaddr;
+ start = gdbarch_adjust_dwarf2_addr (gdbarch, start);
+ end = gdbarch_adjust_dwarf2_addr (gdbarch, end);
+ record_block_range (block, start, end - 1);
+ });
}
}
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_method_type (new_type, self_type, TYPE_TARGET_TYPE (pfn_type),
TYPE_FIELDS (pfn_type), TYPE_NFIELDS (pfn_type),
TYPE_VARARGS (pfn_type));
- 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;
+ smash_to_methodptr_type (type, new_type);
}
+
/* 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
the type's name and general properties; the members will not be
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. */
return set_die_type (die, type, cu);
}
-/* Extract all information from a DW_TAG_reference_type DIE and add to
+/* Extract all information from a DW_TAG_{rvalue_,}reference_type DIE and add to
the user defined type vector. */
static struct type *
-read_tag_reference_type (struct die_info *die, struct dwarf2_cu *cu)
+read_tag_reference_type (struct die_info *die, struct dwarf2_cu *cu,
+ enum type_code refcode)
{
struct comp_unit_head *cu_header = &cu->header;
struct type *type, *target_type;
struct attribute *attr;
+ gdb_assert (refcode == TYPE_CODE_REF || refcode == TYPE_CODE_RVALUE_REF);
+
target_type = die_type (die, cu);
/* The die_type call above may have already set the type for this DIE. */
if (type)
return type;
- type = lookup_reference_type (target_type);
+ type = lookup_reference_type (target_type, refcode);
attr = dwarf2_attr (die, DW_AT_byte_size, cu);
if (attr)
{
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;
abbrev_ptr += 1;
/* now read in declarations */
- abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
- abbrev_ptr += bytes_read;
- abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
- abbrev_ptr += bytes_read;
- while (abbrev_name)
+ for (;;)
{
+ LONGEST implicit_const;
+
+ abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+ abbrev_ptr += bytes_read;
+ abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+ abbrev_ptr += bytes_read;
+ if (abbrev_form == DW_FORM_implicit_const)
+ {
+ implicit_const = read_signed_leb128 (abfd, abbrev_ptr,
+ &bytes_read);
+ abbrev_ptr += bytes_read;
+ }
+ else
+ {
+ /* Initialize it due to a false compiler warning. */
+ implicit_const = -1;
+ }
+
+ if (abbrev_name == 0)
+ break;
+
if (cur_abbrev->num_attrs == allocated_attrs)
{
allocated_attrs += ATTR_ALLOC_CHUNK;
cur_attrs[cur_abbrev->num_attrs].name
= (enum dwarf_attribute) abbrev_name;
- cur_attrs[cur_abbrev->num_attrs++].form
+ cur_attrs[cur_abbrev->num_attrs].form
= (enum dwarf_form) abbrev_form;
- abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
- abbrev_ptr += bytes_read;
- abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
- abbrev_ptr += bytes_read;
+ cur_attrs[cur_abbrev->num_attrs].implicit_const = implicit_const;
+ ++cur_abbrev->num_attrs;
}
cur_abbrev->attrs =
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;
}
static const gdb_byte *
read_attribute_value (const struct die_reader_specs *reader,
struct attribute *attr, unsigned form,
- const gdb_byte *info_ptr)
+ LONGEST implicit_const, const gdb_byte *info_ptr)
{
struct dwarf2_cu *cu = reader->cu;
struct objfile *objfile = cu->objfile;
DW_UNSND (attr) = read_8_bytes (abfd, info_ptr);
info_ptr += 8;
break;
+ case DW_FORM_data16:
+ blk = dwarf_alloc_block (cu);
+ blk->size = 16;
+ blk->data = read_n_bytes (abfd, info_ptr, 16);
+ info_ptr += 16;
+ DW_BLOCK (attr) = blk;
+ break;
case DW_FORM_sec_offset:
DW_UNSND (attr) = read_offset (abfd, info_ptr, &cu->header, &bytes_read);
info_ptr += bytes_read;
break;
}
/* FALLTHROUGH */
+ case DW_FORM_line_strp:
+ if (!cu->per_cu->is_dwz)
+ {
+ DW_STRING (attr) = read_indirect_line_string (abfd, info_ptr,
+ cu_header, &bytes_read);
+ DW_STRING_IS_CANONICAL (attr) = 0;
+ info_ptr += bytes_read;
+ break;
+ }
+ /* FALLTHROUGH */
case DW_FORM_GNU_strp_alt:
{
struct dwz_file *dwz = dwarf2_get_dwz_file ();
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;
case DW_FORM_indirect:
form = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
- info_ptr = read_attribute_value (reader, attr, form, info_ptr);
+ if (form == DW_FORM_implicit_const)
+ {
+ implicit_const = read_signed_leb128 (abfd, info_ptr, &bytes_read);
+ info_ptr += bytes_read;
+ }
+ info_ptr = read_attribute_value (reader, attr, form, implicit_const,
+ info_ptr);
+ break;
+ case DW_FORM_implicit_const:
+ DW_SND (attr) = implicit_const;
break;
case DW_FORM_GNU_addr_index:
if (reader->dwo_file == NULL)
const gdb_byte *info_ptr)
{
attr->name = abbrev->name;
- return read_attribute_value (reader, attr, abbrev->form, info_ptr);
+ return read_attribute_value (reader, attr, abbrev->form,
+ abbrev->implicit_const, info_ptr);
}
/* Read dwarf information from a buffer. */
return (const char *) buf;
}
+/* Return pointer to string at section SECT offset STR_OFFSET with error
+ reporting strings FORM_NAME and SECT_NAME. */
+
static const char *
-read_indirect_string_at_offset (bfd *abfd, LONGEST str_offset)
-{
- dwarf2_read_section (dwarf2_per_objfile->objfile, &dwarf2_per_objfile->str);
- if (dwarf2_per_objfile->str.buffer == NULL)
- error (_("DW_FORM_strp used without .debug_str section [in module %s]"),
- bfd_get_filename (abfd));
- if (str_offset >= dwarf2_per_objfile->str.size)
- error (_("DW_FORM_strp pointing outside of "
- ".debug_str section [in module %s]"),
- bfd_get_filename (abfd));
+read_indirect_string_at_offset_from (bfd *abfd, LONGEST str_offset,
+ struct dwarf2_section_info *sect,
+ const char *form_name,
+ const char *sect_name)
+{
+ dwarf2_read_section (dwarf2_per_objfile->objfile, sect);
+ if (sect->buffer == NULL)
+ error (_("%s used without %s section [in module %s]"),
+ form_name, sect_name, bfd_get_filename (abfd));
+ if (str_offset >= sect->size)
+ error (_("%s pointing outside of %s section [in module %s]"),
+ form_name, sect_name, bfd_get_filename (abfd));
gdb_assert (HOST_CHAR_BIT == 8);
- if (dwarf2_per_objfile->str.buffer[str_offset] == '\0')
+ if (sect->buffer[str_offset] == '\0')
return NULL;
- return (const char *) (dwarf2_per_objfile->str.buffer + str_offset);
+ return (const char *) (sect->buffer + str_offset);
+}
+
+/* Return pointer to string at .debug_str offset STR_OFFSET. */
+
+static const char *
+read_indirect_string_at_offset (bfd *abfd, LONGEST str_offset)
+{
+ return read_indirect_string_at_offset_from (abfd, str_offset,
+ &dwarf2_per_objfile->str,
+ "DW_FORM_strp", ".debug_str");
+}
+
+/* Return pointer to string at .debug_line_str offset STR_OFFSET. */
+
+static const char *
+read_indirect_line_string_at_offset (bfd *abfd, LONGEST str_offset)
+{
+ return read_indirect_string_at_offset_from (abfd, str_offset,
+ &dwarf2_per_objfile->line_str,
+ "DW_FORM_line_strp",
+ ".debug_line_str");
}
/* Read a string at offset STR_OFFSET in the .debug_str section from
return (const char *) (dwz->str.buffer + str_offset);
}
+/* Return pointer to string at .debug_str offset as read from BUF.
+ BUF is assumed to be in a compilation unit described by CU_HEADER.
+ Return *BYTES_READ_PTR count of bytes read from BUF. */
+
static const char *
read_indirect_string (bfd *abfd, const gdb_byte *buf,
const struct comp_unit_head *cu_header,
return read_indirect_string_at_offset (abfd, str_offset);
}
-static ULONGEST
+/* Return pointer to string at .debug_line_str offset as read from BUF.
+ BUF is assumed to be in a compilation unit described by CU_HEADER.
+ Return *BYTES_READ_PTR count of bytes read from BUF. */
+
+static const char *
+read_indirect_line_string (bfd *abfd, const gdb_byte *buf,
+ const struct comp_unit_head *cu_header,
+ unsigned int *bytes_read_ptr)
+{
+ LONGEST str_offset = read_offset (abfd, buf, cu_header, bytes_read_ptr);
+
+ return read_indirect_line_string_at_offset (abfd, str_offset);
+}
+
+ULONGEST
read_unsigned_leb128 (bfd *abfd, const gdb_byte *buf,
- unsigned int *bytes_read_ptr)
+ unsigned int *bytes_read_ptr)
{
ULONGEST result;
unsigned int num_read;
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_string
+ if (attr->form == DW_FORM_strp || attr->form == DW_FORM_line_strp
+ || 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));
}
return follow_die_ref (die, spec_attr, spec_cu);
}
-/* Free the line_header structure *LH, and any arrays and strings it
- refers to.
- NOTE: This is also used as a "cleanup" function. */
-
-static void
-free_line_header (struct line_header *lh)
-{
- if (lh->standard_opcode_lengths)
- xfree (lh->standard_opcode_lengths);
-
- /* Remember that all the lh->file_names[i].name pointers are
- pointers into debug_line_buffer, and don't need to be freed. */
- if (lh->file_names)
- xfree (lh->file_names);
-
- /* Similarly for the include directory names. */
- if (lh->include_dirs)
- xfree (lh->include_dirs);
-
- xfree (lh);
-}
-
/* Stub for free_line_header to match void * callback types. */
static void
{
struct line_header *lh = (struct line_header *) arg;
- free_line_header (lh);
+ delete lh;
}
-/* Add an entry to LH's include directory table. */
-
-static void
-add_include_dir (struct line_header *lh, const char *include_dir)
+void
+line_header::add_include_dir (const char *include_dir)
{
if (dwarf_line_debug >= 2)
- fprintf_unfiltered (gdb_stdlog, "Adding dir %u: %s\n",
- lh->num_include_dirs + 1, include_dir);
-
- /* Grow the array if necessary. */
- if (lh->include_dirs_size == 0)
- {
- lh->include_dirs_size = 1; /* for testing */
- lh->include_dirs = XNEWVEC (const char *, lh->include_dirs_size);
- }
- else if (lh->num_include_dirs >= lh->include_dirs_size)
- {
- lh->include_dirs_size *= 2;
- lh->include_dirs = XRESIZEVEC (const char *, lh->include_dirs,
- lh->include_dirs_size);
- }
+ fprintf_unfiltered (gdb_stdlog, "Adding dir %zu: %s\n",
+ include_dirs.size () + 1, include_dir);
- lh->include_dirs[lh->num_include_dirs++] = include_dir;
+ include_dirs.push_back (include_dir);
}
-/* Add an entry to LH's file name table. */
-
-static void
-add_file_name (struct line_header *lh,
- const char *name,
- unsigned int dir_index,
- unsigned int mod_time,
- unsigned int length)
+void
+line_header::add_file_name (const char *name,
+ dir_index d_index,
+ unsigned int mod_time,
+ unsigned int length)
{
- struct file_entry *fe;
-
if (dwarf_line_debug >= 2)
fprintf_unfiltered (gdb_stdlog, "Adding file %u: %s\n",
- lh->num_file_names + 1, name);
-
- /* Grow the array if necessary. */
- if (lh->file_names_size == 0)
- {
- lh->file_names_size = 1; /* for testing */
- lh->file_names = XNEWVEC (struct file_entry, lh->file_names_size);
- }
- else if (lh->num_file_names >= lh->file_names_size)
- {
- lh->file_names_size *= 2;
- lh->file_names
- = XRESIZEVEC (struct file_entry, lh->file_names, lh->file_names_size);
- }
+ (unsigned) file_names.size () + 1, name);
- fe = &lh->file_names[lh->num_file_names++];
- fe->name = name;
- fe->dir_index = dir_index;
- fe->mod_time = mod_time;
- fe->length = length;
- fe->included_p = 0;
- fe->symtab = NULL;
+ file_names.emplace_back (name, d_index, mod_time, length);
}
/* A convenience function to find the proper .debug_line section for a CU. */
return section;
}
+/* Read directory or file name entry format, starting with byte of
+ format count entries, ULEB128 pairs of entry formats, ULEB128 of
+ entries count and the entries themselves in the described entry
+ format. */
+
+static void
+read_formatted_entries (bfd *abfd, const gdb_byte **bufp,
+ struct line_header *lh,
+ const struct comp_unit_head *cu_header,
+ void (*callback) (struct line_header *lh,
+ const char *name,
+ dir_index d_index,
+ unsigned int mod_time,
+ unsigned int length))
+{
+ gdb_byte format_count, formati;
+ ULONGEST data_count, datai;
+ const gdb_byte *buf = *bufp;
+ const gdb_byte *format_header_data;
+ unsigned int bytes_read;
+
+ format_count = read_1_byte (abfd, buf);
+ buf += 1;
+ format_header_data = buf;
+ for (formati = 0; formati < format_count; formati++)
+ {
+ read_unsigned_leb128 (abfd, buf, &bytes_read);
+ buf += bytes_read;
+ read_unsigned_leb128 (abfd, buf, &bytes_read);
+ buf += bytes_read;
+ }
+
+ data_count = read_unsigned_leb128 (abfd, buf, &bytes_read);
+ buf += bytes_read;
+ for (datai = 0; datai < data_count; datai++)
+ {
+ const gdb_byte *format = format_header_data;
+ struct file_entry fe;
+
+ for (formati = 0; formati < format_count; formati++)
+ {
+ ULONGEST content_type = read_unsigned_leb128 (abfd, format, &bytes_read);
+ 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:
+ string.emplace (read_direct_string (abfd, buf, &bytes_read));
+ buf += bytes_read;
+ break;
+
+ case DW_FORM_line_strp:
+ string.emplace (read_indirect_line_string (abfd, buf,
+ cu_header,
+ &bytes_read));
+ buf += bytes_read;
+ break;
+
+ case DW_FORM_data1:
+ uint.emplace (read_1_byte (abfd, buf));
+ buf += 1;
+ break;
+
+ case DW_FORM_data2:
+ uint.emplace (read_2_bytes (abfd, buf));
+ buf += 2;
+ break;
+
+ case DW_FORM_data4:
+ uint.emplace (read_4_bytes (abfd, buf));
+ buf += 4;
+ break;
+
+ case DW_FORM_data8:
+ uint.emplace (read_8_bytes (abfd, buf));
+ buf += 8;
+ break;
+
+ case DW_FORM_udata:
+ uint.emplace (read_unsigned_leb128 (abfd, buf, &bytes_read));
+ buf += bytes_read;
+ break;
+
+ case DW_FORM_block:
+ /* It is valid only for DW_LNCT_timestamp which is ignored by
+ 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.d_index, fe.mod_time, fe.length);
+ }
+
+ *bufp = buf;
+}
+
/* Read the statement program header starting at OFFSET in
.debug_line, or .debug_line.dwo. Return a pointer
to a struct line_header, allocated using xmalloc.
the returned object point into the dwarf line section buffer,
and must not be freed. */
-static struct line_header *
-dwarf_decode_line_header (unsigned int offset, struct dwarf2_cu *cu)
+static line_header_up
+dwarf_decode_line_header (sect_offset sect_off, struct dwarf2_cu *cu)
{
- struct cleanup *back_to;
- struct line_header *lh;
const gdb_byte *line_ptr;
unsigned int bytes_read, offset_size;
int i;
/* 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;
}
- lh = XNEW (struct line_header);
- memset (lh, 0, sizeof (*lh));
- back_to = make_cleanup ((make_cleanup_ftype *) free_line_header,
- (void *) lh);
+ 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 =
if (line_ptr + lh->total_length > (section->buffer + section->size))
{
dwarf2_statement_list_fits_in_line_number_section_complaint ();
- do_cleanups (back_to);
return 0;
}
lh->statement_program_end = line_ptr + lh->total_length;
lh->version = read_2_bytes (abfd, line_ptr);
line_ptr += 2;
- if (lh->version > 4)
+ if (lh->version > 5)
{
/* This is a version we don't understand. The format could have
changed in ways we don't handle properly so just punt. */
_("unsupported version in .debug_line section"));
return NULL;
}
+ if (lh->version >= 5)
+ {
+ gdb_byte segment_selector_size;
+
+ /* Skip address size. */
+ read_1_byte (abfd, line_ptr);
+ line_ptr += 1;
+
+ segment_selector_size = read_1_byte (abfd, line_ptr);
+ line_ptr += 1;
+ if (segment_selector_size != 0)
+ {
+ complaint (&symfile_complaints,
+ _("unsupported segment selector size %u "
+ "in .debug_line section"),
+ segment_selector_size);
+ return NULL;
+ }
+ }
lh->header_length = read_offset_1 (abfd, line_ptr, offset_size);
line_ptr += offset_size;
lh->minimum_instruction_length = read_1_byte (abfd, line_ptr);
line_ptr += 1;
lh->opcode_base = read_1_byte (abfd, line_ptr);
line_ptr += 1;
- lh->standard_opcode_lengths = XNEWVEC (unsigned char, lh->opcode_base);
+ lh->standard_opcode_lengths.reset (new unsigned char[lh->opcode_base]);
lh->standard_opcode_lengths[0] = 1; /* This should never be used anyway. */
for (i = 1; i < lh->opcode_base; ++i)
line_ptr += 1;
}
- /* Read directory table. */
- while ((cur_dir = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL)
+ if (lh->version >= 5)
{
- line_ptr += bytes_read;
- add_include_dir (lh, cur_dir);
+ /* Read directory table. */
+ read_formatted_entries (abfd, &line_ptr, lh.get (), &cu->header,
+ [] (struct line_header *lh, const char *name,
+ 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,
+ dir_index d_index, unsigned int mod_time,
+ unsigned int length)
+ {
+ lh->add_file_name (name, d_index, mod_time, length);
+ });
}
- line_ptr += bytes_read;
-
- /* Read file name table. */
- while ((cur_file = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL)
+ else
{
- unsigned int dir_index, mod_time, length;
-
- line_ptr += bytes_read;
- 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);
+ /* Read directory table. */
+ while ((cur_dir = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL)
+ {
+ line_ptr += bytes_read;
+ lh->add_include_dir (cur_dir);
+ }
line_ptr += bytes_read;
- add_file_name (lh, cur_file, dir_index, mod_time, length);
+ /* Read file name table. */
+ while ((cur_file = read_direct_string (abfd, line_ptr, &bytes_read)) != NULL)
+ {
+ unsigned int mod_time, length;
+ dir_index d_index;
+
+ 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, d_index, mod_time, length);
+ }
+ line_ptr += bytes_read;
}
- line_ptr += bytes_read;
lh->statement_program_start = line_ptr;
if (line_ptr > (section->buffer + section->size))
_("line number info header doesn't "
"fit in `.debug_line' section"));
- discard_cleanups (back_to);
return lh;
}
const struct partial_symtab *pst,
const char *comp_dir)
{
- const struct file_entry fe = lh->file_names [file_index];
+ const file_entry &fe = lh->file_names[file_index];
const char *include_name = fe.name;
const char *include_name_to_compare = include_name;
- const char *dir_name = NULL;
const char *pst_filename;
char *copied_name = NULL;
int file_is_pst;
- if (fe.dir_index && lh->include_dirs != NULL)
- dir_name = lh->include_dirs[fe.dir_index - 1];
+ const char *dir_name = fe.include_dir (lh);
if (!IS_ABSOLUTE_PATH (include_name)
&& (dir_name != NULL || comp_dir != NULL))
/* State machine to track the state of the line number program. */
-typedef struct
+class lnp_state_machine
{
- /* These are part of the standard DWARF line number 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 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;
+ }
- unsigned char op_index;
- unsigned int file;
- unsigned int line;
- CORE_ADDR address;
- int is_stmt;
- unsigned int discriminator;
+ 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 *m_line_header;
+
+ /* These are part of the standard DWARF line number state machine,
+ and initialized according to the DWARF spec. */
+
+ unsigned char m_op_index = 0;
+ /* The line table index (1-based) of the current file. */
+ 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;
-} lnp_state_machine;
+ 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);
+}
-typedef struct
+void
+lnp_state_machine::handle_special_opcode (unsigned char op_code)
{
- /* The gdbarch. */
- struct gdbarch *gdbarch;
+ 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);
- /* The line number header. */
- struct line_header *line_header;
+ 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;
+}
- /* 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;
+void
+lnp_state_machine::handle_set_file (file_name_index file)
+{
+ m_file = file;
+
+ 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);
+
+ 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 file, line, discriminator;
- int is_stmt;
-
- file = state->file;
- 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, 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);
}
- if (file == 0 || file - 1 >= lh->num_file_names)
+ 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)
{
- lh->file_names[file - 1].included_p = 1;
- if (reader->record_lines_p && is_stmt)
+ fe->included_p = 1;
+ 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));
-
- /* Just starting, there is no "last file". */
- state->last_file = 0;
- state->last_subfile = NULL;
+ m_gdbarch = arch;
+ m_record_lines_p = record_lines_p;
+ m_line_header = lh;
- state->record_line = record_line;
+ m_record_line_callback = ::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;
+ 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 && lh->num_file_names >= state_machine.file)
+ if (record_lines_p)
{
- /* Start a subfile for the current file of the state machine. */
- /* lh->include_dirs and lh->file_names are 0-based, but the
- directory and file name numbers in the statement program
- are 1-based. */
- struct file_entry *fe = &lh->file_names[state_machine.file - 1];
- const char *dir = NULL;
+ /* Start a subfile for the current file of the state
+ machine. */
+ const file_entry *fe = state_machine.current_file ();
- if (fe->dir_index && lh->include_dirs != NULL)
- dir = lh->include_dirs[fe->dir_index - 1];
-
- dwarf2_start_subfile (fe->name, dir);
+ if (fe != NULL)
+ dwarf2_start_subfile (fe->name, fe->include_dir (lh));
}
/* Decode the table. */
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;
- add_file_name (lh, 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:
{
- /* The arrays lh->include_dirs and lh->file_names are
- 0-based, but the directory and file name numbers in
- the statement program are 1-based. */
- struct file_entry *fe;
- const char *dir = NULL;
-
- 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;
- if (state_machine.file == 0
- || state_machine.file - 1 >= lh->num_file_names)
- dwarf2_debug_line_missing_file_complaint ();
- else
- {
- fe = &lh->file_names[state_machine.file - 1];
- if (fe->dir_index && lh->include_dirs != NULL)
- dir = lh->include_dirs[fe->dir_index - 1];
- if (record_lines_p)
- {
- 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);
}
}
/* Now that we're done scanning the Line Header Program, we can
create the psymtab of each included file. */
- for (file_index = 0; file_index < lh->num_file_names; file_index++)
+ for (file_index = 0; file_index < lh->file_names.size (); file_index++)
if (lh->file_names[file_index].included_p == 1)
{
const char *include_name =
struct compunit_symtab *cust = buildsym_compunit_symtab ();
int i;
- for (i = 0; i < lh->num_file_names; i++)
+ for (i = 0; i < lh->file_names.size (); i++)
{
- const char *dir = NULL;
- struct file_entry *fe;
+ file_entry &fe = lh->file_names[i];
- fe = &lh->file_names[i];
- if (fe->dir_index && lh->include_dirs != NULL)
- dir = lh->include_dirs[fe->dir_index - 1];
- dwarf2_start_subfile (fe->name, dir);
+ dwarf2_start_subfile (fe.name, fe.include_dir (lh));
if (current_subfile->symtab == NULL)
{
current_subfile->symtab
= allocate_symtab (cust, current_subfile->name);
}
- fe->symtab = current_subfile->symtab;
+ fe.symtab = current_subfile->symtab;
}
}
}
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)
{
- 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 > cu->line_header->num_file_names)
+ if (cu->line_header != NULL)
+ fe = cu->line_header->file_name_at (file_index);
+ else
+ fe = NULL;
+
+ if (fe == NULL)
complaint (&symfile_complaints,
_("file index out of range"));
- else if (file_index > 0)
- {
- struct file_entry *fe;
-
- fe = &cu->line_header->file_names[file_index - 1];
- symbol_set_symtab (sym, fe->symtab);
- }
+ else
+ symbol_set_symtab (sym, fe->symtab);
}
switch (die->tag)
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
case DW_FORM_block4:
case DW_FORM_block:
case DW_FORM_exprloc:
+ case DW_FORM_data16:
blk = DW_BLOCK (attr);
if (TYPE_LENGTH (type) != blk->size)
dwarf2_const_value_length_mismatch_complaint (name, blk->size,
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);
}
this_type = read_tag_ptr_to_member_type (die, cu);
break;
case DW_TAG_reference_type:
- this_type = read_tag_reference_type (die, cu);
+ this_type = read_tag_reference_type (die, cu, TYPE_CODE_REF);
+ break;
+ case DW_TAG_rvalue_reference_type:
+ this_type = read_tag_reference_type (die, cu, TYPE_CODE_RVALUE_REF);
break;
case DW_TAG_const_type:
this_type = read_tag_const_type (die, cu);
{
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, "expression: size %s",
pulongest (DW_BLOCK (&die->attrs[i])->size));
break;
+ case DW_FORM_data16:
+ fprintf_unfiltered (f, "constant of 16 bytes");
+ break;
case DW_FORM_ref_addr:
fprintf_unfiltered (f, "ref address: ");
fputs_filtered (hex_string (DW_UNSND (&die->attrs[i])), f);
break;
case DW_FORM_string:
case DW_FORM_strp:
+ case DW_FORM_line_strp:
case DW_FORM_GNU_str_index:
case DW_FORM_GNU_strp_alt:
fprintf_unfiltered (f, "string: \"%s\" (%s canonicalized)",
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
return DW_UNSND (attr);
else
{
+ /* For DW_FORM_data16 see attr_form_is_constant. */
complaint (&symfile_complaints,
_("Attribute value is not a constant (%s)"),
dwarf_form_name (attr->form));
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);
case DW_FORM_block4:
case DW_FORM_block:
case DW_FORM_exprloc:
+ case DW_FORM_data16:
result = DW_BLOCK (attr)->data;
*len = DW_BLOCK (attr)->size;
break;
break;
case DW_FORM_sdata:
+ case DW_FORM_implicit_const:
type = die_type (die, cu);
result = write_constant_as_bytes (obstack, byte_order,
type, DW_SND (attr), len);
return result;
}
+/* Return the type of the die at OFFSET in PER_CU. Return NULL if no
+ valid type for this die is found. */
+
+struct type *
+dwarf2_fetch_die_type_sect_off (sect_offset sect_off,
+ struct dwarf2_per_cu_data *per_cu)
+{
+ struct dwarf2_cu *cu;
+ struct die_info *die;
+
+ dw2_setup (per_cu->objfile);
+
+ if (per_cu->cu == NULL)
+ load_cu (per_cu);
+ cu = per_cu->cu;
+ if (!cu)
+ return NULL;
+
+ die = follow_die_offset (sect_off, per_cu->is_dwz, &cu);
+ if (!die)
+ return NULL;
+
+ return die_type (die, cu);
+}
+
/* Return the type of the DIE at DIE_OFFSET in the CU named by
PER_CU. */
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);
}
{
/* Is the file number a valid index into the line header's file name
table? Remember that file numbers start with one, not zero. */
- if (1 <= file && file <= lh->num_file_names)
+ if (1 <= file && file <= lh->file_names.size ())
{
- struct file_entry *fe = &lh->file_names[file - 1];
+ const file_entry &fe = lh->file_names[file - 1];
- if (IS_ABSOLUTE_PATH (fe->name) || fe->dir_index == 0
- || lh->include_dirs == NULL)
- return xstrdup (fe->name);
- return concat (lh->include_dirs[fe->dir_index - 1], SLASH_STRING,
- fe->name, (char *) NULL);
+ if (!IS_ABSOLUTE_PATH (fe.name))
+ {
+ const char *dir = fe.include_dir (lh);
+ if (dir != NULL)
+ return concat (dir, SLASH_STRING, fe.name, (char *) NULL);
+ }
+ return xstrdup (fe.name);
}
else
{
{
/* Is the file number a valid index into the line header's file name
table? Remember that file numbers start with one, not zero. */
- if (1 <= file && file <= lh->num_file_names)
+ if (1 <= file && file <= lh->file_names.size ())
{
char *relative = file_file_name (file, lh);
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);
bytes += 8;
break;
+ case DW_FORM_data16:
+ bytes += 16;
+ break;
+
case DW_FORM_string:
read_direct_string (abfd, bytes, &bytes_read);
bytes += bytes_read;
}
break;
+ case DW_FORM_implicit_const:
+ break;
+
default:
{
- complain:
complaint (&symfile_complaints,
_("invalid form 0x%x in `%s'"),
form, get_section_name (section));
unsigned int version, flags;
version = read_2_bytes (abfd, mac_ptr);
- if (version != 4)
+ if (version != 4 && version != 5)
{
complaint (&symfile_complaints,
_("unrecognized version `%d' in .debug_macro section"),
}
/* A helper for dwarf_decode_macros that handles the GNU extensions,
- including DW_MACRO_GNU_transparent_include. */
+ including DW_MACRO_import. */
static void
dwarf_decode_macro_bytes (bfd *abfd,
case 0:
break;
- case DW_MACRO_GNU_define:
- case DW_MACRO_GNU_undef:
- case DW_MACRO_GNU_define_indirect:
- case DW_MACRO_GNU_undef_indirect:
- case DW_MACRO_GNU_define_indirect_alt:
- case DW_MACRO_GNU_undef_indirect_alt:
+ case DW_MACRO_define:
+ case DW_MACRO_undef:
+ case DW_MACRO_define_strp:
+ case DW_MACRO_undef_strp:
+ case DW_MACRO_define_sup:
+ case DW_MACRO_undef_sup:
{
unsigned int bytes_read;
int line;
line = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
mac_ptr += bytes_read;
- if (macinfo_type == DW_MACRO_GNU_define
- || macinfo_type == DW_MACRO_GNU_undef)
+ if (macinfo_type == DW_MACRO_define
+ || macinfo_type == DW_MACRO_undef)
{
body = read_direct_string (abfd, mac_ptr, &bytes_read);
mac_ptr += bytes_read;
str_offset = read_offset_1 (abfd, mac_ptr, offset_size);
mac_ptr += offset_size;
- if (macinfo_type == DW_MACRO_GNU_define_indirect_alt
- || macinfo_type == DW_MACRO_GNU_undef_indirect_alt
+ if (macinfo_type == DW_MACRO_define_sup
+ || macinfo_type == DW_MACRO_undef_sup
|| section_is_dwz)
{
struct dwz_file *dwz = dwarf2_get_dwz_file ();
body = read_indirect_string_at_offset (abfd, str_offset);
}
- is_define = (macinfo_type == DW_MACRO_GNU_define
- || macinfo_type == DW_MACRO_GNU_define_indirect
- || macinfo_type == DW_MACRO_GNU_define_indirect_alt);
+ is_define = (macinfo_type == DW_MACRO_define
+ || macinfo_type == DW_MACRO_define_strp
+ || macinfo_type == DW_MACRO_define_sup);
if (! current_file)
{
/* DWARF violation as no main source is present. */
parse_macro_definition (current_file, line, body);
else
{
- gdb_assert (macinfo_type == DW_MACRO_GNU_undef
- || macinfo_type == DW_MACRO_GNU_undef_indirect
- || macinfo_type == DW_MACRO_GNU_undef_indirect_alt);
+ gdb_assert (macinfo_type == DW_MACRO_undef
+ || macinfo_type == DW_MACRO_undef_strp
+ || macinfo_type == DW_MACRO_undef_sup);
macro_undef (current_file, line, body);
}
}
break;
- case DW_MACRO_GNU_start_file:
+ case DW_MACRO_start_file:
{
unsigned int bytes_read;
int line, file;
if (at_commandline)
{
- /* This DW_MACRO_GNU_start_file was executed in the
+ /* This DW_MACRO_start_file was executed in the
pass one. */
at_commandline = 0;
}
}
break;
- case DW_MACRO_GNU_end_file:
+ case DW_MACRO_end_file:
if (! current_file)
complaint (&symfile_complaints,
_("macro debug info has an unmatched "
}
break;
- case DW_MACRO_GNU_transparent_include:
- case DW_MACRO_GNU_transparent_include_alt:
+ case DW_MACRO_import:
+ case DW_MACRO_import_sup:
{
LONGEST offset;
void **slot;
offset = read_offset_1 (abfd, mac_ptr, offset_size);
mac_ptr += offset_size;
- if (macinfo_type == DW_MACRO_GNU_transparent_include_alt)
+ if (macinfo_type == DW_MACRO_import_sup)
{
struct dwz_file *dwz = dwarf2_get_dwz_file ();
/* This has actually happened; see
http://sourceware.org/bugzilla/show_bug.cgi?id=13568. */
complaint (&symfile_complaints,
- _("recursive DW_MACRO_GNU_transparent_include in "
+ _("recursive DW_MACRO_import in "
".debug_macro section"));
}
else
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 0:
break;
- case DW_MACRO_GNU_define:
- case DW_MACRO_GNU_undef:
+ case DW_MACRO_define:
+ case DW_MACRO_undef:
/* Only skip the data by MAC_PTR. */
{
unsigned int bytes_read;
}
break;
- case DW_MACRO_GNU_start_file:
+ case DW_MACRO_start_file:
{
unsigned int bytes_read;
int line, file;
}
break;
- case DW_MACRO_GNU_end_file:
+ case DW_MACRO_end_file:
/* No data to skip by MAC_PTR. */
break;
- case DW_MACRO_GNU_define_indirect:
- case DW_MACRO_GNU_undef_indirect:
- case DW_MACRO_GNU_define_indirect_alt:
- case DW_MACRO_GNU_undef_indirect_alt:
+ case DW_MACRO_define_strp:
+ case DW_MACRO_undef_strp:
+ case DW_MACRO_define_sup:
+ case DW_MACRO_undef_sup:
{
unsigned int bytes_read;
}
break;
- case DW_MACRO_GNU_transparent_include:
- case DW_MACRO_GNU_transparent_include_alt:
+ case DW_MACRO_import:
+ case DW_MACRO_import_sup:
/* Note that, according to the spec, a transparent include
- chain cannot call DW_MACRO_GNU_start_file. So, we can just
+ chain cannot call DW_MACRO_start_file. So, we can just
skip this opcode. */
mac_ptr += offset_size;
break;
(lineptr, loclistptr, macptr or rangelistptr). The DWARF spec says
that, if an attribute's can be either a constant or one of the
section offset classes, DW_FORM_data4 and DW_FORM_data8 should be
- taken as section offsets, not constants. */
+ taken as section offsets, not constants.
+
+ DW_FORM_data16 is not considered as dwarf2_get_attr_constant_value
+ cannot handle that. */
static int
attr_form_is_constant (const struct attribute *attr)
case DW_FORM_data2:
case DW_FORM_data4:
case DW_FORM_data8:
+ case DW_FORM_implicit_const:
return 1;
default:
return 0;
cu_debug_loc_section (struct dwarf2_cu *cu)
{
if (cu->dwo_unit)
- return &cu->dwo_unit->dwo_file->sections.loc;
- return &dwarf2_per_objfile->loc;
+ {
+ struct dwo_sections *sections = &cu->dwo_unit->dwo_file->sections;
+
+ return cu->header.version >= 5 ? §ions->loclists : §ions->loc;
+ }
+ return (cu->header.version >= 5 ? &dwarf2_per_objfile->loclists
+ : &dwarf2_per_objfile->loc);
}
/* A helper function that fills in a dwarf2_loclist_baton. */
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->objfile->obfd);
+ read_comp_unit_head (cu_headerp, info_ptr, per_cu->section,
+ rcuh_kind::COMPILE);
return cu_headerp;
}
return ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
}
+/* Return DWARF version number of PER_CU. */
+
+short
+dwarf2_version (struct dwarf2_per_cu_data *per_cu)
+{
+ return per_cu->dwarf_version;
+}
+
/* Locate the .debug_info compilation unit from CU's objfile which contains
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. */
+/* Write SIZE bytes from the buffer pointed to by DATA to FILE, with
+ error checking. */
-static hashval_t
-hash_strtab_entry (const void *e)
+static void
+file_write (FILE *file, const void *data, size_t size)
{
- const struct strtab_entry *entry = (const struct strtab_entry *) e;
- return mapped_index_string_hash (INT_MAX, entry->str);
+ if (fwrite (data, 1, size, file) != size)
+ error (_("couldn't data write to file"));
}
-/* Equality function for a strtab_entry. */
+/* Write the contents of VEC to FILE, with error checking. */
-static int
-eq_strtab_entry (const void *a, const void *b)
+template<typename Elem, typename Alloc>
+static void
+file_write (FILE *file, const std::vector<Elem, Alloc> &vec)
{
- 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);
+ file_write (file, vec.data (), vec.size () * sizeof (vec[0]));
}
-/* Create a strtab_entry hash table. */
-
-static htab_t
-create_strtab (void)
+/* In-memory buffer to prepare data to be written later to a file. */
+class data_buf
{
- return htab_create_alloc (100, hash_strtab_entry, eq_strtab_entry,
- xfree, xcalloc, xfree);
-}
+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)));
+ }
-/* Add a string to the constant pool. Return the string's offset in
- host order. */
+ /* 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));
+ }
-static offset_type
-add_string (htab_t table, struct obstack *cpool, const char *str)
-{
- void **slot;
- struct strtab_entry entry;
- struct strtab_entry *result;
+ /* Store INPUT as ULEB128 to the end of buffer. */
+ void append_unsigned_leb128 (ULONGEST input)
+ {
+ for (;;)
+ {
+ gdb_byte output = input & 0x7f;
+ input >>= 7;
+ if (input)
+ output |= 0x80;
+ append_data (output);
+ if (input == 0)
+ break;
+ }
+ }
- 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;
-}
+ /* 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);
+ }
+
+ /* Return the size of the buffer. */
+ size_t size () const
+ {
+ return m_vec.size ();
+ }
+
+ /* Return true iff the buffer is empty. */
+ bool empty () const
+ {
+ return m_vec.empty ();
+ }
+
+ /* Write the buffer to FILE. */
+ void file_write (FILE *file) const
+ {
+ ::file_write (file, m_vec);
+ }
+
+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;
+ }
+
+ gdb::byte_vector m_vec;
+};
/* An entry in the symbol table. */
struct symtab_index_entry
offset_type index_offset;
/* A sorted vector of the indices of all the CUs that hold an object
of this name. */
- VEC (offset_type) *cu_indices;
+ std::vector<offset_type> cu_indices;
};
/* The symbol table. This is a power-of-2-sized hash table. */
struct mapped_symtab
{
- offset_type n_elements;
- offset_type size;
- struct symtab_index_entry **data;
-};
-
-/* Hash function for a symtab_index_entry. */
-
-static hashval_t
-hash_symtab_entry (const void *e)
-{
- const struct symtab_index_entry *entry
- = (const struct symtab_index_entry *) e;
- return iterative_hash (VEC_address (offset_type, entry->cu_indices),
- sizeof (offset_type) * VEC_length (offset_type,
- entry->cu_indices),
- 0);
-}
-
-/* Equality function for a symtab_index_entry. */
-
-static int
-eq_symtab_entry (const void *a, const void *b)
-{
- const struct symtab_index_entry *ea = (const struct symtab_index_entry *) a;
- const struct symtab_index_entry *eb = (const struct symtab_index_entry *) b;
- int len = VEC_length (offset_type, ea->cu_indices);
- if (len != VEC_length (offset_type, eb->cu_indices))
- return 0;
- return !memcmp (VEC_address (offset_type, ea->cu_indices),
- VEC_address (offset_type, eb->cu_indices),
- sizeof (offset_type) * len);
-}
-
-/* Destroy a symtab_index_entry. */
-
-static void
-delete_symtab_entry (void *p)
-{
- struct symtab_index_entry *entry = (struct symtab_index_entry *) p;
- VEC_free (offset_type, entry->cu_indices);
- xfree (entry);
-}
-
-/* Create a hash table holding symtab_index_entry objects. */
-
-static htab_t
-create_symbol_hash_table (void)
-{
- return htab_create_alloc (100, hash_symtab_entry, eq_symtab_entry,
- delete_symtab_entry, xcalloc, xfree);
-}
-
-/* Create a new mapped symtab object. */
-
-static struct mapped_symtab *
-create_mapped_symtab (void)
-{
- struct mapped_symtab *symtab = XNEW (struct mapped_symtab);
- symtab->n_elements = 0;
- symtab->size = 1024;
- symtab->data = XCNEWVEC (struct symtab_index_entry *, symtab->size);
- return symtab;
-}
-
-/* Destroy a mapped_symtab. */
+ mapped_symtab ()
+ {
+ data.resize (1024);
+ }
-static void
-cleanup_mapped_symtab (void *p)
-{
- struct mapped_symtab *symtab = (struct mapped_symtab *) p;
- /* The contents of the array are freed when the other hash table is
- destroyed. */
- xfree (symtab->data);
- xfree (symtab);
-}
+ offset_type n_elements = 0;
+ std::vector<symtab_index_entry> data;
+};
-/* Find a slot in SYMTAB for the symbol NAME. Returns a pointer to
+/* Find a slot in SYMTAB for the symbol NAME. Returns a reference to
the slot.
Function is used only during write_hash_table so no index format backward
compatibility is needed. */
-static struct symtab_index_entry **
+static symtab_index_entry &
find_slot (struct mapped_symtab *symtab, const char *name)
{
offset_type index, step, hash = mapped_index_string_hash (INT_MAX, name);
- index = hash & (symtab->size - 1);
- step = ((hash * 17) & (symtab->size - 1)) | 1;
+ index = hash & (symtab->data.size () - 1);
+ step = ((hash * 17) & (symtab->data.size () - 1)) | 1;
for (;;)
{
- if (!symtab->data[index] || !strcmp (name, symtab->data[index]->name))
- return &symtab->data[index];
- index = (index + step) & (symtab->size - 1);
+ if (symtab->data[index].name == NULL
+ || strcmp (name, symtab->data[index].name) == 0)
+ return symtab->data[index];
+ index = (index + step) & (symtab->data.size () - 1);
}
}
static void
hash_expand (struct mapped_symtab *symtab)
{
- offset_type old_size = symtab->size;
- offset_type i;
- struct symtab_index_entry **old_entries = symtab->data;
+ auto old_entries = std::move (symtab->data);
- symtab->size *= 2;
- symtab->data = XCNEWVEC (struct symtab_index_entry *, symtab->size);
+ symtab->data.clear ();
+ symtab->data.resize (old_entries.size () * 2);
- for (i = 0; i < old_size; ++i)
- {
- if (old_entries[i])
- {
- struct symtab_index_entry **slot = find_slot (symtab,
- old_entries[i]->name);
- *slot = old_entries[i];
- }
- }
-
- xfree (old_entries);
+ for (auto &it : old_entries)
+ if (it.name != NULL)
+ {
+ auto &ref = find_slot (symtab, it.name);
+ ref = std::move (it);
+ }
}
/* Add an entry to SYMTAB. NAME is the name of the symbol.
int is_static, gdb_index_symbol_kind kind,
offset_type cu_index)
{
- struct symtab_index_entry **slot;
offset_type cu_index_and_attrs;
++symtab->n_elements;
- if (4 * symtab->n_elements / 3 >= symtab->size)
+ if (4 * symtab->n_elements / 3 >= symtab->data.size ())
hash_expand (symtab);
- slot = find_slot (symtab, name);
- if (!*slot)
+ symtab_index_entry &slot = find_slot (symtab, name);
+ if (slot.name == NULL)
{
- *slot = XNEW (struct symtab_index_entry);
- (*slot)->name = name;
+ slot.name = name;
/* index_offset is set later. */
- (*slot)->cu_indices = NULL;
}
cu_index_and_attrs = 0;
the last entry pushed), but a symbol could have multiple kinds in one CU.
To keep things simple we don't worry about the duplication here and
sort and uniqufy the list after we've processed all symbols. */
- VEC_safe_push (offset_type, (*slot)->cu_indices, cu_index_and_attrs);
-}
-
-/* qsort helper routine for uniquify_cu_indices. */
-
-static int
-offset_type_compare (const void *ap, const void *bp)
-{
- offset_type a = *(offset_type *) ap;
- offset_type b = *(offset_type *) bp;
-
- return (a > b) - (b > a);
+ slot.cu_indices.push_back (cu_index_and_attrs);
}
/* Sort and remove duplicates of all symbols' cu_indices lists. */
static void
uniquify_cu_indices (struct mapped_symtab *symtab)
{
- int i;
-
- for (i = 0; i < symtab->size; ++i)
+ for (auto &entry : symtab->data)
{
- struct symtab_index_entry *entry = symtab->data[i];
-
- if (entry
- && entry->cu_indices != NULL)
+ if (entry.name != NULL && !entry.cu_indices.empty ())
{
- unsigned int next_to_insert, next_to_check;
- offset_type last_value;
-
- qsort (VEC_address (offset_type, entry->cu_indices),
- VEC_length (offset_type, entry->cu_indices),
- sizeof (offset_type), offset_type_compare);
-
- last_value = VEC_index (offset_type, entry->cu_indices, 0);
- next_to_insert = 1;
- for (next_to_check = 1;
- next_to_check < VEC_length (offset_type, entry->cu_indices);
- ++next_to_check)
- {
- if (VEC_index (offset_type, entry->cu_indices, next_to_check)
- != last_value)
- {
- last_value = VEC_index (offset_type, entry->cu_indices,
- next_to_check);
- VEC_replace (offset_type, entry->cu_indices, next_to_insert,
- last_value);
- ++next_to_insert;
- }
- }
- VEC_truncate (offset_type, entry->cu_indices, next_to_insert);
+ auto &cu_indices = entry.cu_indices;
+ std::sort (cu_indices.begin (), cu_indices.end ());
+ auto from = std::unique (cu_indices.begin (), cu_indices.end ());
+ cu_indices.erase (from, cu_indices.end ());
}
}
}
-/* Add a vector of indices to the constant pool. */
-
-static offset_type
-add_indices_to_cpool (htab_t symbol_hash_table, struct obstack *cpool,
- struct symtab_index_entry *entry)
+/* A form of 'const char *' suitable for container keys. Only the
+ pointer is stored. The strings themselves are compared, not the
+ pointers. */
+class c_str_view
{
- void **slot;
+public:
+ c_str_view (const char *cstr)
+ : m_cstr (cstr)
+ {}
- slot = htab_find_slot (symbol_hash_table, entry, INSERT);
- if (!*slot)
- {
- offset_type len = VEC_length (offset_type, entry->cu_indices);
- offset_type val = MAYBE_SWAP (len);
- offset_type iter;
- int i;
+ bool operator== (const c_str_view &other) const
+ {
+ return strcmp (m_cstr, other.m_cstr) == 0;
+ }
- *slot = entry;
- entry->index_offset = obstack_object_size (cpool);
+ /* Return the underlying C string. Note, the returned string is
+ only a reference with lifetime of this object. */
+ const char *c_str () const
+ {
+ return 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;
-}
+private:
+ friend class c_str_view_hasher;
+ const char *const m_cstr;
+};
-/* Write the mapped hash table SYMTAB to the obstack OUTPUT, with
- constant pool entries going into the obstack CPOOL. */
+/* A std::unordered_map::hasher for 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);
+ }
+};
-static void
-write_hash_table (struct mapped_symtab *symtab,
- struct obstack *output, struct obstack *cpool)
+/* A std::unordered_map::hasher for std::vector<>. */
+template<typename T>
+class vector_hasher
{
- offset_type i;
- htab_t symbol_hash_table;
- htab_t str_table;
+public:
+ size_t operator () (const std::vector<T> &key) const
+ {
+ return iterative_hash (key.data (),
+ sizeof (key.front ()) * key.size (), 0);
+ }
+};
- symbol_hash_table = create_symbol_hash_table ();
- str_table = create_strtab ();
+/* 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 (mapped_symtab *symtab, data_buf &output, data_buf &cpool)
+{
+ {
+ /* 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);
}
/* Return the symbol kind of PSYM. */
-static gdb_index_symbol_kind
-symbol_kind (struct partial_symbol *psym)
-{
- domain_enum domain = PSYMBOL_DOMAIN (psym);
- enum address_class aclass = PSYMBOL_CLASS (psym);
+static gdb_index_symbol_kind
+symbol_kind (struct partial_symbol *psym)
+{
+ domain_enum domain = PSYMBOL_DOMAIN (psym);
+ enum address_class aclass = PSYMBOL_CLASS (psym);
+
+ switch (domain)
+ {
+ case VAR_DOMAIN:
+ switch (aclass)
+ {
+ case LOC_BLOCK:
+ return GDB_INDEX_SYMBOL_KIND_FUNCTION;
+ case LOC_TYPEDEF:
+ return GDB_INDEX_SYMBOL_KIND_TYPE;
+ case LOC_COMPUTED:
+ case LOC_CONST_BYTES:
+ case LOC_OPTIMIZED_OUT:
+ case LOC_STATIC:
+ return GDB_INDEX_SYMBOL_KIND_VARIABLE;
+ case LOC_CONST:
+ /* Note: It's currently impossible to recognize psyms as enum values
+ short of reading the type info. For now punt. */
+ return GDB_INDEX_SYMBOL_KIND_VARIABLE;
+ default:
+ /* There are other LOC_FOO values that one might want to classify
+ as variables, but dwarf2read.c doesn't currently use them. */
+ return GDB_INDEX_SYMBOL_KIND_OTHER;
+ }
+ case STRUCT_DOMAIN:
+ return GDB_INDEX_SYMBOL_KIND_TYPE;
+ default:
+ return GDB_INDEX_SYMBOL_KIND_OTHER;
+ }
+}
+
+/* Add a list of partial symbols to SYMTAB. */
+
+static void
+write_psymbols (struct mapped_symtab *symtab,
+ std::unordered_set<partial_symbol *> &psyms_seen,
+ struct partial_symbol **psymp,
+ int count,
+ offset_type cu_index,
+ int is_static)
+{
+ for (; count-- > 0; ++psymp)
+ {
+ struct partial_symbol *psym = *psymp;
+
+ if (SYMBOL_LANGUAGE (psym) == language_ada)
+ error (_("Ada is not currently supported by the index"));
+
+ /* Only add a given psymbol once. */
+ if (psyms_seen.insert (psym).second)
+ {
+ gdb_index_symbol_kind kind = symbol_kind (psym);
+
+ add_index_entry (symtab, SYMBOL_SEARCH_NAME (psym),
+ is_static, kind, cu_index);
+ }
+ }
+}
+
+/* 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;
+ data_buf &types_list;
+ std::unordered_set<partial_symbol *> &psyms_seen;
+ int cu_index;
+};
+
+/* A helper function that writes a single signatured_type to an
+ obstack. */
+
+static int
+write_one_signatured_type (void **slot, void *d)
+{
+ struct signatured_type_index_data *info
+ = (struct signatured_type_index_data *) d;
+ struct signatured_type *entry = (struct signatured_type *) *slot;
+ struct partial_symtab *psymtab = entry->per_cu.v.psymtab;
+
+ write_psymbols (info->symtab,
+ info->psyms_seen,
+ &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[psymtab->statics_offset],
+ psymtab->n_static_syms, info->cu_index,
+ 1);
+
+ 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. */
+
+static void
+recursively_write_psymbols (struct objfile *objfile,
+ struct partial_symtab *psymtab,
+ struct mapped_symtab *symtab,
+ std::unordered_set<partial_symbol *> &psyms_seen,
+ offset_type cu_index)
+{
+ int i;
+
+ for (i = 0; i < psymtab->number_of_dependencies; ++i)
+ if (psymtab->dependencies[i]->user != NULL)
+ recursively_write_psymbols (objfile, psymtab->dependencies[i],
+ symtab, psyms_seen, cu_index);
+
+ write_psymbols (symtab,
+ psyms_seen,
+ &objfile->global_psymbols[psymtab->globals_offset],
+ psymtab->n_global_syms, cu_index,
+ 0);
+ write_psymbols (symtab,
+ psyms_seen,
+ &objfile->static_psymbols[psymtab->statics_offset],
+ psymtab->n_static_syms, cu_index,
+ 1);
+}
+
+/* DWARF-5 .debug_names builder. */
+class debug_names
+{
+public:
+ debug_names (bool is_dwarf64, bfd_endian dwarf5_byte_order)
+ : m_dwarf5_byte_order (dwarf5_byte_order),
+ m_dwarf32 (dwarf5_byte_order),
+ m_dwarf64 (dwarf5_byte_order),
+ m_dwarf (is_dwarf64
+ ? static_cast<dwarf &> (m_dwarf64)
+ : static_cast<dwarf &> (m_dwarf32)),
+ m_name_table_string_offs (m_dwarf.name_table_string_offs),
+ m_name_table_entry_offs (m_dwarf.name_table_entry_offs)
+ {}
+
+ int dwarf5_offset_size () const
+ {
+ const bool dwarf5_is_dwarf64 = &m_dwarf == &m_dwarf64;
+ return dwarf5_is_dwarf64 ? 8 : 4;
+ }
+
+ /* Is this symbol from DW_TAG_compile_unit or DW_TAG_type_unit? */
+ enum class unit_kind { cu, tu };
+
+ /* Insert one symbol. */
+ void insert (const partial_symbol *psym, int cu_index, bool is_static,
+ unit_kind kind)
+ {
+ const int dwarf_tag = psymbol_tag (psym);
+ if (dwarf_tag == 0)
+ return;
+ const char *const name = SYMBOL_SEARCH_NAME (psym);
+ const auto insertpair
+ = m_name_to_value_set.emplace (c_str_view (name),
+ std::set<symbol_value> ());
+ std::set<symbol_value> &value_set = insertpair.first->second;
+ value_set.emplace (symbol_value (dwarf_tag, cu_index, is_static, kind));
+ }
+
+ /* Build all the tables. All symbols must be already inserted.
+ This function does not call file_write, caller has to do it
+ afterwards. */
+ void build ()
+ {
+ /* Verify the build method has not be called twice. */
+ gdb_assert (m_abbrev_table.empty ());
+ const size_t name_count = m_name_to_value_set.size ();
+ m_bucket_table.resize
+ (std::pow (2, std::ceil (std::log2 (name_count * 4 / 3))));
+ m_hash_table.reserve (name_count);
+ m_name_table_string_offs.reserve (name_count);
+ m_name_table_entry_offs.reserve (name_count);
+
+ /* Map each hash of symbol to its name and value. */
+ struct hash_it_pair
+ {
+ uint32_t hash;
+ decltype (m_name_to_value_set)::const_iterator it;
+ };
+ std::vector<std::forward_list<hash_it_pair>> bucket_hash;
+ bucket_hash.resize (m_bucket_table.size ());
+ for (decltype (m_name_to_value_set)::const_iterator it
+ = m_name_to_value_set.cbegin ();
+ it != m_name_to_value_set.cend ();
+ ++it)
+ {
+ const char *const name = it->first.c_str ();
+ const uint32_t hash = dwarf5_djb_hash (name);
+ hash_it_pair hashitpair;
+ hashitpair.hash = hash;
+ hashitpair.it = it;
+ auto &slot = bucket_hash[hash % bucket_hash.size()];
+ slot.push_front (std::move (hashitpair));
+ }
+ for (size_t bucket_ix = 0; bucket_ix < bucket_hash.size (); ++bucket_ix)
+ {
+ const std::forward_list<hash_it_pair> &hashitlist
+ = bucket_hash[bucket_ix];
+ if (hashitlist.empty ())
+ continue;
+ uint32_t &bucket_slot = m_bucket_table[bucket_ix];
+ /* The hashes array is indexed starting at 1. */
+ store_unsigned_integer (reinterpret_cast<gdb_byte *> (&bucket_slot),
+ sizeof (bucket_slot), m_dwarf5_byte_order,
+ m_hash_table.size () + 1);
+ for (const hash_it_pair &hashitpair : hashitlist)
+ {
+ m_hash_table.push_back (0);
+ store_unsigned_integer (reinterpret_cast<gdb_byte *>
+ (&m_hash_table.back ()),
+ sizeof (m_hash_table.back ()),
+ m_dwarf5_byte_order, hashitpair.hash);
+ const c_str_view &name = hashitpair.it->first;
+ const std::set<symbol_value> &value_set = hashitpair.it->second;
+ m_name_table_string_offs.push_back_reorder
+ (m_debugstrlookup.lookup (name.c_str ()));
+ m_name_table_entry_offs.push_back_reorder (m_entry_pool.size ());
+ gdb_assert (!value_set.empty ());
+ for (const symbol_value &value : value_set)
+ {
+ int &idx = m_indexkey_to_idx[index_key (value.dwarf_tag,
+ value.is_static,
+ value.kind)];
+ if (idx == 0)
+ {
+ idx = m_idx_next++;
+ m_abbrev_table.append_unsigned_leb128 (idx);
+ m_abbrev_table.append_unsigned_leb128 (value.dwarf_tag);
+ m_abbrev_table.append_unsigned_leb128
+ (value.kind == unit_kind::cu ? DW_IDX_compile_unit
+ : DW_IDX_type_unit);
+ m_abbrev_table.append_unsigned_leb128 (DW_FORM_udata);
+ m_abbrev_table.append_unsigned_leb128 (value.is_static
+ ? DW_IDX_GNU_internal
+ : DW_IDX_GNU_external);
+ m_abbrev_table.append_unsigned_leb128 (DW_FORM_flag_present);
+
+ /* Terminate attributes list. */
+ m_abbrev_table.append_unsigned_leb128 (0);
+ m_abbrev_table.append_unsigned_leb128 (0);
+ }
+
+ m_entry_pool.append_unsigned_leb128 (idx);
+ m_entry_pool.append_unsigned_leb128 (value.cu_index);
+ }
+
+ /* Terminate the list of CUs. */
+ m_entry_pool.append_unsigned_leb128 (0);
+ }
+ }
+ gdb_assert (m_hash_table.size () == name_count);
+
+ /* Terminate tags list. */
+ m_abbrev_table.append_unsigned_leb128 (0);
+ }
+
+ /* Return .debug_names bucket count. This must be called only after
+ calling the build method. */
+ uint32_t bucket_count () const
+ {
+ /* Verify the build method has been already called. */
+ gdb_assert (!m_abbrev_table.empty ());
+ const uint32_t retval = m_bucket_table.size ();
+
+ /* Check for overflow. */
+ gdb_assert (retval == m_bucket_table.size ());
+ return retval;
+ }
+
+ /* Return .debug_names names count. This must be called only after
+ calling the build method. */
+ uint32_t name_count () const
+ {
+ /* Verify the build method has been already called. */
+ gdb_assert (!m_abbrev_table.empty ());
+ const uint32_t retval = m_hash_table.size ();
+
+ /* Check for overflow. */
+ gdb_assert (retval == m_hash_table.size ());
+ return retval;
+ }
+
+ /* Return number of bytes of .debug_names abbreviation table. This
+ must be called only after calling the build method. */
+ uint32_t abbrev_table_bytes () const
+ {
+ gdb_assert (!m_abbrev_table.empty ());
+ return m_abbrev_table.size ();
+ }
+
+ /* Recurse into all "included" dependencies and store their symbols
+ as if they appeared in this psymtab. */
+ void recursively_write_psymbols
+ (struct objfile *objfile,
+ struct partial_symtab *psymtab,
+ std::unordered_set<partial_symbol *> &psyms_seen,
+ int cu_index)
+ {
+ for (int i = 0; i < psymtab->number_of_dependencies; ++i)
+ if (psymtab->dependencies[i]->user != NULL)
+ recursively_write_psymbols (objfile, psymtab->dependencies[i],
+ psyms_seen, cu_index);
+
+ write_psymbols (psyms_seen,
+ &objfile->global_psymbols[psymtab->globals_offset],
+ psymtab->n_global_syms, cu_index, false, unit_kind::cu);
+ write_psymbols (psyms_seen,
+ &objfile->static_psymbols[psymtab->statics_offset],
+ psymtab->n_static_syms, cu_index, true, unit_kind::cu);
+ }
+
+ /* Return number of bytes the .debug_names section will have. This
+ must be called only after calling the build method. */
+ size_t bytes () const
+ {
+ /* Verify the build method has been already called. */
+ gdb_assert (!m_abbrev_table.empty ());
+ size_t expected_bytes = 0;
+ expected_bytes += m_bucket_table.size () * sizeof (m_bucket_table[0]);
+ expected_bytes += m_hash_table.size () * sizeof (m_hash_table[0]);
+ expected_bytes += m_name_table_string_offs.bytes ();
+ expected_bytes += m_name_table_entry_offs.bytes ();
+ expected_bytes += m_abbrev_table.size ();
+ expected_bytes += m_entry_pool.size ();
+ return expected_bytes;
+ }
+
+ /* Write .debug_names to FILE_NAMES and .debug_str addition to
+ FILE_STR. This must be called only after calling the build
+ method. */
+ void file_write (FILE *file_names, FILE *file_str) const
+ {
+ /* Verify the build method has been already called. */
+ gdb_assert (!m_abbrev_table.empty ());
+ ::file_write (file_names, m_bucket_table);
+ ::file_write (file_names, m_hash_table);
+ m_name_table_string_offs.file_write (file_names);
+ m_name_table_entry_offs.file_write (file_names);
+ m_abbrev_table.file_write (file_names);
+ m_entry_pool.file_write (file_names);
+ m_debugstrlookup.file_write (file_str);
+ }
+
+ /* A helper user data for write_one_signatured_type. */
+ class write_one_signatured_type_data
+ {
+ public:
+ write_one_signatured_type_data (debug_names &nametable_,
+ signatured_type_index_data &&info_)
+ : nametable (nametable_), info (std::move (info_))
+ {}
+ debug_names &nametable;
+ struct signatured_type_index_data info;
+ };
+
+ /* A helper function to pass write_one_signatured_type to
+ htab_traverse_noresize. */
+ static int
+ write_one_signatured_type (void **slot, void *d)
+ {
+ write_one_signatured_type_data *data = (write_one_signatured_type_data *) d;
+ struct signatured_type_index_data *info = &data->info;
+ struct signatured_type *entry = (struct signatured_type *) *slot;
+
+ data->nametable.write_one_signatured_type (entry, info);
+
+ return 1;
+ }
+
+private:
+
+ /* Storage for symbol names mapping them to their .debug_str section
+ offsets. */
+ class debug_str_lookup
+ {
+ public:
+
+ /* Object costructor to be called for current DWARF2_PER_OBJFILE.
+ All .debug_str section strings are automatically stored. */
+ debug_str_lookup ()
+ : m_abfd (dwarf2_per_objfile->objfile->obfd)
+ {
+ dwarf2_read_section (dwarf2_per_objfile->objfile,
+ &dwarf2_per_objfile->str);
+ if (dwarf2_per_objfile->str.buffer == NULL)
+ return;
+ for (const gdb_byte *data = dwarf2_per_objfile->str.buffer;
+ data < (dwarf2_per_objfile->str.buffer
+ + dwarf2_per_objfile->str.size);)
+ {
+ const char *const s = reinterpret_cast<const char *> (data);
+ const auto insertpair
+ = m_str_table.emplace (c_str_view (s),
+ data - dwarf2_per_objfile->str.buffer);
+ if (!insertpair.second)
+ complaint (&symfile_complaints,
+ _("Duplicate string \"%s\" in "
+ ".debug_str section [in module %s]"),
+ s, bfd_get_filename (m_abfd));
+ data += strlen (s) + 1;
+ }
+ }
+
+ /* Return offset of symbol name S in the .debug_str section. Add
+ such symbol to the section's end if it does not exist there
+ yet. */
+ size_t lookup (const char *s)
+ {
+ const auto it = m_str_table.find (c_str_view (s));
+ if (it != m_str_table.end ())
+ return it->second;
+ const size_t offset = (dwarf2_per_objfile->str.size
+ + m_str_add_buf.size ());
+ m_str_table.emplace (c_str_view (s), offset);
+ m_str_add_buf.append_cstr0 (s);
+ return offset;
+ }
+
+ /* Append the end of the .debug_str section to FILE. */
+ void file_write (FILE *file) const
+ {
+ m_str_add_buf.file_write (file);
+ }
+
+ private:
+ std::unordered_map<c_str_view, size_t, c_str_view_hasher> m_str_table;
+ bfd *const m_abfd;
+
+ /* Data to add at the end of .debug_str for new needed symbol names. */
+ data_buf m_str_add_buf;
+ };
+
+ /* Container to map used DWARF tags to their .debug_names abbreviation
+ tags. */
+ class index_key
+ {
+ public:
+ index_key (int dwarf_tag_, bool is_static_, unit_kind kind_)
+ : dwarf_tag (dwarf_tag_), is_static (is_static_), kind (kind_)
+ {
+ }
+
+ bool
+ operator== (const index_key &other) const
+ {
+ return (dwarf_tag == other.dwarf_tag && is_static == other.is_static
+ && kind == other.kind);
+ }
+
+ const int dwarf_tag;
+ const bool is_static;
+ const unit_kind kind;
+ };
+
+ /* Provide std::unordered_map::hasher for index_key. */
+ class index_key_hasher
+ {
+ public:
+ size_t
+ operator () (const index_key &key) const
+ {
+ return (std::hash<int>() (key.dwarf_tag) << 1) | key.is_static;
+ }
+ };
+
+ /* Parameters of one symbol entry. */
+ class symbol_value
+ {
+ public:
+ const int dwarf_tag, cu_index;
+ const bool is_static;
+ const unit_kind kind;
+
+ symbol_value (int dwarf_tag_, int cu_index_, bool is_static_,
+ unit_kind kind_)
+ : dwarf_tag (dwarf_tag_), cu_index (cu_index_), is_static (is_static_),
+ kind (kind_)
+ {}
+
+ bool
+ operator< (const symbol_value &other) const
+ {
+#define X(n) \
+ do \
+ { \
+ if (n < other.n) \
+ return true; \
+ if (n > other.n) \
+ return false; \
+ } \
+ while (0)
+ X (dwarf_tag);
+ X (is_static);
+ X (kind);
+ X (cu_index);
+#undef X
+ return false;
+ }
+ };
+
+ /* Abstract base class to unify DWARF-32 and DWARF-64 name table
+ output. */
+ class offset_vec
+ {
+ protected:
+ const bfd_endian dwarf5_byte_order;
+ public:
+ explicit offset_vec (bfd_endian dwarf5_byte_order_)
+ : dwarf5_byte_order (dwarf5_byte_order_)
+ {}
+
+ /* Call std::vector::reserve for NELEM elements. */
+ virtual void reserve (size_t nelem) = 0;
+
+ /* Call std::vector::push_back with store_unsigned_integer byte
+ reordering for ELEM. */
+ virtual void push_back_reorder (size_t elem) = 0;
+
+ /* Return expected output size in bytes. */
+ virtual size_t bytes () const = 0;
+
+ /* Write name table to FILE. */
+ virtual void file_write (FILE *file) const = 0;
+ };
+
+ /* Template to unify DWARF-32 and DWARF-64 output. */
+ template<typename OffsetSize>
+ class offset_vec_tmpl : public offset_vec
+ {
+ public:
+ explicit offset_vec_tmpl (bfd_endian dwarf5_byte_order_)
+ : offset_vec (dwarf5_byte_order_)
+ {}
- switch (domain)
+ /* Implement offset_vec::reserve. */
+ void reserve (size_t nelem) override
{
- case VAR_DOMAIN:
- switch (aclass)
- {
- case LOC_BLOCK:
- return GDB_INDEX_SYMBOL_KIND_FUNCTION;
- case LOC_TYPEDEF:
- return GDB_INDEX_SYMBOL_KIND_TYPE;
- case LOC_COMPUTED:
- case LOC_CONST_BYTES:
- case LOC_OPTIMIZED_OUT:
- case LOC_STATIC:
- return GDB_INDEX_SYMBOL_KIND_VARIABLE;
- case LOC_CONST:
- /* Note: It's currently impossible to recognize psyms as enum values
- short of reading the type info. For now punt. */
- return GDB_INDEX_SYMBOL_KIND_VARIABLE;
- default:
- /* There are other LOC_FOO values that one might want to classify
- as variables, but dwarf2read.c doesn't currently use them. */
- return GDB_INDEX_SYMBOL_KIND_OTHER;
- }
- case STRUCT_DOMAIN:
- return GDB_INDEX_SYMBOL_KIND_TYPE;
- default:
- return GDB_INDEX_SYMBOL_KIND_OTHER;
+ m_vec.reserve (nelem);
}
-}
-
-/* Add a list of partial symbols to SYMTAB. */
-static void
-write_psymbols (struct mapped_symtab *symtab,
- htab_t psyms_seen,
- struct partial_symbol **psymp,
- int count,
- offset_type cu_index,
- int is_static)
-{
- for (; count-- > 0; ++psymp)
+ /* Implement offset_vec::push_back_reorder. */
+ void push_back_reorder (size_t elem) override
{
- struct partial_symbol *psym = *psymp;
- void **slot;
-
- if (SYMBOL_LANGUAGE (psym) == language_ada)
- error (_("Ada is not currently supported by the index"));
+ m_vec.push_back (elem);
+ /* Check for overflow. */
+ gdb_assert (m_vec.back () == elem);
+ store_unsigned_integer (reinterpret_cast<gdb_byte *> (&m_vec.back ()),
+ sizeof (m_vec.back ()), dwarf5_byte_order, elem);
+ }
- /* Only add a given psymbol once. */
- slot = htab_find_slot (psyms_seen, psym, INSERT);
- if (!*slot)
- {
- gdb_index_symbol_kind kind = symbol_kind (psym);
+ /* Implement offset_vec::bytes. */
+ size_t bytes () const override
+ {
+ return m_vec.size () * sizeof (m_vec[0]);
+ }
- *slot = psym;
- add_index_entry (symtab, SYMBOL_SEARCH_NAME (psym),
- is_static, kind, cu_index);
- }
+ /* Implement offset_vec::file_write. */
+ void file_write (FILE *file) const override
+ {
+ ::file_write (file, m_vec);
}
-}
-/* Write the contents of an ("unfinished") obstack to FILE. Throw an
- exception if there is an error. */
+ private:
+ std::vector<OffsetSize> m_vec;
+ };
-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"));
-}
+ /* Base class to unify DWARF-32 and DWARF-64 .debug_names output
+ respecting name table width. */
+ class dwarf
+ {
+ public:
+ offset_vec &name_table_string_offs, &name_table_entry_offs;
-/* Unlink a file if the argument is not NULL. */
+ dwarf (offset_vec &name_table_string_offs_,
+ offset_vec &name_table_entry_offs_)
+ : name_table_string_offs (name_table_string_offs_),
+ name_table_entry_offs (name_table_entry_offs_)
+ {
+ }
+ };
-static void
-unlink_if_set (void *p)
-{
- char **filename = (char **) p;
- if (*filename)
- unlink (*filename);
-}
+ /* Template to unify DWARF-32 and DWARF-64 .debug_names output
+ respecting name table width. */
+ template<typename OffsetSize>
+ class dwarf_tmpl : public dwarf
+ {
+ public:
+ explicit dwarf_tmpl (bfd_endian dwarf5_byte_order_)
+ : dwarf (m_name_table_string_offs, m_name_table_entry_offs),
+ m_name_table_string_offs (dwarf5_byte_order_),
+ m_name_table_entry_offs (dwarf5_byte_order_)
+ {}
+
+ private:
+ offset_vec_tmpl<OffsetSize> m_name_table_string_offs;
+ offset_vec_tmpl<OffsetSize> m_name_table_entry_offs;
+ };
-/* A helper struct used when iterating over debug_types. */
-struct signatured_type_index_data
-{
- struct objfile *objfile;
- struct mapped_symtab *symtab;
- struct obstack *types_list;
- htab_t psyms_seen;
- int cu_index;
-};
+ /* Try to reconstruct original DWARF tag for given partial_symbol.
+ This function is not DWARF-5 compliant but it is sufficient for
+ GDB as a DWARF-5 index consumer. */
+ static int psymbol_tag (const struct partial_symbol *psym)
+ {
+ domain_enum domain = PSYMBOL_DOMAIN (psym);
+ enum address_class aclass = PSYMBOL_CLASS (psym);
-/* A helper function that writes a single signatured_type to an
- obstack. */
+ switch (domain)
+ {
+ case VAR_DOMAIN:
+ switch (aclass)
+ {
+ case LOC_BLOCK:
+ return DW_TAG_subprogram;
+ case LOC_TYPEDEF:
+ return DW_TAG_typedef;
+ case LOC_COMPUTED:
+ case LOC_CONST_BYTES:
+ case LOC_OPTIMIZED_OUT:
+ case LOC_STATIC:
+ return DW_TAG_variable;
+ case LOC_CONST:
+ /* Note: It's currently impossible to recognize psyms as enum values
+ short of reading the type info. For now punt. */
+ return DW_TAG_variable;
+ default:
+ /* There are other LOC_FOO values that one might want to classify
+ as variables, but dwarf2read.c doesn't currently use them. */
+ return DW_TAG_variable;
+ }
+ case STRUCT_DOMAIN:
+ return DW_TAG_structure_type;
+ default:
+ return 0;
+ }
+ }
-static int
-write_one_signatured_type (void **slot, void *d)
-{
- struct signatured_type_index_data *info
- = (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];
+ /* Call insert for all partial symbols and mark them in PSYMS_SEEN. */
+ void write_psymbols (std::unordered_set<partial_symbol *> &psyms_seen,
+ struct partial_symbol **psymp, int count, int cu_index,
+ bool is_static, unit_kind kind)
+ {
+ for (; count-- > 0; ++psymp)
+ {
+ struct partial_symbol *psym = *psymp;
- write_psymbols (info->symtab,
- info->psyms_seen,
- info->objfile->global_psymbols.list
- + 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,
- psymtab->n_static_syms, info->cu_index,
- 1);
+ if (SYMBOL_LANGUAGE (psym) == language_ada)
+ error (_("Ada is not currently supported by the index"));
- 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);
+ /* Only add a given psymbol once. */
+ if (psyms_seen.insert (psym).second)
+ insert (psym, cu_index, is_static, kind);
+ }
+ }
- ++info->cu_index;
+ /* A helper function that writes a single signatured_type
+ to a debug_names. */
+ void
+ write_one_signatured_type (struct signatured_type *entry,
+ struct signatured_type_index_data *info)
+ {
+ struct partial_symtab *psymtab = entry->per_cu.v.psymtab;
- return 1;
-}
+ write_psymbols (info->psyms_seen,
+ &info->objfile->global_psymbols[psymtab->globals_offset],
+ psymtab->n_global_syms, info->cu_index, false,
+ unit_kind::tu);
+ write_psymbols (info->psyms_seen,
+ &info->objfile->static_psymbols[psymtab->statics_offset],
+ psymtab->n_static_syms, info->cu_index, true,
+ unit_kind::tu);
-/* Recurse into all "included" dependencies and write their symbols as
- if they appeared in this psymtab. */
+ info->types_list.append_uint (dwarf5_offset_size (), m_dwarf5_byte_order,
+ to_underlying (entry->per_cu.sect_off));
-static void
-recursively_write_psymbols (struct objfile *objfile,
- struct partial_symtab *psymtab,
- struct mapped_symtab *symtab,
- htab_t psyms_seen,
- offset_type cu_index)
-{
- int i;
+ ++info->cu_index;
+ }
- for (i = 0; i < psymtab->number_of_dependencies; ++i)
- if (psymtab->dependencies[i]->user != NULL)
- recursively_write_psymbols (objfile, psymtab->dependencies[i],
- symtab, psyms_seen, cu_index);
+ /* Store value of each symbol. */
+ std::unordered_map<c_str_view, std::set<symbol_value>, c_str_view_hasher>
+ m_name_to_value_set;
- write_psymbols (symtab,
- psyms_seen,
- objfile->global_psymbols.list + psymtab->globals_offset,
- psymtab->n_global_syms, cu_index,
- 0);
- write_psymbols (symtab,
- psyms_seen,
- objfile->static_psymbols.list + psymtab->statics_offset,
- psymtab->n_static_syms, cu_index,
- 1);
-}
+ /* Tables of DWARF-5 .debug_names. They are in object file byte
+ order. */
+ std::vector<uint32_t> m_bucket_table;
+ std::vector<uint32_t> m_hash_table;
-/* Create an index file for OBJFILE in the directory DIR. */
+ const bfd_endian m_dwarf5_byte_order;
+ dwarf_tmpl<uint32_t> m_dwarf32;
+ dwarf_tmpl<uint64_t> m_dwarf64;
+ dwarf &m_dwarf;
+ offset_vec &m_name_table_string_offs, &m_name_table_entry_offs;
+ debug_str_lookup m_debugstrlookup;
-static void
-write_psymtabs_to_index (struct objfile *objfile, const char *dir)
-{
- struct cleanup *cleanup;
- char *filename, *cleanup_filename;
- struct obstack contents, addr_obstack, constant_pool, symtab_obstack;
- 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;
+ /* Map each used .debug_names abbreviation tag parameter to its
+ index value. */
+ std::unordered_map<index_key, int, index_key_hasher> m_indexkey_to_idx;
- if (dwarf2_per_objfile->using_index)
- error (_("Cannot use an index to create the index"));
+ /* Next unused .debug_names abbreviation tag for
+ m_indexkey_to_idx. */
+ int m_idx_next = 1;
- if (VEC_length (dwarf2_section_info_def, dwarf2_per_objfile->types) > 1)
- error (_("Cannot make an index when the file has multiple .debug_types sections"));
+ /* .debug_names abbreviation table. */
+ data_buf m_abbrev_table;
- if (!objfile->psymtabs || !objfile->psymtabs_addrmap)
- return;
+ /* .debug_names entry pool. */
+ data_buf m_entry_pool;
+};
- if (stat (objfile_name (objfile), &st) < 0)
- perror_with_name (objfile_name (objfile));
+/* Return iff any of the needed offsets does not fit into 32-bit
+ .debug_names section. */
- filename = concat (dir, SLASH_STRING, lbasename (objfile_name (objfile)),
- INDEX_SUFFIX, (char *) NULL);
- cleanup = make_cleanup (xfree, filename);
+static bool
+check_dwarf64_offsets ()
+{
+ for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ {
+ const dwarf2_per_cu_data &per_cu = *dwarf2_per_objfile->all_comp_units[i];
- out_file = gdb_fopen_cloexec (filename, "wb");
- if (!out_file)
- error (_("Can't open `%s' for writing"), filename);
+ if (to_underlying (per_cu.sect_off) >= (static_cast<uint64_t> (1) << 32))
+ return true;
+ }
+ for (int i = 0; i < dwarf2_per_objfile->n_type_units; ++i)
+ {
+ const signatured_type &sigtype = *dwarf2_per_objfile->all_type_units[i];
+ const dwarf2_per_cu_data &per_cu = sigtype.per_cu;
- cleanup_filename = filename;
- make_cleanup (unlink_if_set, &cleanup_filename);
+ if (to_underlying (per_cu.sect_off) >= (static_cast<uint64_t> (1) << 32))
+ return true;
+ }
+ return false;
+}
- symtab = create_mapped_symtab ();
- make_cleanup (cleanup_mapped_symtab, symtab);
+/* 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. */
- obstack_init (&addr_obstack);
- make_cleanup_obstack_free (&addr_obstack);
+static size_t
+psyms_seen_size ()
+{
+ 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;
- obstack_init (&cu_list);
- make_cleanup_obstack_free (&cu_list);
+ 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. */
+ return psyms_count / 4;
+}
- obstack_init (&types_cu_list);
- make_cleanup_obstack_free (&types_cu_list);
+/* Write new .gdb_index section for OBJFILE into OUT_FILE.
+ Return how many bytes were expected to be written into OUT_FILE. */
- htab_up psyms_seen (htab_create_alloc (100, htab_hash_pointer,
- htab_eq_pointer,
- NULL, xcalloc, xfree));
+static size_t
+write_gdbindex (struct objfile *objfile, FILE *out_file)
+{
+ 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)
+
+ std::unordered_set<partial_symbol *> psyms_seen (psyms_seen_size ());
+ 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);
+ contents.append_data (MAYBE_SWAP (total_len));
+ total_len += constant_pool.size ();
+
+ gdb_assert (contents.size () == size_of_contents);
+
+ 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);
+
+ return total_len;
+}
+
+/* DWARF-5 augmentation string for GDB's DW_IDX_GNU_* extension. */
+static const gdb_byte dwarf5_gdb_augmentation[] = { 'G', 'D', 'B', 0 };
+
+/* Write a new .debug_names section for OBJFILE into OUT_FILE, write
+ needed addition to .debug_str section to OUT_FILE_STR. Return how
+ many bytes were expected to be written into OUT_FILE. */
+
+static size_t
+write_debug_names (struct objfile *objfile, FILE *out_file, FILE *out_file_str)
+{
+ const bool dwarf5_is_dwarf64 = check_dwarf64_offsets ();
+ const enum bfd_endian dwarf5_byte_order
+ = gdbarch_byte_order (get_objfile_arch (objfile));
+
+ /* 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. */
+ data_buf cu_list;
+ debug_names nametable (dwarf5_is_dwarf64, dwarf5_byte_order);
+ std::unordered_set<partial_symbol *> psyms_seen (psyms_seen_size ());
+ for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+ {
+ const dwarf2_per_cu_data *per_cu = dwarf2_per_objfile->all_comp_units[i];
+ partial_symtab *psymtab = per_cu->v.psymtab;
+
+ /* 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 need to be present in .debug_names. */
+ if (psymtab == NULL)
+ continue;
+
+ if (psymtab->user == NULL)
+ nametable.recursively_write_psymbols (objfile, psymtab, psyms_seen, i);
+
+ cu_list.append_uint (nametable.dwarf5_offset_size (), dwarf5_byte_order,
+ to_underlying (per_cu->sect_off));
+ }
- gdb_assert (obstack_object_size (&contents) == size_of_contents);
+ /* Write out the .debug_type entries, if any. */
+ data_buf types_cu_list;
+ if (dwarf2_per_objfile->signatured_types)
+ {
+ debug_names::write_one_signatured_type_data sig_data (nametable,
+ signatured_type_index_data (types_cu_list, psyms_seen));
+
+ sig_data.info.objfile = objfile;
+ /* It is used only for gdb_index. */
+ sig_data.info.symtab = nullptr;
+ sig_data.info.cu_index = 0;
+ htab_traverse_noresize (dwarf2_per_objfile->signatured_types,
+ debug_names::write_one_signatured_type,
+ &sig_data);
+ }
+
+ nametable.build ();
+
+ /* No addr_vec - DWARF-5 uses .debug_aranges generated by GCC. */
+
+ const offset_type bytes_of_header
+ = ((dwarf5_is_dwarf64 ? 12 : 4)
+ + 2 + 2 + 7 * 4
+ + sizeof (dwarf5_gdb_augmentation));
+ size_t expected_bytes = 0;
+ expected_bytes += bytes_of_header;
+ expected_bytes += cu_list.size ();
+ expected_bytes += types_cu_list.size ();
+ expected_bytes += nametable.bytes ();
+ data_buf header;
+
+ if (!dwarf5_is_dwarf64)
+ {
+ const uint64_t size64 = expected_bytes - 4;
+ gdb_assert (size64 < 0xfffffff0);
+ header.append_uint (4, dwarf5_byte_order, size64);
+ }
+ else
+ {
+ header.append_uint (4, dwarf5_byte_order, 0xffffffff);
+ header.append_uint (8, dwarf5_byte_order, expected_bytes - 12);
+ }
+
+ /* The version number. */
+ header.append_uint (2, dwarf5_byte_order, 5);
+
+ /* Padding. */
+ header.append_uint (2, dwarf5_byte_order, 0);
+
+ /* comp_unit_count - The number of CUs in the CU list. */
+ header.append_uint (4, dwarf5_byte_order, dwarf2_per_objfile->n_comp_units);
+
+ /* local_type_unit_count - The number of TUs in the local TU
+ list. */
+ header.append_uint (4, dwarf5_byte_order, dwarf2_per_objfile->n_type_units);
+
+ /* foreign_type_unit_count - The number of TUs in the foreign TU
+ list. */
+ header.append_uint (4, dwarf5_byte_order, 0);
+
+ /* bucket_count - The number of hash buckets in the hash lookup
+ table. */
+ header.append_uint (4, dwarf5_byte_order, nametable.bucket_count ());
+
+ /* name_count - The number of unique names in the index. */
+ header.append_uint (4, dwarf5_byte_order, nametable.name_count ());
+
+ /* abbrev_table_size - The size in bytes of the abbreviations
+ table. */
+ header.append_uint (4, dwarf5_byte_order, nametable.abbrev_table_bytes ());
+
+ /* augmentation_string_size - The size in bytes of the augmentation
+ string. This value is rounded up to a multiple of 4. */
+ static_assert (sizeof (dwarf5_gdb_augmentation) % 4 == 0, "");
+ header.append_uint (4, dwarf5_byte_order, sizeof (dwarf5_gdb_augmentation));
+ header.append_data (dwarf5_gdb_augmentation);
+
+ gdb_assert (header.size () == bytes_of_header);
+
+ header.file_write (out_file);
+ cu_list.file_write (out_file);
+ types_cu_list.file_write (out_file);
+ nametable.file_write (out_file, out_file_str);
+
+ return expected_bytes;
+}
+
+/* Assert that FILE's size is EXPECTED_SIZE. Assumes file's seek
+ position is at the end of the file. */
- 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);
+static void
+assert_file_size (FILE *file, const char *filename, size_t expected_size)
+{
+ const auto file_size = ftell (file);
+ if (file_size == -1)
+ error (_("Can't get `%s' size"), filename);
+ gdb_assert (file_size == expected_size);
+}
+
+/* Create an index file for OBJFILE in the directory DIR. */
+
+static void
+write_psymtabs_to_index (struct objfile *objfile, const char *dir,
+ dw_index_kind index_kind)
+{
+ if (dwarf2_per_objfile->using_index)
+ error (_("Cannot use an index to create the index"));
+
+ if (VEC_length (dwarf2_section_info_def, dwarf2_per_objfile->types) > 1)
+ error (_("Cannot make an index when the file has multiple .debug_types sections"));
+
+ if (!objfile->psymtabs || !objfile->psymtabs_addrmap)
+ return;
- fclose (out_file);
+ struct stat st;
+ if (stat (objfile_name (objfile), &st) < 0)
+ perror_with_name (objfile_name (objfile));
+
+ std::string filename (std::string (dir) + SLASH_STRING
+ + lbasename (objfile_name (objfile))
+ + (index_kind == dw_index_kind::DEBUG_NAMES
+ ? INDEX5_SUFFIX : INDEX4_SUFFIX));
- /* We want to keep the file, so we set cleanup_filename to NULL
- here. See unlink_if_set. */
- cleanup_filename = NULL;
+ FILE *out_file = gdb_fopen_cloexec (filename.c_str (), "wb").release ();
+ if (!out_file)
+ error (_("Can't open `%s' for writing"), filename.c_str ());
+
+ /* 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);
+
+ if (index_kind == dw_index_kind::DEBUG_NAMES)
+ {
+ std::string filename_str (std::string (dir) + SLASH_STRING
+ + lbasename (objfile_name (objfile))
+ + DEBUG_STR_SUFFIX);
+ FILE *out_file_str
+ = gdb_fopen_cloexec (filename_str.c_str (), "wb").release ();
+ if (!out_file_str)
+ error (_("Can't open `%s' for writing"), filename_str.c_str ());
+ gdb::unlinker unlink_file_str (filename_str.c_str ());
+ gdb_file_up close_out_file_str (out_file_str);
+
+ const size_t total_len
+ = write_debug_names (objfile, out_file, out_file_str);
+ assert_file_size (out_file, filename.c_str (), total_len);
+
+ /* We want to keep the file .debug_str file too. */
+ unlink_file_str.keep ();
+ }
+ else
+ {
+ const size_t total_len
+ = write_gdbindex (objfile, out_file);
+ assert_file_size (out_file, filename.c_str (), total_len);
+ }
- do_cleanups (cleanup);
+ /* We want to keep the file. */
+ unlink_file.keep ();
}
/* Implementation of the `save gdb-index' command.
- Note that the file format used by this command is documented in the
- GDB manual. Any changes here must be documented there. */
+ Note that the .gdb_index file format used by this command is
+ documented in the 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;
+ const char dwarf5space[] = "-dwarf-5 ";
+ dw_index_kind index_kind = dw_index_kind::GDB_INDEX;
+
+ if (!arg)
+ arg = "";
+
+ arg = skip_spaces (arg);
+ if (strncmp (arg, dwarf5space, strlen (dwarf5space)) == 0)
+ {
+ index_kind = dw_index_kind::DEBUG_NAMES;
+ arg += strlen (dwarf5space);
+ arg = skip_spaces (arg);
+ }
- if (!arg || !*arg)
- error (_("usage: save gdb-index DIRECTORY"));
+ if (!*arg)
+ error (_("usage: save gdb-index [-dwarf-5] DIRECTORY"));
ALL_OBJFILES (objfile)
{
TRY
{
- write_psymtabs_to_index (objfile, arg);
+ write_psymtabs_to_index (objfile, arg, index_kind);
}
CATCH (except, RETURN_MASK_ERROR)
{
value);
}
-void _initialize_dwarf2_read (void);
-
void
_initialize_dwarf2_read (void)
{
c = add_cmd ("gdb-index", class_files, save_gdb_index_command,
_("\
Save a gdb-index file.\n\
-Usage: save gdb-index DIRECTORY"),
+Usage: save gdb-index [-dwarf-5] DIRECTORY\n\
+\n\
+No options create one file with .gdb-index extension for pre-DWARF-5\n\
+compatible .gdb_index section. With -dwarf-5 creates two files with\n\
+extension .debug_names and .debug_str for DWARF-5 .debug_names section."),
&save_cmdlist);
set_cmd_completer (c, filename_completer);
&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
}