aboutsummaryrefslogtreecommitdiff
path: root/gdb/ada-lang.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/ada-lang.c')
-rw-r--r--gdb/ada-lang.c236
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,