diff options
Diffstat (limited to 'gdb/ada-lang.c')
-rw-r--r-- | gdb/ada-lang.c | 236 |
1 files changed, 123 insertions, 113 deletions
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index 1cfd843..3f5e707 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -1,6 +1,6 @@ /* Ada language support routines for GDB, the GNU debugger. - Copyright (C) 1992-2024 Free Software Foundation, Inc. + Copyright (C) 1992-2025 Free Software Foundation, Inc. This file is part of GDB. @@ -36,7 +36,7 @@ #include "objfiles.h" #include "breakpoint.h" #include "gdbcore.h" -#include "hashtab.h" +#include "gdbsupport/unordered_set.h" #include "gdbsupport/gdb_obstack.h" #include "ada-lang.h" #include "completer.h" @@ -52,6 +52,7 @@ #include "namespace.h" #include "cli/cli-style.h" #include "cli/cli-decode.h" +#include "gdbsupport/string-set.h" #include "value.h" #include "mi/mi-common.h" @@ -203,6 +204,8 @@ static int symbols_are_identical_enums static bool ada_identical_enum_types_p (struct type *type1, struct type *type2); + +static const char *ada_unqualify_enum_name (const char *name); /* The character set used for source files. */ @@ -347,56 +350,58 @@ struct cache_entry_search { const char *name; domain_search_flags domain; +}; + +/* Hash function for cache entry. */ + +struct cache_entry_hash +{ + using is_transparent = void; + using is_avalanching = void; - hashval_t hash () const + /* This implementation works for both cache_entry and + cache_entry_search. */ + template<typename T> + uint64_t operator() (const T &entry) const noexcept { - /* This must agree with hash_cache_entry, below. */ - return htab_hash_string (name); + return ankerl::unordered_dense::hash<std::string_view> () (entry.name); } }; -/* Hash function for cache_entry. */ +/* Equality function for cache entry. */ -static hashval_t -hash_cache_entry (const void *v) +struct cache_entry_eq { - const cache_entry *entry = (const cache_entry *) v; - return htab_hash_string (entry->name.c_str ()); -} + using is_transparent = void; -/* Equality function for cache_entry. */ - -static int -eq_cache_entry (const void *a, const void *b) -{ - const cache_entry *entrya = (const cache_entry *) a; - const cache_entry_search *entryb = (const cache_entry_search *) b; + /* This implementation works for both cache_entry and + cache_entry_search. */ + template<typename T> + bool operator() (const T &lhs, const cache_entry &rhs) const noexcept + { + return lhs.domain == rhs.domain && lhs.name == rhs.name; + } +}; - return entrya->domain == entryb->domain && entrya->name == entryb->name; -} +using cache_entry_set + = gdb::unordered_set<cache_entry, cache_entry_hash, cache_entry_eq>; /* Key to our per-program-space data. */ -static const registry<program_space>::key<htab, htab_deleter> +static const registry<program_space>::key<cache_entry_set> ada_pspace_data_handle; -/* Return this module's data for the given program space (PSPACE). - If not is found, add a zero'ed one now. - - This function always returns a valid object. */ +/* Return this module's data for the given program space (PSPACE). If + not is found, one is created. This function always returns a valid + object. */ -static htab_t +static cache_entry_set & get_ada_pspace_data (struct program_space *pspace) { - htab_t data = ada_pspace_data_handle.get (pspace); + cache_entry_set *data = ada_pspace_data_handle.get (pspace); if (data == nullptr) - { - data = htab_create_alloc (10, hash_cache_entry, eq_cache_entry, - htab_delete_entry<cache_entry>, - xcalloc, xfree); - ada_pspace_data_handle.set (pspace, data); - } + data = ada_pspace_data_handle.emplace (pspace); - return data; + return *data; } /* Utilities */ @@ -1530,7 +1535,7 @@ ada_decode (const char *encoded, bool wrap, bool operators, bool wide) { /* This is a X[bn]* sequence not separated from the previous part of the name with a non-alpha-numeric character (in other - words, immediately following an alpha-numeric character), then + words, immediately following an alphanumeric character), then verify that it is placed at the end of the encoded name. If not, then the encoding is not valid and we should abort the decoding. Otherwise, just skip it, it is used in body-nested @@ -1601,7 +1606,7 @@ ada_decode_tests () storage leak, it should not be significant unless there are massive changes in the set of decoded names in successive versions of a symbol table loaded during a single session. */ -static struct htab *decoded_names_store; +static gdb::string_set decoded_names_store; /* Returns the decoded name of GSYMBOL, as for ada_decode, caching it in the language-specific part of GSYMBOL, if it has not been @@ -1635,13 +1640,7 @@ ada_decode_symbol (const struct general_symbol_info *arg) which case, we put the result on the heap. Since we only decode when needed, we hope this usually does not cause a significant memory leak (FIXME). */ - - char **slot = (char **) htab_find_slot (decoded_names_store, - decoded.c_str (), INSERT); - - if (*slot == NULL) - *slot = xstrdup (decoded.c_str ()); - *resultp = *slot; + *resultp = decoded_names_store.insert (decoded); } } @@ -3045,7 +3044,7 @@ ada_value_subscript (struct value *arr, int arity, struct value **ind) Note: Unlike what one would expect, this function is used instead of ada_value_subscript for basically all non-packed array types. The reason - for this is that a side effect of doing our own pointer arithmetics instead + for this is that a side effect of doing our own pointer arithmetic instead of relying on value_subscript is that there is no implicit typedef peeling. This is important for arrays of array accesses, where it allows us to preserve the fact that the array's element is an array access, where the @@ -3796,7 +3795,10 @@ ada_resolve_enum (std::vector<struct block_symbol> &syms, for (int i = 0; i < syms.size (); ++i) { struct type *type2 = ada_check_typedef (syms[i].symbol->type ()); - if (strcmp (type1->name (), type2->name ()) != 0) + /* We let an anonymous enum type match a non-anonymous one. */ + if (type1->name () != nullptr + && type2->name () != nullptr + && strcmp (type1->name (), type2->name ()) != 0) continue; if (ada_identical_enum_types_p (type1, type2)) return i; @@ -3945,9 +3947,9 @@ ada_type_match (struct type *ftype, struct type *atype) atype = ada_check_typedef (atype); if (ftype->code () == TYPE_CODE_REF) - ftype = ftype->target_type (); + ftype = ada_check_typedef (ftype->target_type ()); if (atype->code () == TYPE_CODE_REF) - atype = atype->target_type (); + atype = ada_check_typedef (atype->target_type ()); switch (ftype->code ()) { @@ -4690,19 +4692,18 @@ static int lookup_cached_symbol (const char *name, domain_search_flags domain, struct symbol **sym, const struct block **block) { - htab_t tab = get_ada_pspace_data (current_program_space); + cache_entry_set &htab = get_ada_pspace_data (current_program_space); cache_entry_search search; search.name = name; search.domain = domain; - cache_entry *e = (cache_entry *) htab_find_with_hash (tab, &search, - search.hash ()); - if (e == nullptr) + auto iter = htab.find (search); + if (iter == htab.end ()) return 0; if (sym != nullptr) - *sym = e->sym; + *sym = iter->sym; if (block != nullptr) - *block = e->block; + *block = iter->block; return 1; } @@ -4730,21 +4731,8 @@ cache_symbol (const char *name, domain_search_flags domain, return; } - htab_t tab = get_ada_pspace_data (current_program_space); - cache_entry_search search; - search.name = name; - search.domain = domain; - - void **slot = htab_find_slot_with_hash (tab, &search, - search.hash (), INSERT); - - cache_entry *e = new cache_entry; - e->name = name; - e->domain = domain; - e->sym = sym; - e->block = block; - - *slot = e; + cache_entry_set &tab = get_ada_pspace_data (current_program_space); + tab.insert (cache_entry {name, domain, sym, block}); } /* Symbol Lookup */ @@ -4973,8 +4961,8 @@ ada_identical_enum_types_p (struct type *type1, struct type *type2) suffix). */ for (int i = 0; i < type1->num_fields (); i++) { - const char *name_1 = type1->field (i).name (); - const char *name_2 = type2->field (i).name (); + const char *name_1 = ada_unqualify_enum_name (type1->field (i).name ()); + const char *name_2 = ada_unqualify_enum_name (type2->field (i).name ()); int len_1 = strlen (name_1); int len_2 = strlen (name_2); @@ -5421,36 +5409,47 @@ ada_add_block_renamings (std::vector<struct block_symbol> &result, const char *r_name; /* Avoid infinite recursions: skip this renaming if we are actually - already traversing it. - - Currently, symbol lookup in Ada don't use the namespace machinery from - C++/Fortran support: skip namespace imports that use them. */ - if (renaming->searched - || (renaming->import_src != NULL - && renaming->import_src[0] != '\0') - || (renaming->import_dest != NULL - && renaming->import_dest[0] != '\0')) + already traversing it. */ + if (renaming->searched) continue; - renaming->searched = 1; /* TODO: here, we perform another name-based symbol lookup, which can pull its own multiple overloads. In theory, we should be able to do better in this case since, in DWARF, DW_AT_import is a DIE reference, not a simple name. But in order to do this, we would need to enhance the DWARF reader to associate a symbol to this renaming, instead of a - name. So, for now, we do something simpler: re-use the C++/Fortran + name. So, for now, we do something simpler: reuse the C++/Fortran namespace machinery. */ r_name = (renaming->alias != NULL ? renaming->alias : renaming->declaration); + if (r_name == nullptr) + continue; + + scoped_restore reset_searched + = make_scoped_restore (&renaming->searched, 1); + std::string storage; + if (renaming->import_src != nullptr && renaming->import_src[0] != '\0') + { + storage = std::string (renaming->import_src) + "__" + r_name; + r_name = storage.c_str (); + } + if (name_match (r_name, lookup_name, NULL)) { - lookup_name_info decl_lookup_name (renaming->declaration, + r_name = renaming->declaration; + if (renaming->import_dest != nullptr + && renaming->import_dest[0] != '\0') + { + storage = std::string (renaming->import_dest) + "__" + r_name; + r_name = storage.c_str (); + } + + lookup_name_info decl_lookup_name (r_name, lookup_name.match_type ()); ada_add_all_symbols (result, block, decl_lookup_name, domain, 1, NULL); } - renaming->searched = 0; } return result.size () != defns_mark; } @@ -6682,8 +6681,10 @@ ada_variant_discrim_name (struct type *type0) if (name == NULL || name[0] == '\000') return ""; - for (discrim_end = name + strlen (name) - 6; discrim_end != name; - discrim_end -= 1) + size_t len = strlen (name); + if (len < 6) + return ""; + for (discrim_end = name + len - 6; discrim_end != name; discrim_end -= 1) { if (startswith (discrim_end, "___XVN")) break; @@ -8753,7 +8754,14 @@ ada_atr_enum_rep (struct expression *exp, enum noside noside, struct type *type, type = type->target_type (); if (type->code () != TYPE_CODE_ENUM) error (_("'Enum_Rep only defined on enum types")); - if (!types_equal (type, arg->type ())) + /* In some scenarios, GNAT will emit two distinct-but-equivalent + enum types. For example, this can happen with an artificial + range type like the index type in: + + type AR is array (Enum_With_Gaps range <>) of MyWord; + + This is why types_equal is not used here. */ + if (!ada_identical_enum_types_p (type, arg->type ())) error (_("'Enum_Rep requires argument to have same type as enum")); return value_cast (inttype, arg); @@ -8939,15 +8947,12 @@ ada_aligned_value_addr (struct type *type, const gdb_byte *valaddr) } +/* Remove qualifications from the enumeration constant named NAME, + returning a pointer to the constant's base name. */ -/* The printed representation of an enumeration literal with encoded - name NAME. The value is good to the next call of ada_enum_name. */ -const char * -ada_enum_name (const char *name) +static const char * +ada_unqualify_enum_name (const char *name) { - static std::string storage; - const char *tmp; - /* First, unqualify the enumeration name: 1. Search for the last '.' character. If we find one, then skip all the preceding characters, the unqualified name starts @@ -8957,7 +8962,7 @@ ada_enum_name (const char *name) but stop searching when we hit an overloading suffix, which is of the form "__" followed by digits. */ - tmp = strrchr (name, '.'); + const char *tmp = strrchr (name, '.'); if (tmp != NULL) name = tmp + 1; else @@ -8971,6 +8976,17 @@ ada_enum_name (const char *name) } } + return name; +} + +/* The printed representation of an enumeration literal with encoded + name NAME. The value is good to the next call of ada_enum_name. */ +const char * +ada_enum_name (const char *name) +{ + static std::string storage; + + name = ada_unqualify_enum_name (name); if (name[0] == 'Q') { int v; @@ -9009,7 +9025,7 @@ ada_enum_name (const char *name) } else { - tmp = strstr (name, "__"); + const char *tmp = strstr (name, "__"); if (tmp == NULL) tmp = strstr (name, "$"); if (tmp != NULL) @@ -9769,7 +9785,7 @@ ada_value_cast (struct type *type, struct value *arg2) The following description is a general guide as to what should be done (and what should NOT be done) in order to evaluate an expression involving such types, and when. This does not cover how the semantic - information is encoded by GNAT as this is covered separatly. For the + information is encoded by GNAT as this is covered separately. For the document used as the reference for the GNAT encoding, see exp_dbug.ads in the GNAT sources. @@ -11747,14 +11763,14 @@ ada_exception_support_info_sniffer (void) return; } - /* Try the v0 exception suport info. */ + /* Try the v0 exception support info. */ if (ada_has_this_exception_support (&exception_support_info_v0)) { data->exception_info = &exception_support_info_v0; return; } - /* Try our fallback exception suport info. */ + /* Try our fallback exception support info. */ if (ada_has_this_exception_support (&exception_support_info_fallback)) { data->exception_info = &exception_support_info_fallback; @@ -12999,15 +13015,6 @@ ada_add_exceptions_from_frame (compiled_regex *preg, } } -/* Return true if NAME matches PREG or if PREG is NULL. */ - -static bool -name_matches_regex (const char *name, compiled_regex *preg) -{ - return (preg == NULL - || preg->exec (ada_decode (name).c_str (), 0, NULL, 0) == 0); -} - /* Add all exceptions defined globally whose name name match a regular expression, excluding standard exceptions. @@ -13031,6 +13038,13 @@ static void ada_add_global_exceptions (compiled_regex *preg, std::vector<ada_exc_info> *exceptions) { + /* Return true if NAME matches PREG or if PREG is NULL. */ + auto name_matches_regex = [&] (const char *name) + { + return preg == nullptr || preg->exec (name, 0, NULL, 0) == 0; + }; + + /* In Ada, the symbol "search name" is a linkage name, whereas the regular expression used to do the matching refers to the natural name. So match against the decoded name. */ @@ -13039,7 +13053,7 @@ ada_add_global_exceptions (compiled_regex *preg, [&] (const char *search_name) { std::string decoded = ada_decode (search_name); - return name_matches_regex (decoded.c_str (), preg); + return name_matches_regex (decoded.c_str ()); }, NULL, SEARCH_GLOBAL_BLOCK | SEARCH_STATIC_BLOCK, @@ -13065,7 +13079,7 @@ ada_add_global_exceptions (compiled_regex *preg, for (struct symbol *sym : block_iterator_range (b)) if (ada_is_non_standard_exception_sym (sym) - && name_matches_regex (sym->natural_name (), preg)) + && name_matches_regex (sym->natural_name ())) { struct ada_exc_info info = {sym->print_name (), sym->value_address ()}; @@ -14018,10 +14032,6 @@ When enabled, the debugger will stop using the DW_AT_GNAT_descriptive_type\n\ DWARF attribute."), NULL, NULL, &maint_set_ada_cmdlist, &maint_show_ada_cmdlist); - decoded_names_store = htab_create_alloc (256, htab_hash_string, - htab_eq_string, - NULL, xcalloc, xfree); - /* The ada-lang observers. */ gdb::observers::new_objfile.attach (ada_new_objfile_observer, "ada-lang"); gdb::observers::all_objfiles_removed.attach (ada_clear_symbol_cache, |