#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 <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 final : 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 final : 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;
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;
/* The mapped index, or NULL if .gdb_index is missing or not being used. */
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
separate table of all line table entries to support the sharing.
{ ".debug_frame", ".zdebug_frame" },
{ ".eh_frame", NULL },
{ ".gdb_index", ".zgdb_index" },
+ { ".debug_names", ".zdebug_names" },
+ { ".debug_aranges", ".zdebug_aranges" },
23
};
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;
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
/* 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
const struct comp_unit_head *,
unsigned int *);
+static const char *read_indirect_string_at_offset (bfd *abfd,
+ LONGEST str_offset);
+
static const char *read_indirect_string_from_dwz (struct dwz_file *, LONGEST);
static LONGEST read_signed_leb128 (bfd *, const gdb_byte *, unsigned int *);
static void read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu);
+static void read_variable (struct die_info *die, struct dwarf2_cu *cu);
+
static int dwarf2_ranges_read (unsigned, CORE_ADDR *, CORE_ADDR *,
struct dwarf2_cu *, struct partial_symtab *);
}
\f
-#if WORDS_BIGENDIAN
-
-/* Convert VALUE between big- and little-endian. */
-static offset_type
-byte_swap (offset_type value)
-{
- offset_type result;
-
- result = (value & 0xff) << 24;
- result |= (value & 0xff00) << 8;
- result |= (value & 0xff0000) >> 8;
- result |= (value & 0xff000000) >> 24;
- return result;
-}
-
-#define MAYBE_SWAP(V) byte_swap (V)
-
-#else
-#define MAYBE_SWAP(V) static_cast<offset_type> (V)
-#endif /* WORDS_BIGENDIAN */
/* Read the given attribute value as an address, taking the attribute's
form into account. */
}
/* The suffix for an index file. */
-#define INDEX_SUFFIX ".gdb-index"
+#define INDEX4_SUFFIX ".gdb-index"
+#define INDEX5_SUFFIX ".debug_names"
+#define DEBUG_STR_SUFFIX ".debug_str"
/* See declaration. */
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)
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))
+ {
+ 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)
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)
{
- 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))
bfd_map_over_sections (result->dwz_bfd, locate_dwz_sections, result);
- do_cleanups (cleanup);
-
gdb_bfd_record_inclusion (dwarf2_per_objfile->objfile->obfd, result->dwz_bfd);
dwarf2_per_objfile->dwz_file = result;
return result;
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. */
ULONGEST length = extract_unsigned_integer (cu_list + 8, 8, BFD_ENDIAN_LITTLE);
cu_list += 2 * 8;
- 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;
- 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);
}
}
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. */
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->objfile_obstack);
}
+/* 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
SYMBOL_HASH_NEXT, but we keep a separate copy to maintain control over the
implementation. This is necessary because the hash function is tied to the
/* 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;
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
- && SYMBOL_MATCHES_SEARCH_NAME (sym, name))
+ && SYMBOL_MATCHES_SEARCH_NAME (sym, lookup_name))
return stab;
if (with_opaque != NULL
- && SYMBOL_MATCHES_SEARCH_NAME (with_opaque, name))
+ && 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,
- gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
- gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
- gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
- enum search_domain kind)
-{
- int i;
- offset_type iter;
- struct mapped_index *index;
+/* 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);
+ }
+ }
+}
+
+bool
+gdb_index_symbol_name_matcher::matches (const char *symbol_name)
+{
+ for (auto matches_name : m_symbol_name_matcher_funcs)
+ if (matches_name (symbol_name, m_lookup_name, NULL))
+ return true;
+
+ return false;
+}
+
+/* Starting from a search name, return the string that finds the upper
+ bound of all strings that start with SEARCH_NAME in a sorted name
+ list. Returns the empty string to indicate that the upper bound is
+ the end of the list. */
+
+static std::string
+make_sort_after_prefix_name (const char *search_name)
+{
+ /* When looking to complete "func", we find the upper bound of all
+ symbols that start with "func" by looking for where we'd insert
+ the closest string that would follow "func" in lexicographical
+ order. Usually, that's "func"-with-last-character-incremented,
+ i.e. "fund". Mind non-ASCII characters, though. Usually those
+ will be UTF-8 multi-byte sequences, but we can't be certain.
+ Especially mind the 0xff character, which is a valid character in
+ non-UTF-8 source character sets (e.g. Latin1 'ÿ'), and we can't
+ rule out compilers allowing it in identifiers. Note that
+ conveniently, strcmp/strcasecmp are specified to compare
+ characters interpreted as unsigned char. So what we do is treat
+ the whole string as a base 256 number composed of a sequence of
+ base 256 "digits" and add 1 to it. I.e., adding 1 to 0xff wraps
+ to 0, and carries 1 to the following more-significant position.
+ If the very first character in SEARCH_NAME ends up incremented
+ and carries/overflows, then the upper bound is the end of the
+ list. The string after the empty string is also the empty
+ string.
+
+ Some examples of this operation:
+
+ SEARCH_NAME => "+1" RESULT
+
+ "abc" => "abd"
+ "ab\xff" => "ac"
+ "\xff" "a" "\xff" => "\xff" "b"
+ "\xff" => ""
+ "\xff\xff" => ""
+ "" => ""
+
+ Then, with these symbols for example:
+
+ func
+ func1
+ fund
+
+ completing "func" looks for symbols between "func" and
+ "func"-with-last-character-incremented, i.e. "fund" (exclusive),
+ which finds "func" and "func1", but not "fund".
+
+ And with:
+
+ funcÿ (Latin1 'ÿ' [0xff])
+ funcÿ1
+ fund
+
+ completing "funcÿ" looks for symbols between "funcÿ" and "fund"
+ (exclusive), which finds "funcÿ" and "funcÿ1", but not "fund".
+
+ And with:
+
+ ÿÿ (Latin1 'ÿ' [0xff])
+ ÿÿ1
+
+ completing "ÿ" or "ÿÿ" looks for symbols between between "ÿÿ" and
+ the end of the list.
+ */
+ std::string after = search_name;
+ while (!after.empty () && (unsigned char) after.back () == 0xff)
+ after.pop_back ();
+ if (!after.empty ())
+ after.back () = (unsigned char) after.back () + 1;
+ return after;
+}
+
+/* See declaration. */
+
+std::pair<std::vector<name_component>::const_iterator,
+ std::vector<name_component>::const_iterator>
+mapped_index_base::find_name_components_bounds
+ (const lookup_name_info &lookup_name_without_params) const
+{
+ auto *name_cmp
+ = this->name_components_casing == case_sensitive_on ? strcmp : strcasecmp;
+
+ const char *cplus
+ = lookup_name_without_params.cplus ().lookup_name ().c_str ();
+
+ /* Comparison function object for lower_bound that matches against a
+ given symbol name. */
+ auto lookup_compare_lower = [&] (const name_component &elem,
+ const char *name)
+ {
+ const char *elem_qualified = this->symbol_name_at (elem.idx);
+ const char *elem_name = elem_qualified + elem.name_offset;
+ return name_cmp (elem_name, name) < 0;
+ };
+
+ /* Comparison function object for upper_bound that matches against a
+ given symbol name. */
+ auto lookup_compare_upper = [&] (const char *name,
+ const name_component &elem)
+ {
+ const char *elem_qualified = this->symbol_name_at (elem.idx);
+ const char *elem_name = elem_qualified + elem.name_offset;
+ return name_cmp (name, elem_name) < 0;
+ };
+
+ auto begin = this->name_components.begin ();
+ auto end = this->name_components.end ();
+
+ /* Find the lower bound. */
+ auto lower = [&] ()
+ {
+ if (lookup_name_without_params.completion_mode () && cplus[0] == '\0')
+ return begin;
+ else
+ return std::lower_bound (begin, end, cplus, lookup_compare_lower);
+ } ();
+
+ /* Find the upper bound. */
+ auto upper = [&] ()
+ {
+ if (lookup_name_without_params.completion_mode ())
+ {
+ /* In completion mode, we want UPPER to point past all
+ symbols names that have the same prefix. I.e., with
+ these symbols, and completing "func":
+
+ function << lower bound
+ function1
+ other_function << upper bound
+
+ We find the upper bound by looking for the insertion
+ point of "func"-with-last-character-incremented,
+ i.e. "fund". */
+ std::string after = make_sort_after_prefix_name (cplus);
+ if (after.empty ())
+ return end;
+ return std::lower_bound (lower, end, after.c_str (),
+ lookup_compare_lower);
+ }
+ else
+ return std::upper_bound (lower, end, cplus, lookup_compare_upper);
+ } ();
+
+ return {lower, upper};
+}
+
+/* See declaration. */
+
+void
+mapped_index_base::build_name_components ()
+{
+ if (!this->name_components.empty ())
+ return;
+
+ this->name_components_casing = case_sensitivity;
+ auto *name_cmp
+ = this->name_components_casing == case_sensitive_on ? strcmp : strcasecmp;
+
+ /* The code below only knows how to break apart components of C++
+ symbol names (and other languages that use '::' as
+ namespace/module separator). If we add support for wild matching
+ to some language that uses some other operator (E.g., Ada, Go and
+ D use '.'), then we'll need to try splitting the symbol name
+ according to that language too. Note that Ada does support wild
+ matching, but doesn't currently support .gdb_index. */
+ auto count = this->symbol_name_count ();
+ for (offset_type idx = 0; idx < count; idx++)
+ {
+ if (this->symbol_name_slot_invalid (idx))
+ continue;
+
+ const char *name = this->symbol_name_at (idx);
+
+ /* Add each name component to the name component table. */
+ unsigned int previous_len = 0;
+ for (unsigned int current_len = cp_find_first_component (name);
+ name[current_len] != '\0';
+ current_len += cp_find_first_component (name + current_len))
+ {
+ gdb_assert (name[current_len] == ':');
+ this->name_components.push_back ({previous_len, idx});
+ /* Skip the '::'. */
+ current_len += 2;
+ previous_len = current_len;
+ }
+ this->name_components.push_back ({previous_len, idx});
+ }
+
+ /* Sort name_components elements by name. */
+ auto name_comp_compare = [&] (const name_component &left,
+ const name_component &right)
+ {
+ const char *left_qualified = this->symbol_name_at (left.idx);
+ const char *right_qualified = this->symbol_name_at (right.idx);
+
+ const char *left_name = left_qualified + left.name_offset;
+ const char *right_name = right_qualified + right.name_offset;
+
+ return name_cmp (left_name, right_name) < 0;
+ };
+
+ std::sort (this->name_components.begin (),
+ this->name_components.end (),
+ name_comp_compare);
+}
+
+/* Helper for dw2_expand_symtabs_matching that works with a
+ mapped_index_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_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)
+{
+ lookup_name_info lookup_name_without_params
+ = lookup_name_in.make_ignore_params ();
+ gdb_index_symbol_name_matcher lookup_name_matcher
+ (lookup_name_without_params);
+
+ /* Build the symbol name component sorted vector, if we haven't
+ yet. */
+ index.build_name_components ();
+
+ auto bounds = index.find_name_components_bounds (lookup_name_without_params);
+
+ /* Now for each symbol name in range, check to see if we have a name
+ match, and if so, call the MATCH_CALLBACK callback. */
+
+ /* The same symbol may appear more than once in the range though.
+ E.g., if we're looking for symbols that complete "w", and we have
+ a symbol named "w1::w2", we'll find the two name components for
+ that same symbol in the range. To be sure we only call the
+ callback once per symbol, we first collect the symbol name
+ indexes that matched in a temporary vector and ignore
+ duplicates. */
+ std::vector<offset_type> matches;
+ matches.reserve (std::distance (bounds.first, bounds.second));
+
+ for (; bounds.first != bounds.second; ++bounds.first)
+ {
+ const char *qualified = index.symbol_name_at (bounds.first->idx);
+
+ if (!lookup_name_matcher.matches (qualified)
+ || (symbol_matcher != NULL && !symbol_matcher (qualified)))
+ continue;
+
+ matches.push_back (bounds.first->idx);
+ }
+
+ std::sort (matches.begin (), matches.end ());
+
+ /* Finally call the callback, once per match. */
+ ULONGEST prev = -1;
+ for (offset_type idx : matches)
+ {
+ if (prev != idx)
+ {
+ match_callback (idx);
+ prev = idx;
+ }
+ }
+
+ /* Above we use a type wider than idx's for 'prev', since 0 and
+ (offset_type)-1 are both possible values. */
+ static_assert (sizeof (prev) > sizeof (offset_type), "");
+}
+
+#if GDB_SELF_TEST
+
+namespace selftests { namespace dw2_expand_symtabs_matching {
+
+/* A 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 (file_matcher (file_data->file_names[j], false))
- {
- per_cu->v.quick->mark = 1;
- break;
- }
+ 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);
- /* 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;
+ 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;
- 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;
- }
- }
+ dwarf2_section_info *section = VEC_index (dwarf2_section_info_def,
+ dwarf2_per_objfile->types, 0);
- slot = htab_find_slot (per_cu->v.quick->mark
- ? visited_found.get ()
- : visited_not_found.get (),
- file_data, INSERT);
- *slot = file_data;
- }
+ create_signatured_type_table_from_debug_names
+ (objfile, local_map, section, &dwarf2_per_objfile->abbrev);
}
- 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;
+ create_addrmap_from_aranges (objfile, &dwarf2_per_objfile->debug_aranges);
- QUIT;
+ 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);
- if (index->symbol_table[idx] == 0 && index->symbol_table[idx + 1] == 0)
- continue;
+ return true;
+}
- name = index->constant_pool + MAYBE_SWAP (index->symbol_table[idx]);
+/* Symbol name hashing function as specified by DWARF-5. */
- if (!symbol_matcher (name))
- continue;
+static uint32_t
+dwarf5_djb_hash (const char *str_)
+{
+ const unsigned char *str = (const unsigned char *) str_;
- /* 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);
+ /* Note: tolower here ignores UTF-8, which isn't fully compliant.
+ See http://dwarfstd.org/ShowIssue.php?issue=161027.1. */
- /* Work around gold/15646. */
- if (attrs_valid)
- {
- if (!is_static && global_seen)
- continue;
- if (!is_static)
- global_seen = 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);
- /* Only check the symbol's kind if it has one. */
- if (attrs_valid)
+ if (without_params != NULL)
{
- 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;
- }
+ name = without_params.get();
}
+ }
+ }
- /* Don't crash on bad data. */
- if (cu_index >= (dwarf2_per_objfile->n_comp_units
- + dwarf2_per_objfile->n_type_units))
+ 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,
- _(".gdb_index entry has bad CU index"
- " [in module %s]"), objfile_name (objfile));
- continue;
+ _("Wrong .debug_names hash for string at index %u "
+ "[in module %s]"),
+ namei, objfile_name (dwarf2_per_objfile->objfile));
+ return NULL;
}
+#endif
- per_cu = dw2_get_cutu (cu_index);
- if (file_matcher == NULL || per_cu->v.quick->mark)
+ if (cmp (namei_string, name) == 0)
{
- int symtab_was_null =
- (per_cu->v.quick->compunit_symtab == NULL);
-
- dw2_instantiate_symtab (per_cu);
-
- if (expansion_notify != NULL
- && symtab_was_null
- && per_cu->v.quick->compunit_symtab != NULL)
- {
- expansion_notify (per_cu->v.quick->compunit_symtab);
- }
+ 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;
}
}
-/* A helper for dw2_find_pc_sect_compunit_symtab which finds the most specific
- symtab. */
+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;
+ }
-static struct compunit_symtab *
-recursively_find_pc_sect_compunit_symtab (struct compunit_symtab *cust,
- CORE_ADDR pc)
+ 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 ()
{
- int i;
+ if (m_addr == NULL)
+ return NULL;
- if (COMPUNIT_BLOCKVECTOR (cust) != NULL
- && blockvector_contains_pc (COMPUNIT_BLOCKVECTOR (cust), pc))
- return cust;
+ bfd *const abfd = dwarf2_per_objfile->objfile->obfd;
- if (cust->includes == NULL)
+ 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;
- for (i = 0; cust->includes[i]; ++i)
+ const auto indexval_it = m_map.abbrev_map.find (abbrev);
+ if (indexval_it == m_map.abbrev_map.cend ())
{
- struct compunit_symtab *s = cust->includes[i];
+ 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)
+ {
+ 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;
+ }
+ }
- s = recursively_find_pc_sect_compunit_symtab (s, pc);
- if (s != NULL)
- return s;
+ /* 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;
}
- return NULL;
+ /* 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 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)
+dw2_debug_names_lookup_symbol (struct objfile *objfile, int block_index_int,
+ const char *name, domain_enum domain)
{
- struct dwarf2_per_cu_data *data;
- struct compunit_symtab *result;
-
+ const block_enum block_index = static_cast<block_enum> (block_index_int);
dw2_setup (objfile);
- if (!objfile->psymtabs_addrmap)
- return NULL;
+ const auto &mapp = dwarf2_per_objfile->debug_names_table;
+ if (!mapp)
+ {
+ /* index is NULL if OBJF_READNOW. */
+ return NULL;
+ }
+ const auto &map = *mapp;
- data = (struct dwarf2_per_cu_data *) addrmap_find (objfile->psymtabs_addrmap,
- pc);
- if (!data)
- return NULL;
+ dw2_debug_names_iterator iter (map, true /* want_specific_block */,
+ block_index, domain, name);
- 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));
+ 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;
+}
- result
- = recursively_find_pc_sect_compunit_symtab (dw2_instantiate_symtab (data),
- pc);
- gdb_assert (result != NULL);
- return result;
+/* 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_map_symbol_filenames (struct objfile *objfile, symbol_filename_ftype *fun,
- void *data, int need_fullname)
+dw2_debug_names_expand_symtabs_for_function (struct objfile *objfile,
+ const char *func_name)
{
dw2_setup (objfile);
- if (!dwarf2_per_objfile->filenames_cache)
+ /* dwarf2_per_objfile->debug_names_table is NULL if OBJF_READNOW. */
+ if (dwarf2_per_objfile->debug_names_table)
{
- 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);
+ const mapped_debug_names &map = *dwarf2_per_objfile->debug_names_table;
- *slot = per_cu->v.quick->file_names;
- }
- }
+ /* 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);
- 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;
+ struct dwarf2_per_cu_data *per_cu;
+ while ((per_cu = iter.next ()) != NULL)
+ dw2_instantiate_symtab (per_cu);
+ }
+}
- /* We only need to look at symtabs not already expanded. */
- if (per_cu->v.quick->compunit_symtab)
- continue;
+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);
- file_data = dw2_get_file_names (per_cu);
- if (file_data == NULL)
- continue;
+ /* debug_names_table is NULL if OBJF_READNOW. */
+ if (!dwarf2_per_objfile->debug_names_table)
+ return;
- slot = htab_find_slot (visited.get (), file_data, INSERT);
- if (*slot)
- {
- /* Already visited. */
- continue;
- }
- *slot = file_data;
+ dw_expand_symtabs_matching_file_matcher (file_matcher);
- 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);
- }
- }
- }
+ mapped_debug_names &map = *dwarf2_per_objfile->debug_names_table;
- dwarf2_per_objfile->filenames_cache->traverse ([&] (const char *filename)
+ dw2_expand_symtabs_matching_symbol (map, lookup_name,
+ symbol_matcher,
+ kind, [&] (offset_type namei)
{
- gdb::unique_xmalloc_ptr<char> this_real_name;
+ /* The name was matched, now expand corresponding CUs that were
+ marked. */
+ dw2_debug_names_iterator iter (map, kind, namei);
- if (need_fullname)
- this_real_name = gdb_realpath (filename);
- (*fun) (filename, this_real_name.get (), data);
+ struct dwarf2_per_cu_data *per_cu;
+ while ((per_cu = iter.next ()) != NULL)
+ dw2_expand_symtabs_matching_one (per_cu, file_matcher,
+ expansion_notify);
});
}
-static int
-dw2_has_symbols (struct objfile *objfile)
-{
- return 1;
-}
-
-const struct quick_symbol_functions dwarf2_gdb_index_functions =
+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
{
rcuh_kind section_kind)
{
const gdb_byte *beg_of_comp_unit = info_ptr;
- bfd *abfd = get_section_bfd_owner (section);
header->sect_off = (sect_offset) (beg_of_comp_unit - section->buffer);
struct dwarf2_section_info *section;
bfd *abfd;
const gdb_byte *begin_info_ptr, *info_ptr;
- ULONGEST signature; /* Or dwo_id. */
struct attribute *comp_dir, *stmt_list, *low_pc, *high_pc, *ranges;
int i,num_extra_attrs;
struct dwarf2_section_info *dwo_abbrev_section;
struct die_info *comp_unit_die)
{
struct dwarf2_cu *cu = this_cu->cu;
- struct attribute *attr;
ULONGEST signature;
struct dwo_unit *dwo_unit;
const char *comp_dir, *dwo_name;
struct partial_symtab *pst;
pst = start_psymtab_common (objfile, name, 0,
- objfile->global_psymbols.next,
- objfile->static_psymbols.next);
+ objfile->global_psymbols,
+ objfile->static_psymbols);
pst->psymtabs_addrmap_supported = 1;
}
}
-/* 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 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. */
auto_obstack temp_obstack;
- objfile->psymtabs_addrmap = addrmap_create_mutable (&temp_obstack);
- addrmap_cleanup = make_cleanup (psymtabs_addrmap_cleanup, objfile);
+
+ 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);
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",
break;
case DW_TAG_constant:
{
- struct psymbol_allocation_list *list;
+ std::vector<partial_symbol *> *list;
if (pdi->is_external)
list = &objfile->global_psymbols;
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. */
process_imported_unit_die (die, cu);
break;
+ case DW_TAG_variable:
+ read_variable (die, cu);
+ break;
+
default:
new_symbol (die, NULL, cu);
break;
{
if (die_needs_namespace (die, cu))
{
- long length;
const char *prefix;
const char *canonical_name = NULL;
{
struct objfile *objfile = cu->objfile;
const char *retval, *mangled = NULL, *canon = NULL;
- struct cleanup *back_to;
int need_copy = 1;
/* In this case dwarf2_compute_name is just a shortcut not building anything
if (!die_needs_namespace (die, cu))
return dwarf2_compute_name (name, die, cu, 1);
- back_to = make_cleanup (null_cleanup, NULL);
-
mangled = dw2_linkage_name (die, cu);
/* rustc emits invalid values for DW_AT_linkage_name. Ignore these.
/* DW_AT_linkage_name is missing in some cases - depend on what GDB
has computed. */
+ gdb::unique_xmalloc_ptr<char> demangled;
if (mangled != NULL)
{
- char *demangled;
-
/* Use DMGL_RET_DROP for C++ template functions to suppress their return
type. It is easier for GDB users to search for such functions as
`name(params)' than `long name(params)'. In such case the minimal
/* This is a lie, but we already lie to the caller new_symbol_full.
new_symbol_full assumes we return the mangled name.
This just undoes that lie until things are cleaned up. */
- demangled = NULL;
}
else
{
- demangled = gdb_demangle (mangled,
- (DMGL_PARAMS | DMGL_ANSI | DMGL_RET_DROP));
+ demangled.reset (gdb_demangle (mangled,
+ (DMGL_PARAMS | DMGL_ANSI
+ | DMGL_RET_DROP)));
}
if (demangled)
- {
- make_cleanup (xfree, demangled);
- canon = demangled;
- }
+ canon = demangled.get ();
else
{
canon = mangled;
obstack_copy0 (&objfile->per_bfd->storage_obstack,
retval, strlen (retval)));
- do_cleanups (back_to);
return retval;
}
struct attribute *attr;
struct line_header line_header_local;
hashval_t line_header_local_hash;
- unsigned u;
void **slot;
int decode_mapping;
htab_t &cus_htab)
{
struct objfile *objfile = dwarf2_per_objfile->objfile;
- const struct dwarf2_section_info *abbrev_section = &dwo_file.sections.abbrev;
const gdb_byte *info_ptr, *end_ptr;
dwarf2_read_section (objfile, §ion);
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;
dwp_file->tus = create_dwp_hash_table (dwp_file, 1);
/* The DWP file version is stored in the hash table. Oh well. */
- if (dwp_file->cus->version != dwp_file->tus->version)
+ if (dwp_file->cus && dwp_file->tus
+ && dwp_file->cus->version != dwp_file->tus->version)
{
/* Technically speaking, we should try to limp along, but this is
pretty bizarre. We use pulongest here because that's the established
pulongest (dwp_file->cus->version),
pulongest (dwp_file->tus->version), dwp_name.c_str ());
}
- dwp_file->version = dwp_file->cus->version;
+
+ if (dwp_file->cus)
+ dwp_file->version = dwp_file->cus->version;
+ else if (dwp_file->tus)
+ dwp_file->version = dwp_file->tus->version;
+ else
+ dwp_file->version = 2;
if (dwp_file->version == 2)
bfd_map_over_sections (dwp_file->dbfd, dwarf2_locate_v2_dwp_sections,
{
/* Print the name of the DWP file if we looked there, helps the user
better diagnose the problem. */
- char *dwp_text = NULL;
- struct cleanup *cleanups;
+ std::string dwp_text;
if (dwp_file != NULL)
- dwp_text = xstrprintf (" [in DWP file %s]", lbasename (dwp_file->name));
- cleanups = make_cleanup (xfree, dwp_text);
+ dwp_text = string_printf (" [in DWP file %s]",
+ lbasename (dwp_file->name));
warning (_("Could not find DWO %s %s(%s)%s referenced by %s at offset 0x%x"
" [in module %s]"),
kind, dwo_name, hex_string (signature),
- dwp_text != NULL ? dwp_text : "",
+ dwp_text.c_str (),
this_unit->is_debug_types ? "TU" : "CU",
to_underlying (this_unit->sect_off), objfile_name (objfile));
-
- do_cleanups (cleanups);
}
return NULL;
}
\f
/* Read in various DIEs. */
-/* qsort helper for inherit_abstract_dies. */
-
-static int
-unsigned_int_compar (const void *ap, const void *bp)
-{
- unsigned int a = *(unsigned int *) ap;
- unsigned int b = *(unsigned int *) bp;
-
- return (a > b) - (b > a);
-}
-
/* DW_AT_abstract_origin inherits whole DIEs (not just their attributes).
Inherit only the children of the DW_AT_abstract_origin DIE not being
already referenced by DW_AT_abstract_origin from the children of the
inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu)
{
struct die_info *child_die;
- unsigned die_children_count;
- /* CU offsets which were referenced by children of the current DIE. */
- sect_offset *offsets;
- sect_offset *offsets_end, *offsetp;
+ sect_offset *offsetp;
/* Parent of DIE - referenced by DW_AT_abstract_origin. */
struct die_info *origin_die;
/* Iterator of the ORIGIN_DIE children. */
struct die_info *origin_child_die;
- struct cleanup *cleanups;
struct attribute *attr;
struct dwarf2_cu *origin_cu;
struct pending **origin_previous_list_in_scope;
to_underlying (die->sect_off),
to_underlying (origin_die->sect_off));
- child_die = die->child;
- die_children_count = 0;
- while (child_die && child_die->tag)
- {
- child_die = sibling_die (child_die);
- die_children_count++;
- }
- offsets = XNEWVEC (sect_offset, die_children_count);
- cleanups = make_cleanup (xfree, offsets);
+ std::vector<sect_offset> offsets;
- offsets_end = offsets;
for (child_die = die->child;
child_die && child_die->tag;
child_die = sibling_die (child_die))
to_underlying (child_die->sect_off),
to_underlying (child_origin_die->sect_off));
else
- *offsets_end++ = child_origin_die->sect_off;
+ offsets.push_back (child_origin_die->sect_off);
}
}
- qsort (offsets, offsets_end - offsets, sizeof (*offsets),
- unsigned_int_compar);
- for (offsetp = offsets + 1; offsetp < offsets_end; offsetp++)
+ std::sort (offsets.begin (), offsets.end ());
+ sect_offset *offsets_end = offsets.data () + offsets.size ();
+ for (offsetp = offsets.data () + 1; offsetp < offsets_end; offsetp++)
if (offsetp[-1] == *offsetp)
complaint (&symfile_complaints,
_("Multiple children of DIE 0x%x refer "
"to DIE 0x%x as their abstract origin"),
to_underlying (die->sect_off), to_underlying (*offsetp));
- offsetp = offsets;
+ offsetp = offsets.data ();
origin_child_die = origin_die->child;
while (origin_child_die && origin_child_die->tag)
{
origin_child_die = sibling_die (origin_child_die);
}
origin_cu->list_in_scope = origin_previous_list_in_scope;
-
- do_cleanups (cleanups);
}
static void
CORE_ADDR baseaddr;
struct block *block;
int inlined_func = (die->tag == DW_TAG_inlined_subroutine);
- VEC (symbolp) *template_args = NULL;
+ std::vector<struct symbol *> template_args;
struct template_symbol *templ_func = NULL;
if (inlined_func)
|| child_die->tag == DW_TAG_template_value_param)
{
templ_func = allocate_template_symbol (objfile);
- templ_func->base.is_cplus_template_function = 1;
+ templ_func->subclass = SYMBOL_TEMPLATE;
break;
}
}
struct symbol *arg = new_symbol (child_die, NULL, cu);
if (arg != NULL)
- VEC_safe_push (symbolp, template_args, arg);
+ template_args.push_back (arg);
}
else
process_die (child_die, cu);
gdbarch_make_symbol_special (gdbarch, newobj->name, objfile);
/* Attach template arguments to function. */
- if (! VEC_empty (symbolp, template_args))
+ if (!template_args.empty ())
{
gdb_assert (templ_func != NULL);
- templ_func->n_template_arguments = VEC_length (symbolp, template_args);
+ templ_func->n_template_arguments = template_args.size ();
templ_func->template_arguments
= XOBNEWVEC (&objfile->objfile_obstack, struct symbol *,
templ_func->n_template_arguments);
memcpy (templ_func->template_arguments,
- VEC_address (symbolp, template_args),
+ template_args.data (),
(templ_func->n_template_arguments * sizeof (struct symbol *)));
- VEC_free (symbolp, template_args);
}
/* In C++, we can have functions nested inside functions (e.g., when
}
}
+/* Helper function for read_variable. If DIE represents a virtual
+ table, then return the type of the concrete object that is
+ associated with the virtual table. Otherwise, return NULL. */
+
+static struct type *
+rust_containing_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct attribute *attr = dwarf2_attr (die, DW_AT_type, cu);
+ if (attr == NULL)
+ return NULL;
+
+ /* Find the type DIE. */
+ struct die_info *type_die = NULL;
+ struct dwarf2_cu *type_cu = cu;
+
+ if (attr_form_is_ref (attr))
+ type_die = follow_die_ref (die, attr, &type_cu);
+ if (type_die == NULL)
+ return NULL;
+
+ if (dwarf2_attr (type_die, DW_AT_containing_type, type_cu) == NULL)
+ return NULL;
+ return die_containing_type (type_die, type_cu);
+}
+
+/* Read a variable (DW_TAG_variable) DIE and create a new symbol. */
+
+static void
+read_variable (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct rust_vtable_symbol *storage = NULL;
+
+ if (cu->language == language_rust)
+ {
+ struct type *containing_type = rust_containing_type (die, cu);
+
+ if (containing_type != NULL)
+ {
+ struct objfile *objfile = cu->objfile;
+
+ storage = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+ struct rust_vtable_symbol);
+ initialize_objfile_symbol (storage);
+ storage->concrete_type = containing_type;
+ storage->subclass = SYMBOL_RUST_VTABLE;
+ }
+ }
+
+ new_symbol_full (die, NULL, cu, storage);
+}
+
/* Call CALLBACK from DW_AT_ranges attribute value OFFSET
reading .debug_rnglists.
Callback's type should be:
Callback &&callback)
{
struct objfile *objfile = cu->objfile;
- struct gdbarch *gdbarch = get_objfile_arch (objfile);
- struct comp_unit_head *cu_header = &cu->header;
bfd *obfd = objfile->obfd;
- unsigned int addr_size = cu_header->addr_size;
- CORE_ADDR mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
/* Base address selection entry. */
CORE_ADDR base;
int found_base;
- unsigned int dummy;
const gdb_byte *buffer;
- CORE_ADDR low = 0;
- CORE_ADDR high = 0;
CORE_ADDR baseaddr;
bool overflow = false;
Callback &&callback)
{
struct objfile *objfile = cu->objfile;
- struct gdbarch *gdbarch = get_objfile_arch (objfile);
struct comp_unit_head *cu_header = &cu->header;
bfd *obfd = objfile->obfd;
unsigned int addr_size = cu_header->addr_size;
attr = dwarf2_attr (die, DW_AT_ranges, cu);
if (attr)
{
- bfd *obfd = objfile->obfd;
/* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton.
We take advantage of the fact that DW_AT_ranges does not appear
in DW_TAG_compile_unit of DWO files. */
}
}
-/* Add a typedef defined in the scope of the FIP's class. */
+/* Can the type given by DIE define another type? */
+
+static bool
+type_can_define_types (const struct die_info *die)
+{
+ switch (die->tag)
+ {
+ case DW_TAG_typedef:
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_enumeration_type:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Add a type definition defined in the scope of the FIP's class. */
static void
-dwarf2_add_typedef (struct field_info *fip, struct die_info *die,
- struct dwarf2_cu *cu)
+dwarf2_add_type_defn (struct field_info *fip, struct die_info *die,
+ struct dwarf2_cu *cu)
{
- struct typedef_field_list *new_field;
- struct typedef_field *fp;
+ struct decl_field_list *new_field;
+ struct decl_field *fp;
/* Allocate a new field list entry and link it in. */
- new_field = XCNEW (struct typedef_field_list);
+ new_field = XCNEW (struct decl_field_list);
make_cleanup (xfree, new_field);
- gdb_assert (die->tag == DW_TAG_typedef);
+ gdb_assert (type_can_define_types (die));
fp = &new_field->field;
- /* Get name of field. */
+ /* Get name of field. NULL is okay here, meaning an anonymous type. */
fp->name = dwarf2_name (die, cu);
- if (fp->name == NULL)
- return;
-
fp->type = read_type_die (die, cu);
- new_field->next = fip->typedef_field_list;
- fip->typedef_field_list = new_field;
- fip->typedef_field_list_count++;
+ /* Save accessibility. */
+ enum dwarf_access_attribute accessibility;
+ struct attribute *attr = dwarf2_attr (die, DW_AT_accessibility, cu);
+ if (attr != NULL)
+ accessibility = (enum dwarf_access_attribute) DW_UNSND (attr);
+ else
+ accessibility = dwarf2_default_access_attribute (die, cu);
+ switch (accessibility)
+ {
+ case DW_ACCESS_public:
+ /* The assumed value if neither private nor protected. */
+ break;
+ case DW_ACCESS_private:
+ fp->is_private = 1;
+ break;
+ case DW_ACCESS_protected:
+ fp->is_protected = 1;
+ break;
+ default:
+ complaint (&symfile_complaints,
+ _("Unhandled DW_AT_accessibility value (%x)"), accessibility);
+ }
+
+ if (die->tag == DW_TAG_typedef)
+ {
+ new_field->next = fip->typedef_field_list;
+ fip->typedef_field_list = new_field;
+ fip->typedef_field_list_count++;
+ }
+ else
+ {
+ new_field->next = fip->nested_types_list;
+ fip->nested_types_list = new_field;
+ fip->nested_types_list_count++;
+ }
}
/* Create the vector of fields, and attach it to the type. */
is_vtable_name (const char *name, struct dwarf2_cu *cu)
{
static const char vptr[] = "_vptr";
- static const char vtable[] = "vtable";
/* Look for the C++ form of the vtable. */
if (startswith (name, vptr) && is_cplus_marker (name[sizeof (vptr) - 1]))
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. */
}
}
- /* Copy fi.typedef_field_list linked list elements content into the
- allocated array TYPE_TYPEDEF_FIELD_ARRAY (type). */
- if (fi.typedef_field_list)
+ /* Copy fi.typedef_field_list linked list elements content into the
+ allocated array TYPE_TYPEDEF_FIELD_ARRAY (type). */
+ if (fi.typedef_field_list)
+ {
+ int i = fi.typedef_field_list_count;
+
+ ALLOCATE_CPLUS_STRUCT_TYPE (type);
+ TYPE_TYPEDEF_FIELD_ARRAY (type)
+ = ((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 decl_field *dest, *src;
+
+ dest = &TYPE_TYPEDEF_FIELD (type, i);
+ src = &fi.typedef_field_list->field;
+ fi.typedef_field_list = fi.typedef_field_list->next;
+ *dest = *src;
+ }
+ }
+
+ /* 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.typedef_field_list_count;
+ int i = fi.nested_types_list_count;
ALLOCATE_CPLUS_STRUCT_TYPE (type);
- TYPE_TYPEDEF_FIELD_ARRAY (type)
- = ((struct typedef_field *)
- TYPE_ALLOC (type, sizeof (TYPE_TYPEDEF_FIELD (type, 0)) * i));
- TYPE_TYPEDEF_FIELD_COUNT (type) = i;
+ 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 typedef_field *dest, *src;
+ struct decl_field *dest, *src;
- dest = &TYPE_TYPEDEF_FIELD (type, i);
- src = &fi.typedef_field_list->field;
- fi.typedef_field_list = fi.typedef_field_list->next;
+ dest = &TYPE_NESTED_TYPES_FIELD (type, i);
+ src = &fi.nested_types_list->field;
+ fi.nested_types_list = fi.nested_types_list->next;
*dest = *src;
}
}
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;
}
if (format)
type = init_float_type (objfile, bits, name, format);
else
- type = init_type (objfile, TYPE_CODE_ERROR, bits / TARGET_CHAR_BIT, name);
+ type = init_type (objfile, TYPE_CODE_ERROR, bits, name);
return type;
}
{
case DW_ATE_address:
/* Turn DW_ATE_address into a void * pointer. */
- type = init_type (objfile, TYPE_CODE_VOID, 1, NULL);
+ type = init_type (objfile, TYPE_CODE_VOID, TARGET_CHAR_BIT, NULL);
type = init_pointer_type (objfile, bits, name, type);
break;
case DW_ATE_boolean:
default:
complaint (&symfile_complaints, _("unsupported DW_AT_encoding: '%s'"),
dwarf_type_encoding_name (encoding));
- type = init_type (objfile, TYPE_CODE_ERROR,
- bits / TARGET_CHAR_BIT, name);
+ type = init_type (objfile, TYPE_CODE_ERROR, bits, name);
break;
}
ULONGEST data_count, datai;
const gdb_byte *buf = *bufp;
const gdb_byte *format_header_data;
- int i;
unsigned int bytes_read;
format_count = read_1_byte (abfd, buf);
const char *name, const char *comp_dir, CORE_ADDR low_pc)
{
struct compunit_symtab *cust
- = start_symtab (cu->objfile, name, comp_dir, low_pc);
+ = start_symtab (cu->objfile, name, comp_dir, low_pc, cu->language);
record_debugformat ("DWARF 2");
record_producer (cu->producer);
default:
{
- complain:
complaint (&symfile_complaints,
_("invalid form 0x%x in `%s'"),
form, get_section_name (section));
/* Note that we rely on the fact that the corresponding GNU and
DWARF constants are the same. */
+ DIAGNOSTIC_PUSH
+ DIAGNOSTIC_IGNORE_SWITCH_DIFFERENT_ENUM_TYPES
switch (macinfo_type)
{
/* A zero macinfo type indicates the end of the macro
return;
break;
}
+ DIAGNOSTIC_POP
} while (macinfo_type != 0);
}
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;
/* Note that we rely on the fact that the corresponding GNU and
DWARF constants are the same. */
+ DIAGNOSTIC_PUSH
+ DIAGNOSTIC_IGNORE_SWITCH_DIFFERENT_ENUM_TYPES
switch (macinfo_type)
{
/* A zero macinfo type indicates the end of the macro
return;
break;
}
+ DIAGNOSTIC_POP
} while (macinfo_type != 0 && current_file == NULL);
/* Second pass: Process all entries.
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. */
+/* Write SIZE bytes from the buffer pointed to by DATA to FILE, with
+ error checking. */
+
+static void
+file_write (FILE *file, const void *data, size_t size)
+{
+ if (fwrite (data, 1, size, file) != size)
+ error (_("couldn't data write to file"));
+}
+
+/* Write the contents of VEC to FILE, with error checking. */
+
+template<typename Elem, typename Alloc>
+static void
+file_write (FILE *file, const std::vector<Elem, Alloc> &vec)
+{
+ file_write (file, vec.data (), vec.size () * sizeof (vec[0]));
+}
+
/* In-memory buffer to prepare data to be written later to a file. */
class data_buf
{
std::copy (cstr, cstr + size, grow (size));
}
+ /* 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;
+ }
+ }
+
/* 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)
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
{
- if (::fwrite (m_vec.data (), 1, m_vec.size (), file) != m_vec.size ())
- error (_("couldn't write data to file"));
+ ::file_write (file, m_vec);
}
private:
return strcmp (m_cstr, other.m_cstr) == 0;
}
+ /* 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;
+ }
+
private:
friend class c_str_view_hasher;
const char *const m_cstr;
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_)
+ {}
+
+ /* Implement offset_vec::reserve. */
+ void reserve (size_t nelem) override
+ {
+ m_vec.reserve (nelem);
+ }
+
+ /* Implement offset_vec::push_back_reorder. */
+ void push_back_reorder (size_t elem) override
+ {
+ 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);
+ }
+
+ /* Implement offset_vec::bytes. */
+ size_t bytes () const override
+ {
+ return m_vec.size () * sizeof (m_vec[0]);
+ }
+
+ /* Implement offset_vec::file_write. */
+ void file_write (FILE *file) const override
+ {
+ ::file_write (file, m_vec);
+ }
+
+ private:
+ std::vector<OffsetSize> m_vec;
+ };
+
+ /* 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;
+
+ 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_)
+ {
+ }
+ };
-/* 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_)
- {}
+ /* 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;
+ };
- struct objfile *objfile;
- struct mapped_symtab *symtab;
- data_buf &types_list;
- std::unordered_set<partial_symbol *> &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;
+ /* 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"));
- 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);
+ /* 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 count 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_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);
+ ++info->cu_index;
+ }
- psyms_seen += psymtab->n_global_syms;
- psyms_seen += psymtab->n_static_syms;
-}
+ /* Store value of each symbol. */
+ std::unordered_map<c_str_view, std::set<symbol_value>, c_str_view_hasher>
+ m_name_to_value_set;
-/* Recurse into all "included" dependencies and write their symbols as
- if they appeared in this psymtab. */
+ /* 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;
-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;
+ 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;
- 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);
+ /* 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;
- 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);
-}
+ /* Next unused .debug_names abbreviation tag for
+ m_indexkey_to_idx. */
+ int m_idx_next = 1;
-/* Create an index file for OBJFILE in the directory DIR. */
+ /* .debug_names abbreviation table. */
+ data_buf m_abbrev_table;
-static void
-write_psymtabs_to_index (struct objfile *objfile, const char *dir)
+ /* .debug_names entry pool. */
+ data_buf m_entry_pool;
+};
+
+/* Return iff any of the needed offsets does not fit into 32-bit
+ .debug_names section. */
+
+static bool
+check_dwarf64_offsets ()
{
- if (dwarf2_per_objfile->using_index)
- error (_("Cannot use an index to create the index"));
+ 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];
- 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 (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;
- if (!objfile->psymtabs || !objfile->psymtabs_addrmap)
- return;
+ if (to_underlying (per_cu.sect_off) >= (static_cast<uint64_t> (1) << 32))
+ return true;
+ }
+ return false;
+}
- struct stat st;
- if (stat (objfile_name (objfile), &st) < 0)
- perror_with_name (objfile_name (objfile));
+/* 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. */
- std::string filename (std::string (dir) + SLASH_STRING
- + lbasename (objfile_name (objfile)) + INDEX_SUFFIX);
+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;
- FILE *out_file = gdb_fopen_cloexec (filename.c_str (), "wb").release ();
- if (!out_file)
- error (_("Can't open `%s' for writing"), filename.c_str ());
+ 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;
+}
- /* 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);
+/* Write new .gdb_index section for OBJFILE into OUT_FILE.
+ Return how many bytes were expected to be written into OUT_FILE. */
+static size_t
+write_gdbindex (struct objfile *objfile, FILE *out_file)
+{
mapped_symtab symtab;
data_buf cu_list;
work here. Also, the debug_types entries do not appear in
all_comp_units, but only in their own hash table. */
- /* The psyms_seen set is potentially going to be largish (~40k
- elements when indexing a -g3 build of GDB itself). Estimate the
- number of elements in order to avoid too many rehashes, which
- require rebuilding buckets and thus many trips to
- malloc/free. */
- size_t psyms_count = 0;
- for (int i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
- {
- struct dwarf2_per_cu_data *per_cu
- = dwarf2_per_objfile->all_comp_units[i];
- struct partial_symtab *psymtab = per_cu->v.psymtab;
-
- if (psymtab != NULL && psymtab->user == NULL)
- recursively_count_psymbols (psymtab, psyms_count);
- }
- /* Generating an index for gdb itself shows a ratio of
- TOTAL_SEEN_SYMS/UNIQUE_SYMS or ~5. 4 seems like a good bet. */
- std::unordered_set<partial_symbol *> psyms_seen (psyms_count / 4);
+ 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
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));
+ }
+
+ /* 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. */
+
+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;
+
+ 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));
+
+ 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);
+ }
+
/* 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)
{
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
}