diff options
-rw-r--r-- | bfd/version.h | 2 | ||||
-rw-r--r-- | gdb/dwarf2/attribute.c | 73 | ||||
-rw-r--r-- | gdb/dwarf2/attribute.h | 43 | ||||
-rw-r--r-- | gdb/dwarf2/cooked-index-storage.c | 56 | ||||
-rw-r--r-- | gdb/dwarf2/cooked-index-storage.h | 26 | ||||
-rw-r--r-- | gdb/dwarf2/cooked-indexer.c | 7 | ||||
-rw-r--r-- | gdb/dwarf2/read-debug-names.c | 5 | ||||
-rw-r--r-- | gdb/dwarf2/read-gdb-index.c | 2 | ||||
-rw-r--r-- | gdb/dwarf2/read.c | 441 | ||||
-rw-r--r-- | gdb/dwarf2/read.h | 49 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/enum_cond.c | 16 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/enum_cond.exp | 15 | ||||
-rw-r--r-- | gdb/testsuite/lib/gdb.exp | 12 |
13 files changed, 369 insertions, 378 deletions
diff --git a/bfd/version.h b/bfd/version.h index c90df07..a6afff6 100644 --- a/bfd/version.h +++ b/bfd/version.h @@ -16,7 +16,7 @@ In releases, the date is not included in either version strings or sonames. */ -#define BFD_VERSION_DATE 20250318 +#define BFD_VERSION_DATE 20250319 #define BFD_VERSION @bfd_version@ #define BFD_VERSION_STRING @bfd_version_package@ @bfd_version_string@ #define REPORT_BUGS_TO @report_bugs_to@ diff --git a/gdb/dwarf2/attribute.c b/gdb/dwarf2/attribute.c index f777c14..49c0bc0 100644 --- a/gdb/dwarf2/attribute.c +++ b/gdb/dwarf2/attribute.c @@ -164,6 +164,27 @@ attribute::constant_value (int default_value) const /* See attribute.h. */ +std::optional<ULONGEST> +attribute::unsigned_constant () const +{ + if (form_is_strictly_signed ()) + { + if (u.snd >= 0) + return u.snd; + complaint (_("Attribute value is not unsigned (%s)"), + dwarf_form_name (form)); + } + else if (form_is_constant ()) + return u.unsnd; + + /* For DW_FORM_data16 see attribute::form_is_constant. */ + complaint (_("Attribute value is not a constant (%s)"), + dwarf_form_name (form)); + return {}; +} + +/* See attribute.h. */ + bool attribute::form_is_unsigned () const { @@ -189,7 +210,7 @@ attribute::form_is_unsigned () const /* See attribute.h. */ bool -attribute::form_is_signed () const +attribute::form_is_strictly_signed () const { return form == DW_FORM_sdata || form == DW_FORM_implicit_const; } @@ -216,21 +237,24 @@ attribute::form_requires_reprocessing () const dwarf_defaulted_attribute attribute::defaulted () const { - LONGEST value = constant_value (-1); + std::optional<ULONGEST> value = unsigned_constant (); - switch (value) + if (value.has_value ()) { - case DW_DEFAULTED_no: - case DW_DEFAULTED_in_class: - case DW_DEFAULTED_out_of_class: - return (dwarf_defaulted_attribute) value; + switch (*value) + { + case DW_DEFAULTED_no: + case DW_DEFAULTED_in_class: + case DW_DEFAULTED_out_of_class: + return (dwarf_defaulted_attribute) *value; + + default: + complaint (_("unrecognized DW_AT_defaulted value (%s)"), + plongest (*value)); + break; + } } - /* If the form was not constant, we already complained in - constant_value, so there's no need to complain again. */ - if (form_is_constant ()) - complaint (_("unrecognized DW_AT_defaulted value (%s)"), - plongest (value)); return DW_DEFAULTED_no; } @@ -239,21 +263,24 @@ attribute::defaulted () const dwarf_virtuality_attribute attribute::as_virtuality () const { - LONGEST value = constant_value (-1); + std::optional<ULONGEST> value = unsigned_constant (); - switch (value) + if (value.has_value ()) { - case DW_VIRTUALITY_none: - case DW_VIRTUALITY_virtual: - case DW_VIRTUALITY_pure_virtual: - return (dwarf_virtuality_attribute) value; + switch (*value) + { + case DW_VIRTUALITY_none: + case DW_VIRTUALITY_virtual: + case DW_VIRTUALITY_pure_virtual: + return (dwarf_virtuality_attribute) *value; + + default: + complaint (_("unrecognized DW_AT_virtuality value (%s)"), + plongest (*value)); + break; + } } - /* If the form was not constant, we already complained in - constant_value, so there's no need to complain again. */ - if (form_is_constant ()) - complaint (_("unrecognized DW_AT_virtuality value (%s)"), - plongest (value)); return DW_VIRTUALITY_none; } diff --git a/gdb/dwarf2/attribute.h b/gdb/dwarf2/attribute.h index 115d006..4dce04d 100644 --- a/gdb/dwarf2/attribute.h +++ b/gdb/dwarf2/attribute.h @@ -69,7 +69,7 @@ struct attribute form. */ LONGEST as_signed () const { - gdb_assert (form_is_signed ()); + gdb_assert (form_is_strictly_signed ()); return u.snd; } @@ -91,28 +91,6 @@ struct attribute return u.unsnd; } - /* Return true if the value is nonnegative. Requires that that - reprocessing not be needed. */ - bool is_nonnegative () const - { - if (form_is_unsigned ()) - return true; - if (form_is_signed ()) - return as_signed () >= 0; - return false; - } - - /* Return the nonnegative value. Requires that that reprocessing not be - needed. */ - ULONGEST as_nonnegative () const - { - if (form_is_unsigned ()) - return as_unsigned (); - if (form_is_signed ()) - return (ULONGEST)as_signed (); - gdb_assert (false); - } - /* Return non-zero if ATTR's value is a section offset --- classes lineptr, loclistptr, macptr or rangelistptr --- or zero, otherwise. You may use the as_unsigned method to retrieve such offsets. @@ -124,6 +102,18 @@ struct attribute bool form_is_section_offset () const; + /* Return an unsigned constant value. This only handles constant + forms (i.e., form_is_constant -- and not the extended list of + "unsigned" forms) and assumes an unsigned value is desired. This + can intended for use with DWARF-defined enumerations like DW_CC_* + or DW_INL_*, but also in situations where a nonnegative constant + integer is specified by DWARF. + + If a signed form and negative value is used, or if a non-constant + form is used, then complaint is issued and an empty value is + returned. */ + std::optional<ULONGEST> unsigned_constant () const; + /* Return non-zero if ATTR's value falls in the 'constant' class, or zero otherwise. When this function returns true, you can apply the constant_value method to it. @@ -168,8 +158,11 @@ struct attribute /* Check if the attribute's form is an unsigned integer form. */ bool form_is_unsigned () const; - /* Check if the attribute's form is a signed integer form. */ - bool form_is_signed () const; + /* Check if the attribute's form is a signed integer form. This + only returns true for forms that are strictly signed -- that is, + for a context-dependent form like DW_FORM_data1, this returns + false. */ + bool form_is_strictly_signed () const; /* Check if the attribute's form is a form that requires "reprocessing". */ diff --git a/gdb/dwarf2/cooked-index-storage.c b/gdb/dwarf2/cooked-index-storage.c index 820989e..9c05cf5 100644 --- a/gdb/dwarf2/cooked-index-storage.c +++ b/gdb/dwarf2/cooked-index-storage.c @@ -22,11 +22,7 @@ /* See cooked-index-storage.h. */ cooked_index_storage::cooked_index_storage () - : m_reader_hash (htab_create_alloc (10, hash_cutu_reader, - eq_cutu_reader, - htab_delete_entry<cutu_reader>, - xcalloc, xfree)), - m_shard (new cooked_index_shard) + : m_shard (new cooked_index_shard) { } @@ -35,9 +31,8 @@ cooked_index_storage::cooked_index_storage () cutu_reader * cooked_index_storage::get_reader (dwarf2_per_cu *per_cu) { - int index = per_cu->index; - return (cutu_reader *) htab_find_with_hash (m_reader_hash.get (), - &index, index); + auto it = m_reader_hash.find (*per_cu); + return it != m_reader_hash.end () ? it->get () : nullptr; } /* See cooked-index-storage.h. */ @@ -47,30 +42,43 @@ cooked_index_storage::preserve (cutu_reader_up reader) { m_abbrev_table_cache.add (reader->release_abbrev_table ()); - int index = reader->cu ()->per_cu->index; - void **slot = htab_find_slot_with_hash (m_reader_hash.get (), &index, - index, INSERT); - gdb_assert (*slot == nullptr); - cutu_reader *result = reader.get (); - *slot = reader.release (); - return result; + auto [it, inserted] = m_reader_hash.insert (std::move (reader)); + gdb_assert (inserted); + + return it->get(); +} + +/* See cooked-index-storage.h. */ + +std::uint64_t +cooked_index_storage::cutu_reader_hash::operator() + (const cutu_reader_up &reader) const noexcept +{ + return (*this) (*reader->cu ()->per_cu); +} + +/* See cooked-index-storage.h. */ + +std::uint64_t +cooked_index_storage::cutu_reader_hash::operator() (const dwarf2_per_cu &per_cu) + const noexcept +{ + return per_cu.index; } /* See cooked-index-storage.h. */ -hashval_t -cooked_index_storage::hash_cutu_reader (const void *a) +bool +cooked_index_storage::cutu_reader_eq::operator() (const cutu_reader_up &a, + const cutu_reader_up &b) const noexcept { - const cutu_reader *reader = (const cutu_reader *) a; - return reader->cu ()->per_cu->index; + return (*this) (*a->cu ()->per_cu, b); } /* See cooked-index-storage.h. */ -int -cooked_index_storage::eq_cutu_reader (const void *a, const void *b) +bool cooked_index_storage::cutu_reader_eq::operator() + (const dwarf2_per_cu &per_cu, const cutu_reader_up &reader) const noexcept { - const cutu_reader *ra = (const cutu_reader *) a; - const int *rb = (const int *) b; - return ra->cu ()->per_cu->index == *rb; + return per_cu.index == reader->cu ()->per_cu->index; } diff --git a/gdb/dwarf2/cooked-index-storage.h b/gdb/dwarf2/cooked-index-storage.h index 3d0b5b2..449fbe1 100644 --- a/gdb/dwarf2/cooked-index-storage.h +++ b/gdb/dwarf2/cooked-index-storage.h @@ -90,18 +90,34 @@ public: } private: + /* The abbrev table cache used by this indexer. */ + abbrev_table_cache m_abbrev_table_cache; /* Hash function for a cutu_reader. */ - static hashval_t hash_cutu_reader (const void *a); + struct cutu_reader_hash + { + using is_transparent = void; + + std::uint64_t operator() (const cutu_reader_up &reader) const noexcept; + std::uint64_t operator() (const dwarf2_per_cu &per_cu) const noexcept; + }; /* Equality function for cutu_reader. */ - static int eq_cutu_reader (const void *a, const void *b); + struct cutu_reader_eq + { + using is_transparent = void; - /* The abbrev table cache used by this indexer. */ - abbrev_table_cache m_abbrev_table_cache; + bool operator() (const cutu_reader_up &a, + const cutu_reader_up &b) const noexcept; + + bool operator() (const dwarf2_per_cu &per_cu, + const cutu_reader_up &reader) const noexcept; + }; /* A hash table of cutu_reader objects. */ - htab_up m_reader_hash; + gdb::unordered_set<cutu_reader_up, cutu_reader_hash, cutu_reader_eq> + m_reader_hash; + /* The index shard that is being constructed. */ cooked_index_shard_up m_shard; diff --git a/gdb/dwarf2/cooked-indexer.c b/gdb/dwarf2/cooked-indexer.c index 441a852..3b80cd6 100644 --- a/gdb/dwarf2/cooked-indexer.c +++ b/gdb/dwarf2/cooked-indexer.c @@ -202,8 +202,11 @@ cooked_indexer::scan_attributes (dwarf2_per_cu *scanning_per_cu, the DW_AT_calling_convention attribute was used instead as the only means available. We handle both variants then. */ case DW_AT_calling_convention: - if (attr.constant_value (DW_CC_normal) == DW_CC_program) - *flags |= IS_MAIN; + { + std::optional<ULONGEST> value = attr.unsigned_constant (); + if (value.has_value () && *value == DW_CC_program) + *flags |= IS_MAIN; + } break; case DW_AT_declaration: diff --git a/gdb/dwarf2/read-debug-names.c b/gdb/dwarf2/read-debug-names.c index 8c265dd..edac713 100644 --- a/gdb/dwarf2/read-debug-names.c +++ b/gdb/dwarf2/read-debug-names.c @@ -424,13 +424,12 @@ cooked_index_worker_debug_names::do_reading () exceptions.push_back (std::move (exc)); } - dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd; - per_bfd->quick_file_names_table - = create_quick_file_names_table (per_bfd->all_units.size ()); m_results.emplace_back (nullptr, complaint_handler.release (), std::move (exceptions), parent_map ()); + + dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd; cooked_index *table = (gdb::checked_static_cast<cooked_index *> (per_bfd->index_table.get ())); diff --git a/gdb/dwarf2/read-gdb-index.c b/gdb/dwarf2/read-gdb-index.c index f6c73d0..3439163 100644 --- a/gdb/dwarf2/read-gdb-index.c +++ b/gdb/dwarf2/read-gdb-index.c @@ -1558,8 +1558,6 @@ dwarf2_read_gdb_index set_main_name_from_gdb_index (per_objfile, map.get ()); per_bfd->index_table = std::move (map); - per_bfd->quick_file_names_table = - create_quick_file_names_table (per_bfd->all_units.size ()); return true; } diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index f41723c..b9040a5 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -265,31 +265,6 @@ struct loclists_rnglists_header unsigned int offset_entry_count; }; -/* A struct that can be used as a hash key for tables based on DW_AT_stmt_list. - This includes type_unit_group and quick_file_names. */ - -struct stmt_list_hash -{ - /* The DWO unit this table is from or NULL if there is none. */ - struct dwo_unit *dwo_unit; - - /* Offset in .debug_line or .debug_line.dwo. */ - sect_offset line_sect_off; -}; - -/* Each element of dwarf2_per_bfd->type_unit_groups is a pointer to - an object of this type. This contains elements of type unit groups - that can be shared across objfiles. The non-shareable parts are in - type_unit_group_unshareable. */ - -struct type_unit_group -{ - /* The data used to construct the hash key. */ - struct stmt_list_hash hash {}; -}; - -using type_unit_group_up = std::unique_ptr<type_unit_group>; - /* These sections are what may appear in a (real or virtual) DWO file. */ struct dwo_sections @@ -1535,9 +1510,6 @@ dwarf2_per_bfd::start_reading (dwarf_scanner_base_up new_table) line_header when we're done and don't need to record it here. */ struct quick_file_names { - /* The data used to construct the hash key. */ - struct stmt_list_hash hash; - /* The number of entries in file_names, real_names. */ unsigned int num_file_names; @@ -1579,64 +1551,34 @@ struct readnow_functions : public dwarf2_base_index_functions } }; -/* Utility hash function for a stmt_list_hash. */ - -static hashval_t -hash_stmt_list_entry (const struct stmt_list_hash *stmt_list_hash) -{ - hashval_t v = 0; - - if (stmt_list_hash->dwo_unit != NULL) - v += (uintptr_t) stmt_list_hash->dwo_unit->dwo_file; - v += to_underlying (stmt_list_hash->line_sect_off); - return v; -} - -/* Utility equality function for a stmt_list_hash. */ +/* See read.h. */ -static int -eq_stmt_list_entry (const struct stmt_list_hash *lhs, - const struct stmt_list_hash *rhs) +std::uint64_t +stmt_list_hash_hash::operator() (const stmt_list_hash &key) const noexcept { - if ((lhs->dwo_unit != NULL) != (rhs->dwo_unit != NULL)) - return 0; - if (lhs->dwo_unit != NULL - && lhs->dwo_unit->dwo_file != rhs->dwo_unit->dwo_file) - return 0; - - return lhs->line_sect_off == rhs->line_sect_off; -} + std::uint64_t v = 0; -/* Hash function for a quick_file_names. */ + if (key.dwo_unit != nullptr) + v += ankerl::unordered_dense::hash<dwo_file *> () (key.dwo_unit->dwo_file); -static hashval_t -hash_file_name_entry (const void *e) -{ - const struct quick_file_names *file_data - = (const struct quick_file_names *) e; - - return hash_stmt_list_entry (&file_data->hash); + v += (ankerl::unordered_dense::hash<std::uint64_t> () + (to_underlying (key.line_sect_off))); + return v; } -/* Equality function for a quick_file_names. */ +/* See read.h. */ -static int -eq_file_name_entry (const void *a, const void *b) +bool +stmt_list_hash::operator== (const stmt_list_hash &rhs) const noexcept { - const struct quick_file_names *ea = (const struct quick_file_names *) a; - const struct quick_file_names *eb = (const struct quick_file_names *) b; - - return eq_stmt_list_entry (&ea->hash, &eb->hash); -} + if ((this->dwo_unit != nullptr) != (rhs.dwo_unit != nullptr)) + return false; -/* See read.h. */ + if (this->dwo_unit != nullptr + && this->dwo_unit->dwo_file != rhs.dwo_unit->dwo_file) + return false; -htab_up -create_quick_file_names_table (unsigned int nr_initial_entries) -{ - return htab_up (htab_create_alloc (nr_initial_entries, - hash_file_name_entry, eq_file_name_entry, - nullptr, xcalloc, xfree)); + return this->line_sect_off == rhs.line_sect_off; } /* Read in CU (dwarf2_cu object) for PER_CU in the context of PER_OBJFILE. This @@ -1759,9 +1701,7 @@ dw2_get_file_names_reader (dwarf2_cu *cu, die_info *comp_unit_die) { dwarf2_per_cu *this_cu = cu->per_cu; dwarf2_per_objfile *per_objfile = cu->per_objfile; - struct attribute *attr; - void **slot; - struct quick_file_names *qfn; + dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; gdb_assert (! this_cu->is_debug_types); @@ -1771,29 +1711,24 @@ dw2_get_file_names_reader (dwarf2_cu *cu, die_info *comp_unit_die) if (comp_unit_die->tag == DW_TAG_partial_unit) return; - slot = NULL; - line_header_up lh; - sect_offset line_offset {}; file_and_directory &fnd = find_file_and_directory (comp_unit_die, cu); + std::optional<stmt_list_hash> stmt_list_hash_key; + attribute *attr = dwarf2_attr (comp_unit_die, DW_AT_stmt_list, cu); - attr = dwarf2_attr (comp_unit_die, DW_AT_stmt_list, cu); if (attr != nullptr && attr->form_is_unsigned ()) { - struct quick_file_names find_entry; - - line_offset = (sect_offset) attr->as_unsigned (); + sect_offset line_offset = (sect_offset) attr->as_unsigned (); /* We may have already read in this line header (TU line header sharing). If we have we're done. */ - find_entry.hash.dwo_unit = cu->dwo_unit; - find_entry.hash.line_sect_off = line_offset; - slot = htab_find_slot (per_objfile->per_bfd->quick_file_names_table.get (), - &find_entry, INSERT); - if (*slot != NULL) + stmt_list_hash_key = {cu->dwo_unit, line_offset}; + + if (auto it = per_bfd->quick_file_names_table.find (*stmt_list_hash_key); + it != per_bfd->quick_file_names_table.end ()) { - this_cu->file_names = (struct quick_file_names *) *slot; + this_cu->file_names = it->second; return; } @@ -1806,12 +1741,11 @@ dw2_get_file_names_reader (dwarf2_cu *cu, die_info *comp_unit_die) else if (lh == nullptr) return; - qfn = XOBNEW (&per_objfile->per_bfd->obstack, struct quick_file_names); - qfn->hash.dwo_unit = cu->dwo_unit; - qfn->hash.line_sect_off = line_offset; + auto *qfn = XOBNEW (&per_bfd->obstack, quick_file_names); + /* There may not be a DW_AT_stmt_list. */ - if (slot != nullptr) - *slot = qfn; + if (stmt_list_hash_key.has_value ()) + per_bfd->quick_file_names_table.emplace (*stmt_list_hash_key, qfn); std::vector<const char *> include_names; if (lh != nullptr) @@ -1831,9 +1765,8 @@ dw2_get_file_names_reader (dwarf2_cu *cu, die_info *comp_unit_die) qfn->num_file_names = offset + include_names.size (); qfn->comp_dir = fnd.intern_comp_dir (per_objfile->objfile); - qfn->file_names = - XOBNEWVEC (&per_objfile->per_bfd->obstack, const char *, - qfn->num_file_names); + qfn->file_names + = XOBNEWVEC (&per_bfd->obstack, const char *, qfn->num_file_names); if (offset != 0) qfn->file_names[0] = per_objfile->objfile->intern (fnd.get_name ()); @@ -2348,9 +2281,6 @@ dwarf2_initialize_objfile (struct objfile *objfile, dwarf_read_debug_printf ("readnow requested"); create_all_units (per_objfile); - per_bfd->quick_file_names_table - = create_quick_file_names_table (per_bfd->all_units.size ()); - objfile->qf.emplace_front (new readnow_functions); } /* Was a GDB index already read when we processed an objfile sharing @@ -2599,7 +2529,7 @@ fill_in_sig_entry_from_dwo_entry (dwarf2_per_objfile *per_objfile, gdb_assert (to_underlying (sig_entry->type_offset_in_section) == 0 || (to_underlying (sig_entry->type_offset_in_section) == to_underlying (dwo_entry->type_offset_in_tu))); - gdb_assert (sig_entry->type_unit_group == NULL); + gdb_assert (!sig_entry->type_unit_group_key.has_value ()); gdb_assert (sig_entry->dwo_unit == NULL || sig_entry->dwo_unit == dwo_entry); @@ -3320,71 +3250,21 @@ cutu_reader::cutu_reader (dwarf2_per_cu *this_cu, together. A future step could be to put the types in the same symtab as the CU the types ultimately came from. */ -static hashval_t -hash_type_unit_group (const void *item) -{ - const struct type_unit_group *tu_group - = (const struct type_unit_group *) item; - - return hash_stmt_list_entry (&tu_group->hash); -} - -static int -eq_type_unit_group (const void *item_lhs, const void *item_rhs) -{ - const struct type_unit_group *lhs = (const struct type_unit_group *) item_lhs; - const struct type_unit_group *rhs = (const struct type_unit_group *) item_rhs; - - return eq_stmt_list_entry (&lhs->hash, &rhs->hash); -} - -/* Allocate a hash table for type unit groups. */ - -static htab_up -allocate_type_unit_groups_table () -{ - return htab_up (htab_create_alloc (3, - hash_type_unit_group, - eq_type_unit_group, - htab_delete_entry<type_unit_group>, - xcalloc, xfree)); -} - /* Type units that don't have DW_AT_stmt_list are grouped into their own partial symtabs. We combine several TUs per psymtab to not let the size of any one psymtab grow too big. */ #define NO_STMT_LIST_TYPE_UNIT_PSYMTAB (1 << 31) #define NO_STMT_LIST_TYPE_UNIT_PSYMTAB_SIZE 10 -/* Helper routine for get_type_unit_group. - Create the type_unit_group object used to hold one or more TUs. */ - -static type_unit_group_up -create_type_unit_group (struct dwarf2_cu *cu, sect_offset line_offset_struct) -{ - auto tu_group = std::make_unique<type_unit_group> (); - - tu_group->hash.dwo_unit = cu->dwo_unit; - tu_group->hash.line_sect_off = line_offset_struct; - - return tu_group; -} - -/* Look up the type_unit_group for type unit CU, and create it if necessary. - STMT_LIST is a DW_AT_stmt_list attribute. */ +/* Get the type unit group key for type unit CU. STMT_LIST is a DW_AT_stmt_list + attribute. */ -static struct type_unit_group * -get_type_unit_group (struct dwarf2_cu *cu, const struct attribute *stmt_list) +static stmt_list_hash +get_type_unit_group_key (struct dwarf2_cu *cu, const struct attribute *stmt_list) { dwarf2_per_objfile *per_objfile = cu->per_objfile; struct tu_stats *tu_stats = &per_objfile->per_bfd->tu_stats; - struct type_unit_group *tu_group; - void **slot; unsigned int line_offset; - struct type_unit_group type_unit_group_for_lookup; - - if (per_objfile->per_bfd->type_unit_groups == NULL) - per_objfile->per_bfd->type_unit_groups = allocate_type_unit_groups_table (); /* Do we need to create a new group, or can we use an existing one? */ @@ -3406,21 +3286,7 @@ get_type_unit_group (struct dwarf2_cu *cu, const struct attribute *stmt_list) ++tu_stats->nr_stmt_less_type_units; } - type_unit_group_for_lookup.hash.dwo_unit = cu->dwo_unit; - type_unit_group_for_lookup.hash.line_sect_off = (sect_offset) line_offset; - slot = htab_find_slot (per_objfile->per_bfd->type_unit_groups.get (), - &type_unit_group_for_lookup, INSERT); - if (*slot == nullptr) - { - sect_offset line_offset_struct = (sect_offset) line_offset; - auto grp = create_type_unit_group (cu, line_offset_struct); - *slot = grp.release (); - ++tu_stats->nr_symtabs; - } - - tu_group = (struct type_unit_group *) *slot; - gdb_assert (tu_group != nullptr); - return tu_group; + return {cu->dwo_unit, static_cast<sect_offset> (line_offset)}; } /* Subroutine of dwarf2_build_psymtabs_hard to simplify it. @@ -3525,9 +3391,6 @@ build_type_psymtabs (dwarf2_per_objfile *per_objfile, abbrev_table_up abbrev_table; sect_offset abbrev_offset; - /* It's up to the caller to not call us multiple times. */ - gdb_assert (per_objfile->per_bfd->type_unit_groups == NULL); - if (per_objfile->per_bfd->all_type_units.size () == 0) return; @@ -3781,8 +3644,6 @@ cooked_index_worker_debug_info::do_reading () create_all_units (m_per_objfile); build_type_psymtabs (m_per_objfile, &m_index_storage); - per_bfd->quick_file_names_table - = create_quick_file_names_table (per_bfd->all_units.size ()); if (!per_bfd->debug_aranges.empty ()) read_addrmap_from_aranges (m_per_objfile, &per_bfd->debug_aranges, m_index_storage.get_addrmap (), @@ -4856,16 +4717,15 @@ rust_union_quirks (struct dwarf2_cu *cu) /* See read.h. */ type_unit_group_unshareable * -dwarf2_per_objfile::get_type_unit_group_unshareable (type_unit_group *tu_group) +dwarf2_per_objfile::get_type_unit_group_unshareable + (stmt_list_hash tu_group_key) { - auto iter = m_type_units.find (tu_group); - if (iter != m_type_units.end ()) - return iter->second.get (); + auto [it, inserted] = m_type_units.emplace (tu_group_key, nullptr); - type_unit_group_unshareable_up uniq (new type_unit_group_unshareable); - type_unit_group_unshareable *result = uniq.get (); - m_type_units[tu_group] = std::move (uniq); - return result; + if (inserted) + it->second = std::make_unique<type_unit_group_unshareable> (); + + return it->second.get (); } struct type * @@ -5137,7 +4997,7 @@ process_full_type_unit (dwarf2_cu *cu) of it with end_expandable_symtab. Otherwise, complete the addition of this TU's symbols to the existing symtab. */ type_unit_group_unshareable *tug_unshare = - per_objfile->get_type_unit_group_unshareable (sig_type->type_unit_group); + per_objfile->get_type_unit_group_unshareable (*sig_type->type_unit_group_key); if (tug_unshare->compunit_symtab == NULL) { buildsym_compunit *builder = cu->get_builder (); @@ -5947,17 +5807,14 @@ read_decl_line (struct die_info *die, struct dwarf2_cu *cu) struct attribute *decl_line = dwarf2_attr (die, DW_AT_decl_line, cu); if (decl_line == nullptr) return 0; - if (decl_line->form_is_constant ()) - { - LONGEST val = decl_line->constant_value (0); - if (0 <= val && val <= UINT_MAX) - return (unsigned int) val; + std::optional<ULONGEST> val = decl_line->unsigned_constant (); + if (val.has_value ()) + { + if (*val <= UINT_MAX) + return (unsigned int) *val; complaint (_("Declared line for using directive is too large")); - return 0; } - - complaint (_("Declared line for using directive is of incorrect format")); return 0; } @@ -6328,7 +6185,6 @@ read_file_scope (struct die_info *die, struct dwarf2_cu *cu) void dwarf2_cu::setup_type_unit_groups (struct die_info *die) { - struct type_unit_group *tu_group; int first_time; struct attribute *attr; unsigned int i; @@ -6341,16 +6197,15 @@ dwarf2_cu::setup_type_unit_groups (struct die_info *die) /* If we're using .gdb_index (includes -readnow) then per_cu->type_unit_group may not have been set up yet. */ - if (sig_type->type_unit_group == NULL) - sig_type->type_unit_group = get_type_unit_group (this, attr); - tu_group = sig_type->type_unit_group; + if (!sig_type->type_unit_group_key.has_value ()) + sig_type->type_unit_group_key = get_type_unit_group_key (this, attr); /* If we've already processed this stmt_list there's no real need to do it again, we could fake it and just recreate the part we need (file name,index -> symtab mapping). If data shows this optimization is useful we can do it then. */ type_unit_group_unshareable *tug_unshare - = per_objfile->get_type_unit_group_unshareable (tu_group); + = per_objfile->get_type_unit_group_unshareable (*sig_type->type_unit_group_key); first_time = tug_unshare->compunit_symtab == NULL; /* We have to handle the case of both a missing DW_AT_stmt_list or bad @@ -8499,8 +8354,10 @@ dwarf2_func_is_main_p (struct die_info *die, struct dwarf2_cu *cu) if (dwarf2_flag_true_p (die, DW_AT_main_subprogram, cu)) return true; struct attribute *attr = dwarf2_attr (die, DW_AT_calling_convention, cu); - return (attr != nullptr - && attr->constant_value (DW_CC_normal) == DW_CC_program); + if (attr == nullptr) + return false; + std::optional<ULONGEST> value = attr->unsigned_constant (); + return value.has_value () && *value == DW_CC_program; } /* A helper to handle Ada's "Pragma Import" feature when it is applied @@ -8620,11 +8477,14 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) attr = dwarf2_attr (die, DW_AT_external, cu); bool external_p = attr != nullptr && attr->as_boolean (); attr = dwarf2_attr (die, DW_AT_inline, cu); - bool inlined_p - = (attr != nullptr - && attr->is_nonnegative () - && (attr->as_nonnegative () == DW_INL_inlined - || attr->as_nonnegative () == DW_INL_declared_inlined)); + bool inlined_p = false; + if (attr != nullptr) + { + std::optional<ULONGEST> value = attr->unsigned_constant (); + inlined_p = (value.has_value () + && (*value == DW_INL_inlined + || *value == DW_INL_declared_inlined)); + } attr = dwarf2_attr (die, DW_AT_declaration, cu); bool decl_p = attr != nullptr && attr->as_boolean (); if (!external_p && !inlined_p && !decl_p) @@ -9962,8 +9822,8 @@ dwarf2_record_block_entry_pc (struct die_info *die, struct block *block, { /* We could possibly handle signed constants, but this is out of spec, so for now, just complain and ignore it. */ - complaint (_("Unhandled constant for DW_AT_entry_pc, value (%s)"), - plongest (attr->as_nonnegative ())); + complaint (_("Invalid form for DW_AT_entry_pc: %s"), + dwarf_form_name (attr->form)); } } else @@ -10093,13 +9953,16 @@ dwarf2_access_attribute (struct die_info *die, struct dwarf2_cu *cu) attribute *attr = dwarf2_attr (die, DW_AT_accessibility, cu); if (attr != nullptr) { - LONGEST value = attr->constant_value (-1); - if (value == DW_ACCESS_public - || value == DW_ACCESS_protected - || value == DW_ACCESS_private) - return (dwarf_access_attribute) value; - complaint (_("Unhandled DW_AT_accessibility value (%s)"), - plongest (value)); + std::optional<ULONGEST> value = attr->unsigned_constant (); + if (value.has_value ()) + { + if (*value == DW_ACCESS_public + || *value == DW_ACCESS_protected + || *value == DW_ACCESS_private) + return (dwarf_access_attribute) *value; + complaint (_("Unhandled DW_AT_accessibility value (%s)"), + pulongest (*value)); + } } if (cu->header.version < 3 || cu->producer_is_gxx_lt_4_6 ()) @@ -11126,16 +10989,11 @@ get_alignment (struct dwarf2_cu *cu, struct die_info *die) return 0; } - LONGEST val = attr->constant_value (0); - if (val < 0) - { - complaint (_("DW_AT_alignment value must not be negative" - " - DIE at %s [in module %s]"), - sect_offset_str (die->sect_off), - objfile_name (cu->per_objfile->objfile)); - return 0; - } - ULONGEST align = val; + std::optional<ULONGEST> val = attr->unsigned_constant (); + if (!val.has_value ()) + return 0; + + ULONGEST align = *val; if (align == 0) { @@ -11302,12 +11160,16 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu) the die. Otherwise the calling convention remains set to the default value DW_CC_normal. */ attr = dwarf2_attr (die, DW_AT_calling_convention, cu); - if (attr != nullptr - && is_valid_DW_AT_calling_convention_for_type (attr->constant_value (0))) + if (attr != nullptr) { - ALLOCATE_CPLUS_STRUCT_TYPE (type); - TYPE_CPLUS_CALLING_CONVENTION (type) - = (enum dwarf_calling_convention) (attr->constant_value (0)); + std::optional<ULONGEST> value = attr->unsigned_constant (); + if (value.has_value () + && is_valid_DW_AT_calling_convention_for_type (*value)) + { + ALLOCATE_CPLUS_STRUCT_TYPE (type); + TYPE_CPLUS_CALLING_CONVENTION (type) + = (enum dwarf_calling_convention) *value; + } } attr = dwarf2_attr (die, DW_AT_byte_size, cu); @@ -11773,19 +11635,26 @@ die_byte_order (die_info *die, dwarf2_cu *cu, enum bfd_endian *byte_order) attribute *attr = dwarf2_attr (die, DW_AT_endianity, cu); if (attr != nullptr && attr->form_is_constant ()) { - int endianity = attr->constant_value (0); + std::optional<ULONGEST> endianity = attr->unsigned_constant (); - switch (endianity) + if (endianity.has_value ()) { - case DW_END_big: - new_order = BFD_ENDIAN_BIG; - break; - case DW_END_little: - new_order = BFD_ENDIAN_LITTLE; - break; - default: - complaint (_("DW_AT_endianity has unrecognized value %d"), endianity); - break; + switch (*endianity) + { + case DW_END_default: + /* Nothing. */ + break; + case DW_END_big: + new_order = BFD_ENDIAN_BIG; + break; + case DW_END_little: + new_order = BFD_ENDIAN_LITTLE; + break; + default: + complaint (_("DW_AT_endianity has unrecognized value %s"), + pulongest (*endianity)); + break; + } } } @@ -12439,9 +12308,10 @@ read_array_order (struct die_info *die, struct dwarf2_cu *cu) if (attr != nullptr) { - LONGEST val = attr->constant_value (-1); - if (val == DW_ORD_row_major || val == DW_ORD_col_major) - return (enum dwarf_array_dim_ordering) val; + std::optional<ULONGEST> val = attr->unsigned_constant (); + if (val.has_value () && + (*val == DW_ORD_row_major || *val == DW_ORD_col_major)) + return (enum dwarf_array_dim_ordering) *val; } /* GNU F77 is a special case, as at 08/2004 array type info is the @@ -12847,7 +12717,7 @@ read_tag_pointer_type (struct die_info *die, struct dwarf2_cu *cu) struct type *type; struct attribute *attr_byte_size; struct attribute *attr_address_class; - int byte_size, addr_class; + int byte_size; struct type *target_type; target_type = die_type (die, cu); @@ -12866,8 +12736,10 @@ read_tag_pointer_type (struct die_info *die, struct dwarf2_cu *cu) byte_size = cu_header->addr_size; attr_address_class = dwarf2_attr (die, DW_AT_address_class, cu); + ULONGEST addr_class; if (attr_address_class) - addr_class = attr_address_class->constant_value (DW_ADDR_none); + addr_class = (attr_address_class->unsigned_constant () + .value_or (DW_ADDR_none)); else addr_class = DW_ADDR_none; @@ -13269,10 +13141,14 @@ read_subroutine_type (struct die_info *die, struct dwarf2_cu *cu) the subroutine die. Otherwise set the calling convention to the default value DW_CC_normal. */ attr = dwarf2_attr (die, DW_AT_calling_convention, cu); - if (attr != nullptr - && is_valid_DW_AT_calling_convention_for_subroutine (attr->constant_value (0))) - TYPE_CALLING_CONVENTION (ftype) - = (enum dwarf_calling_convention) attr->constant_value (0); + if (attr != nullptr) + { + std::optional<ULONGEST> value = attr->unsigned_constant (); + if (value.has_value () + && is_valid_DW_AT_calling_convention_for_subroutine (*value)) + TYPE_CALLING_CONVENTION (ftype) + = (enum dwarf_calling_convention) *value; + } else if (cu->producer_is_xlc_opencl ()) TYPE_CALLING_CONVENTION (ftype) = DW_CC_GDB_IBM_OpenCL; else @@ -13863,12 +13739,17 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu) struct objfile *objfile = cu->per_objfile->objfile; struct type *type; struct attribute *attr; - int encoding = 0, bits = 0; + ULONGEST encoding = 0; + int bits = 0; const char *name; attr = dwarf2_attr (die, DW_AT_encoding, cu); - if (attr != nullptr && attr->form_is_constant ()) - encoding = attr->constant_value (0); + if (attr != nullptr) + { + std::optional<ULONGEST> value = attr->unsigned_constant (); + if (value.has_value ()) + encoding = *value; + } attr = dwarf2_attr (die, DW_AT_byte_size, cu); if (attr != nullptr) bits = attr->constant_value (0) * TARGET_CHAR_BIT; @@ -15699,7 +15580,7 @@ leb128_size (const gdb_byte *buf) /* Converts DWARF language names to GDB language names. */ enum language -dwarf_lang_to_enum_language (unsigned int lang) +dwarf_lang_to_enum_language (ULONGEST lang) { enum language language; @@ -16973,33 +16854,36 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu, inlined_func ? DW_AT_call_line : DW_AT_decl_line, cu); if (attr != nullptr) - sym->set_line (attr->constant_value (0)); + sym->set_line (attr->unsigned_constant ().value_or (0)); struct dwarf2_cu *file_cu = cu; attr = dwarf2_attr (die, inlined_func ? DW_AT_call_file : DW_AT_decl_file, &file_cu); - if (attr != nullptr && attr->is_nonnegative ()) + if (attr != nullptr) { - file_name_index file_index - = (file_name_index) attr->as_nonnegative (); - struct file_entry *fe; - - if (file_cu->line_header == nullptr) + std::optional<ULONGEST> index_cst = attr->unsigned_constant (); + if (index_cst.has_value ()) { - file_and_directory fnd (nullptr, nullptr); - handle_DW_AT_stmt_list (file_cu->dies, file_cu, fnd, {}, false); - } + file_name_index file_index = (file_name_index) *index_cst; + struct file_entry *fe; - if (file_cu->line_header != nullptr) - fe = file_cu->line_header->file_name_at (file_index); - else - fe = NULL; + if (file_cu->line_header == nullptr) + { + file_and_directory fnd (nullptr, nullptr); + handle_DW_AT_stmt_list (file_cu->dies, file_cu, fnd, {}, false); + } - if (fe == NULL) - complaint (_("file index out of range")); - else - sym->set_symtab (fe->symtab); + if (file_cu->line_header != nullptr) + fe = file_cu->line_header->file_name_at (file_index); + else + fe = NULL; + + if (fe == NULL) + complaint (_("file index out of range")); + else + sym->set_symtab (fe->symtab); + } } switch (die->tag) @@ -19730,8 +19614,15 @@ cutu_reader::prepare_one_comp_unit (struct dwarf2_cu *cu, } else if (attr != nullptr) { - lang = dwarf_lang_to_enum_language (attr->constant_value (0)); - dw_lang = (dwarf_source_language) attr->constant_value (0); + std::optional<ULONGEST> lang_val = attr->unsigned_constant (); + if (lang_val.has_value ()) + { + lang = dwarf_lang_to_enum_language (*lang_val); + if (lang_val <= DW_LANG_hi_user) + dw_lang = (dwarf_source_language) *lang_val; + } + else + lang = language_minimal; } else lang = pretend_language; diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h index be6549b..ba2dd07 100644 --- a/gdb/dwarf2/read.h +++ b/gdb/dwarf2/read.h @@ -55,7 +55,6 @@ struct dwarf2_per_cu; struct mapped_index; struct mapped_debug_names; struct signatured_type; -struct type_unit_group; /* One item on the queue of compilation units to read in full symbols for. */ @@ -74,6 +73,27 @@ struct dwarf2_queue_item dwarf2_per_objfile *per_objfile; }; +/* A struct that can be used as a hash key for tables based on DW_AT_stmt_list. + This includes type_unit_group and quick_file_names. */ + +struct stmt_list_hash +{ + bool operator== (const stmt_list_hash &other) const noexcept; + + /* The DWO unit this table is from or NULL if there is none. */ + struct dwo_unit *dwo_unit; + + /* Offset in .debug_line or .debug_line.dwo. */ + sect_offset line_sect_off; +}; + +struct stmt_list_hash_hash +{ + using is_avalanching = void; + + std::uint64_t operator() (const stmt_list_hash &key) const noexcept; +}; + /* A deleter for dwarf2_per_cu that knows to downcast to signatured_type as appropriate. This approach lets us avoid a virtual destructor, which saves a bit of space. */ @@ -376,8 +396,9 @@ struct signatured_type : public dwarf2_per_cu sect_offset type_offset_in_section {}; /* Type units are grouped by their DW_AT_stmt_list entry so that they - can share them. This points to the containing symtab. */ - struct type_unit_group *type_unit_group = nullptr; + can share them. This is the key of the group this type unit is part + of. */ + std::optional<stmt_list_hash> type_unit_group_key; /* Containing DWO unit. This field is valid iff per_cu.reading_dwo_directly. */ @@ -603,10 +624,6 @@ public: std::vector<dwarf2_per_cu *> all_comp_units_index_cus; std::vector<dwarf2_per_cu *> all_comp_units_index_tus; - /* Table of struct type_unit_group objects. - The hash key is the DW_AT_stmt_list value. */ - htab_up type_unit_groups; - /* Set of signatured_types, used to look up by signature. */ signatured_type_set signatured_types; @@ -644,7 +661,8 @@ public: sorted all the TUs into "type unit groups", grouped by their DW_AT_stmt_list value. Therefore the only sharing done here is with a CU and its associated TU group if there is one. */ - htab_up quick_file_names_table; + gdb::unordered_map<stmt_list_hash, quick_file_names *, stmt_list_hash_hash> + quick_file_names_table; /* The CUs we recently read. */ std::vector<dwarf2_per_cu *> just_read_cus; @@ -815,10 +833,10 @@ struct dwarf2_per_objfile /* Set the compunit_symtab associated to PER_CU. */ void set_symtab (const dwarf2_per_cu *per_cu, compunit_symtab *symtab); - /* Get the type_unit_group_unshareable corresponding to TU_GROUP. If one + /* Get the type_unit_group_unshareable corresponding to TU_GROUP_KEY. If one does not exist, create it. */ type_unit_group_unshareable *get_type_unit_group_unshareable - (type_unit_group *tu_group); + (stmt_list_hash tu_group_key); struct type *get_type_for_signatured_type (signatured_type *sig_type) const; @@ -885,9 +903,10 @@ private: expanded yet. */ std::vector<compunit_symtab *> m_symtabs; - /* Map from a type unit group to the corresponding unshared + /* Map from a type unit group key to the corresponding unshared structure. */ - gdb::unordered_map<type_unit_group *, type_unit_group_unshareable_up> + gdb::unordered_map<stmt_list_hash, type_unit_group_unshareable_up, + stmt_list_hash_hash> m_type_units; /* Map from signatured types to the corresponding struct type. */ @@ -1047,7 +1066,7 @@ private: /* Converts DWARF language names to GDB language names. */ -enum language dwarf_lang_to_enum_language (unsigned int lang); +enum language dwarf_lang_to_enum_language (ULONGEST lang); /* Get the dwarf2_per_objfile associated to OBJFILE. */ @@ -1194,10 +1213,6 @@ extern void finalize_all_units (dwarf2_per_bfd *per_bfd); extern void create_all_units (dwarf2_per_objfile *per_objfile); -/* Create a quick_file_names hash table. */ - -extern htab_up create_quick_file_names_table (unsigned int nr_initial_entries); - /* Find the base address of the compilation unit for range lists and location lists. It will normally be specified by DW_AT_low_pc. In DWARF-3 draft 4, the base address could be overridden by diff --git a/gdb/testsuite/gdb.base/enum_cond.c b/gdb/testsuite/gdb.base/enum_cond.c index 35e126a..df8830f 100644 --- a/gdb/testsuite/gdb.base/enum_cond.c +++ b/gdb/testsuite/gdb.base/enum_cond.c @@ -46,3 +46,19 @@ main (void) return 0; } +void +exit (int status) +{ +#if HAVE_BUILTIN_TRAP + __builtin_trap (); +#endif + while (1) + ; +} + +void +_start (void) +{ + main (); + exit (0); +} diff --git a/gdb/testsuite/gdb.base/enum_cond.exp b/gdb/testsuite/gdb.base/enum_cond.exp index 3ee90f8..d58da47 100644 --- a/gdb/testsuite/gdb.base/enum_cond.exp +++ b/gdb/testsuite/gdb.base/enum_cond.exp @@ -19,7 +19,20 @@ standard_testfile .c -set opts [list debug additional_flags=-fshort-enums] +set opts {} +lappend opts debug +lappend opts additional_flags=-fshort-enums +# Without -nostdlib, on arm we run into: +# +# ld: warning: enum_cond.o uses variable-size enums yet the output is to use +# 32-bit enums; use of enum values across objects may fail +# +# due to conflicting values for Tag_ABI_enum_size between enum_cond.o and +# linked-in objects. Work around this by using -nostdlib, making sure there's +# just one object, and no such conflict can happen. +lappend opts additional_flags=-nostdlib +lappend opts additional_flags=-DHAVE_BUILTIN_TRAP=[have_builtin_trap] + if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable $opts] != "" } { untested "failed to compile" return -1 diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 481f9ec..3349da7 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -11072,5 +11072,17 @@ proc section_get {exec section} { return $retval } +# Return 1 if the compiler supports __builtin_trap, else return 0. + +gdb_caching_proc have_builtin_trap {} { + + return [gdb_can_simple_compile builtin_trap { + int main() { + __builtin_trap (); + return 0; + } + } executable] +} + # Always load compatibility stuff. load_lib future.exp |