/* Helper routines for C++ support in GDB.
- Copyright (C) 2002-2017 Free Software Foundation, Inc.
+ Copyright (C) 2002-2019 Free Software Foundation, Inc.
Contributed by MontaVista Software.
#include "cp-abi.h"
#include "namespace.h"
#include <signal.h>
-#include "gdb_setjmp.h"
+#include "gdbsupport/gdb_setjmp.h"
#include "safe-ctype.h"
-#include "selftest.h"
+#include "gdbsupport/selftest.h"
+#include "gdbsupport/gdb-sigmask.h"
+#include <atomic>
+#include "event-top.h"
+#include "run-on-main-thread.h"
#define d_left(dc) (dc)->u.s_binary.left
#define d_right(dc) (dc)->u.s_binary.right
static void demangled_name_complaint (const char *name);
-/* Functions/variables related to overload resolution. */
-
-static int sym_return_val_size = -1;
-static int sym_return_val_index;
-static struct symbol **sym_return_val;
+/* Functions related to overload resolution. */
static void overload_list_add_symbol (struct symbol *sym,
- const char *oload_name);
+ const char *oload_name,
+ std::vector<symbol *> *overload_list);
-static void make_symbol_overload_list_using (const char *func_name,
- const char *the_namespace);
+static void add_symbol_overload_list_using
+ (const char *func_name, const char *the_namespace,
+ std::vector<symbol *> *overload_list);
-static void make_symbol_overload_list_qualified (const char *func_name);
+static void add_symbol_overload_list_qualified
+ (const char *func_name,
+ std::vector<symbol *> *overload_list);
/* The list of "maint cplus" commands. */
canonicalization_ftype *finder,
void *data)
{
- int i;
char *name;
struct symbol *sym;
name[ret_comp->u.s_name.len] = '\0';
/* Ignore any typedefs that should not be substituted. */
- for (i = 0; i < ARRAY_SIZE (ignore_typedefs); ++i)
+ for (int i = 0; i < ARRAY_SIZE (ignore_typedefs); ++i)
{
if (strcmp (name, ignore_typedefs[i]) == 0)
return 0;
sym = NULL;
- TRY
+ try
{
sym = lookup_symbol (name, 0, VAR_DOMAIN, 0).symbol;
}
- CATCH (except, RETURN_MASK_ALL)
+ catch (const gdb_exception &except)
{
return 0;
}
- END_CATCH
if (sym != NULL)
{
/* Get the real type of the typedef. */
type = check_typedef (otype);
- /* If the symbol is a namespace and its type name is no different
+ /* If the symbol name is the same as the original type name,
+ don't substitute. That would cause infinite recursion in
+ symbol lookups, as the typedef symbol is often the first
+ found symbol in the symbol table.
+
+ However, this can happen in a number of situations, such as:
+
+ If the symbol is a namespace and its type name is no different
than the name we looked up, this symbol is not a namespace
- alias and does not need to be substituted. */
- if (TYPE_CODE (otype) == TYPE_CODE_NAMESPACE
+ alias and does not need to be substituted.
+
+ If the symbol is typedef and its type name is the same
+ as the symbol's name, e.g., "typedef struct foo foo;". */
+ if (TYPE_NAME (type) != nullptr
&& strcmp (TYPE_NAME (type), name) == 0)
return 0;
- is_anon = (TYPE_TAG_NAME (type) == NULL
+ is_anon = (TYPE_NAME (type) == NULL
&& (TYPE_CODE (type) == TYPE_CODE_ENUM
|| TYPE_CODE (type) == TYPE_CODE_STRUCT
|| TYPE_CODE (type) == TYPE_CODE_UNION));
}
string_file buf;
- TRY
+ try
{
type_print (type, "", &buf, -1);
}
/* If type_print threw an exception, there is little point
in continuing, so just bow out gracefully. */
- CATCH (except, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &except)
{
return 0;
}
- END_CATCH
len = buf.size ();
- name = (char *) obstack_copy0 (&info->obstack, buf.c_str (), len);
+ name = obstack_strdup (&info->obstack, buf.string ());
/* Turn the result into a new tree. Note that this
tree will contain pointers into NAME, so NAME cannot
buf.write (d_left (comp)->u.s_name.s, d_left (comp)->u.s_name.len);
newobj.type = DEMANGLE_COMPONENT_NAME;
- newobj.u.s_name.s
- = (char *) obstack_copy0 (&info->obstack,
- buf.c_str (), buf.size ());
+ newobj.u.s_name.s = obstack_strdup (&info->obstack, buf.string ());
newobj.u.s_name.len = buf.size ();
if (inspect_type (info, &newobj, finder, data))
{
with a DEMANGLE_COMPONENT_NAME node containing the whole
name. */
ret_comp->type = DEMANGLE_COMPONENT_NAME;
- ret_comp->u.s_name.s
- = (char *) obstack_copy0 (&info->obstack,
- buf.c_str (), buf.size ());
+ ret_comp->u.s_name.s = obstack_strdup (&info->obstack, buf.string ());
ret_comp->u.s_name.len = buf.size ();
inspect_type (info, ret_comp, finder, data);
}
struct symbol *sym = NULL;
sym = NULL;
- TRY
+ try
{
sym = lookup_symbol (local_name.get (), 0,
VAR_DOMAIN, 0).symbol;
}
- CATCH (except, RETURN_MASK_ALL)
+ catch (const gdb_exception &except)
{
}
- END_CATCH
if (sym != NULL)
{
/* If FULL_NAME is the demangled name of a C++ function (including an
arg list, possibly including namespace/class qualifications),
return a new string containing only the function name (without the
- arg list/class qualifications). Otherwise, return NULL. The
- caller is responsible for freeing the memory in question. */
+ arg list/class qualifications). Otherwise, return NULL. */
-char *
+gdb::unique_xmalloc_ptr<char>
cp_func_name (const char *full_name)
{
gdb::unique_xmalloc_ptr<char> ret;
info = cp_demangled_name_to_comp (full_name, NULL);
if (!info)
- return NULL;
+ return nullptr;
ret_comp = unqualified_name_from_comp (info->tree);
if (ret_comp != NULL)
ret = cp_comp_to_string (ret_comp, 10);
- return ret.release ();
+ return ret;
}
/* Helper for cp_remove_params. DEMANGLED_NAME is the name of a
we're completing / matching everything, avoid returning NULL
which would make callers interpret the result as an error. */
if (demangled_name[0] == '\0' && completion_mode)
- return gdb::unique_xmalloc_ptr<char> (xstrdup (""));
+ return make_unique_xstrdup ("");
gdb::unique_xmalloc_ptr<char> without_params
= cp_remove_params_1 (demangled_name, false);
/* Operator names can show up in unexpected places. Since these can
contain parentheses or angle brackets, they can screw up the
recursion. But not every string 'operator' is part of an
- operater name: e.g. you could have a variable 'cooperator'. So
+ operator name: e.g. you could have a variable 'cooperator'. So
this variable tells us whether or not we should treat the string
'operator' as starting an operator. */
int operator_possible = 1;
static void
demangled_name_complaint (const char *name)
{
- complaint (&symfile_complaints,
- "unexpected demangled name '%s'", name);
+ complaint ("unexpected demangled name '%s'", name);
}
/* If NAME is the fully-qualified name of a C++
/* Overload resolution functions. */
/* Test to see if SYM is a symbol that we haven't seen corresponding
- to a function named OLOAD_NAME. If so, add it to the current
- completion list. */
+ to a function named OLOAD_NAME. If so, add it to
+ OVERLOAD_LIST. */
static void
overload_list_add_symbol (struct symbol *sym,
- const char *oload_name)
+ const char *oload_name,
+ std::vector<symbol *> *overload_list)
{
- int newsize;
- int i;
- gdb::unique_xmalloc_ptr<char> sym_name;
-
/* If there is no type information, we can't do anything, so
skip. */
if (SYMBOL_TYPE (sym) == NULL)
return;
/* skip any symbols that we've already considered. */
- for (i = 0; i < sym_return_val_index; ++i)
- if (strcmp (SYMBOL_LINKAGE_NAME (sym),
- SYMBOL_LINKAGE_NAME (sym_return_val[i])) == 0)
+ for (symbol *listed_sym : *overload_list)
+ if (strcmp (sym->linkage_name (), listed_sym->linkage_name ()) == 0)
return;
/* Get the demangled name without parameters */
- sym_name = cp_remove_params (SYMBOL_NATURAL_NAME (sym));
+ gdb::unique_xmalloc_ptr<char> sym_name
+ = cp_remove_params (sym->natural_name ());
if (!sym_name)
return;
if (strcmp (sym_name.get (), oload_name) != 0)
return;
- /* We have a match for an overload instance, so add SYM to the
- current list of overload instances */
- if (sym_return_val_index + 3 > sym_return_val_size)
- {
- newsize = (sym_return_val_size *= 2) * sizeof (struct symbol *);
- sym_return_val = (struct symbol **)
- xrealloc ((char *) sym_return_val, newsize);
- }
- sym_return_val[sym_return_val_index++] = sym;
- sym_return_val[sym_return_val_index] = NULL;
+ overload_list->push_back (sym);
}
/* Return a null-terminated list of pointers to function symbols that
are named FUNC_NAME and are visible within NAMESPACE. */
-struct symbol **
+struct std::vector<symbol *>
make_symbol_overload_list (const char *func_name,
const char *the_namespace)
{
- struct cleanup *old_cleanups;
const char *name;
+ std::vector<symbol *> overload_list;
- sym_return_val_size = 100;
- sym_return_val_index = 0;
- sym_return_val = XNEWVEC (struct symbol *, sym_return_val_size + 1);
- sym_return_val[0] = NULL;
-
- old_cleanups = make_cleanup (xfree, sym_return_val);
+ overload_list.reserve (100);
- make_symbol_overload_list_using (func_name, the_namespace);
+ add_symbol_overload_list_using (func_name, the_namespace, &overload_list);
if (the_namespace[0] == '\0')
name = func_name;
name = concatenated_name;
}
- make_symbol_overload_list_qualified (name);
-
- discard_cleanups (old_cleanups);
-
- return sym_return_val;
+ add_symbol_overload_list_qualified (name, &overload_list);
+ return overload_list;
}
/* Add all symbols with a name matching NAME in BLOCK to the overload
list. */
static void
-make_symbol_overload_list_block (const char *name,
- const struct block *block)
+add_symbol_overload_list_block (const char *name,
+ const struct block *block,
+ std::vector<symbol *> *overload_list)
{
struct block_iterator iter;
struct symbol *sym;
lookup_name_info lookup_name (name, symbol_name_match_type::FULL);
ALL_BLOCK_SYMBOLS_WITH_NAME (block, lookup_name, iter, sym)
- overload_list_add_symbol (sym, name);
+ overload_list_add_symbol (sym, name, overload_list);
}
/* Adds the function FUNC_NAME from NAMESPACE to the overload set. */
static void
-make_symbol_overload_list_namespace (const char *func_name,
- const char *the_namespace)
+add_symbol_overload_list_namespace (const char *func_name,
+ const char *the_namespace,
+ std::vector<symbol *> *overload_list)
{
const char *name;
const struct block *block = NULL;
/* Look in the static block. */
block = block_static_block (get_selected_block (0));
if (block)
- make_symbol_overload_list_block (name, block);
+ add_symbol_overload_list_block (name, block, overload_list);
/* Look in the global block. */
block = block_global_block (block);
if (block)
- make_symbol_overload_list_block (name, block);
+ add_symbol_overload_list_block (name, block, overload_list);
}
base types. */
static void
-make_symbol_overload_list_adl_namespace (struct type *type,
- const char *func_name)
+add_symbol_overload_list_adl_namespace (struct type *type,
+ const char *func_name,
+ std::vector<symbol *> *overload_list)
{
char *the_namespace;
const char *type_name;
strncpy (the_namespace, type_name, prefix_len);
the_namespace[prefix_len] = '\0';
- make_symbol_overload_list_namespace (func_name, the_namespace);
+ add_symbol_overload_list_namespace (func_name, the_namespace,
+ overload_list);
}
/* Check public base type */
for (i = 0; i < TYPE_N_BASECLASSES (type); i++)
{
if (BASETYPE_VIA_PUBLIC (type, i))
- make_symbol_overload_list_adl_namespace (TYPE_BASECLASS (type,
- i),
- func_name);
+ add_symbol_overload_list_adl_namespace (TYPE_BASECLASS (type, i),
+ func_name,
+ overload_list);
}
}
-/* Adds the overload list overload candidates for FUNC_NAME found
- through argument dependent lookup. */
+/* Adds to OVERLOAD_LIST the overload list overload candidates for
+ FUNC_NAME found through argument dependent lookup. */
-struct symbol **
-make_symbol_overload_list_adl (struct type **arg_types, int nargs,
- const char *func_name)
+void
+add_symbol_overload_list_adl (gdb::array_view<type *> arg_types,
+ const char *func_name,
+ std::vector<symbol *> *overload_list)
{
- int i;
-
- gdb_assert (sym_return_val_size != -1);
-
- for (i = 1; i <= nargs; i++)
- make_symbol_overload_list_adl_namespace (arg_types[i - 1],
- func_name);
-
- return sym_return_val;
+ for (type *arg_type : arg_types)
+ add_symbol_overload_list_adl_namespace (arg_type, func_name,
+ overload_list);
}
/* This applies the using directives to add namespaces to search in,
make_symbol_overload_list. */
static void
-make_symbol_overload_list_using (const char *func_name,
- const char *the_namespace)
+add_symbol_overload_list_using (const char *func_name,
+ const char *the_namespace,
+ std::vector<symbol *> *overload_list)
{
struct using_direct *current;
const struct block *block;
scoped_restore reset_directive_searched
= make_scoped_restore (¤t->searched, 1);
- make_symbol_overload_list_using (func_name,
- current->import_src);
+ add_symbol_overload_list_using (func_name,
+ current->import_src,
+ overload_list);
}
}
/* Now, add names for this namespace. */
- make_symbol_overload_list_namespace (func_name, the_namespace);
+ add_symbol_overload_list_namespace (func_name, the_namespace,
+ overload_list);
}
/* This does the bulk of the work of finding overloaded symbols.
(possibly including namespace info). */
static void
-make_symbol_overload_list_qualified (const char *func_name)
+add_symbol_overload_list_qualified (const char *func_name,
+ std::vector<symbol *> *overload_list)
{
- struct compunit_symtab *cust;
- struct objfile *objfile;
const struct block *b, *surrounding_static_block = 0;
/* Look through the partial symtabs for all symbols which begin by
matching FUNC_NAME. Make sure we read that symbol table in. */
- ALL_OBJFILES (objfile)
- {
- if (objfile->sf)
- objfile->sf->qf->expand_symtabs_for_function (objfile, func_name);
- }
+ for (objfile *objf : current_program_space->objfiles ())
+ {
+ if (objf->sf)
+ objf->sf->qf->expand_symtabs_for_function (objf, func_name);
+ }
/* Search upwards from currently selected frame (so that we can
complete on local vars. */
for (b = get_selected_block (0); b != NULL; b = BLOCK_SUPERBLOCK (b))
- make_symbol_overload_list_block (func_name, b);
+ add_symbol_overload_list_block (func_name, b, overload_list);
surrounding_static_block = block_static_block (get_selected_block (0));
/* Go through the symtabs and check the externs and statics for
symbols which match. */
- ALL_COMPUNITS (objfile, cust)
- {
- QUIT;
- b = BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), GLOBAL_BLOCK);
- make_symbol_overload_list_block (func_name, b);
- }
+ for (objfile *objfile : current_program_space->objfiles ())
+ {
+ for (compunit_symtab *cust : objfile->compunits ())
+ {
+ QUIT;
+ b = BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), GLOBAL_BLOCK);
+ add_symbol_overload_list_block (func_name, b, overload_list);
+ }
+ }
- ALL_COMPUNITS (objfile, cust)
- {
- QUIT;
- b = BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), STATIC_BLOCK);
- /* Don't do this block twice. */
- if (b == surrounding_static_block)
- continue;
- make_symbol_overload_list_block (func_name, b);
- }
+ for (objfile *objfile : current_program_space->objfiles ())
+ {
+ for (compunit_symtab *cust : objfile->compunits ())
+ {
+ QUIT;
+ b = BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), STATIC_BLOCK);
+ /* Don't do this block twice. */
+ if (b == surrounding_static_block)
+ continue;
+ add_symbol_overload_list_block (func_name, b, overload_list);
+ }
+ }
}
/* Lookup the rtti type for a class name. */
struct type *
-cp_lookup_rtti_type (const char *name, struct block *block)
+cp_lookup_rtti_type (const char *name, const struct block *block)
{
struct symbol * rtti_sym;
struct type * rtti_type;
#ifdef HAVE_WORKING_FORK
-/* If nonzero, attempt to catch crashes in the demangler and print
+/* If true, attempt to catch crashes in the demangler and print
useful debugging information. */
-static int catch_demangler_crashes = 1;
+static bool catch_demangler_crashes = true;
/* Stack context and environment for demangler crash recovery. */
-static SIGJMP_BUF gdb_demangle_jmp_buf;
+static thread_local SIGJMP_BUF *gdb_demangle_jmp_buf;
-/* If nonzero, attempt to dump core from the signal handler. */
+/* If true, attempt to dump core from the signal handler. */
-static int gdb_demangle_attempt_core_dump = 1;
+static std::atomic<bool> gdb_demangle_attempt_core_dump;
/* Signal handler for gdb_demangle. */
if (fork () == 0)
dump_core ();
- gdb_demangle_attempt_core_dump = 0;
+ gdb_demangle_attempt_core_dump = false;
}
- SIGLONGJMP (gdb_demangle_jmp_buf, signo);
+ SIGLONGJMP (*gdb_demangle_jmp_buf, signo);
+}
+
+/* A helper for gdb_demangle that reports a demangling failure. */
+
+static void
+report_failed_demangle (const char *name, bool core_dump_allowed,
+ int crash_signal)
+{
+ static bool error_reported = false;
+
+ if (!error_reported)
+ {
+ std::string short_msg
+ = string_printf (_("unable to demangle '%s' "
+ "(demangler failed with signal %d)"),
+ name, crash_signal);
+
+ std::string long_msg
+ = string_printf ("%s:%d: %s: %s", __FILE__, __LINE__,
+ "demangler-warning", short_msg.c_str ());
+
+ target_terminal::scoped_restore_terminal_state term_state;
+ target_terminal::ours_for_output ();
+
+ begin_line ();
+ if (core_dump_allowed)
+ fprintf_unfiltered (gdb_stderr,
+ _("%s\nAttempting to dump core.\n"),
+ long_msg.c_str ());
+ else
+ warn_cant_dump_core (long_msg.c_str ());
+
+ demangler_warning (__FILE__, __LINE__, "%s", short_msg.c_str ());
+
+ error_reported = true;
+ }
}
#endif
int crash_signal = 0;
#ifdef HAVE_WORKING_FORK
-#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
- struct sigaction sa, old_sa;
-#else
- sighandler_t ofunc;
-#endif
- static int core_dump_allowed = -1;
-
- if (core_dump_allowed == -1)
- {
- core_dump_allowed = can_dump_core (LIMIT_CUR);
-
- if (!core_dump_allowed)
- gdb_demangle_attempt_core_dump = 0;
- }
-
+ scoped_restore restore_segv
+ = make_scoped_restore (&thread_local_segv_handler,
+ catch_demangler_crashes
+ ? gdb_demangle_signal_handler
+ : nullptr);
+
+ bool core_dump_allowed = gdb_demangle_attempt_core_dump;
+ SIGJMP_BUF jmp_buf;
+ scoped_restore restore_jmp_buf
+ = make_scoped_restore (&gdb_demangle_jmp_buf, &jmp_buf);
if (catch_demangler_crashes)
{
-#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
- sa.sa_handler = gdb_demangle_signal_handler;
- sigemptyset (&sa.sa_mask);
-#ifdef HAVE_SIGALTSTACK
- sa.sa_flags = SA_ONSTACK;
+ /* The signal handler may keep the signal blocked when we longjmp out
+ of it. If we have sigprocmask, we can use it to unblock the signal
+ afterwards and we can avoid the performance overhead of saving the
+ signal mask just in case the signal gets triggered. Otherwise, just
+ tell sigsetjmp to save the mask. */
+#ifdef HAVE_SIGPROCMASK
+ crash_signal = SIGSETJMP (*gdb_demangle_jmp_buf, 0);
#else
- sa.sa_flags = 0;
+ crash_signal = SIGSETJMP (*gdb_demangle_jmp_buf, 1);
#endif
- sigaction (SIGSEGV, &sa, &old_sa);
-#else
- ofunc = signal (SIGSEGV, gdb_demangle_signal_handler);
-#endif
-
- crash_signal = SIGSETJMP (gdb_demangle_jmp_buf);
}
#endif
#ifdef HAVE_WORKING_FORK
if (catch_demangler_crashes)
{
-#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
- sigaction (SIGSEGV, &old_sa, NULL);
-#else
- signal (SIGSEGV, ofunc);
-#endif
-
if (crash_signal != 0)
- {
- static int error_reported = 0;
-
- if (!error_reported)
- {
- std::string short_msg
- = string_printf (_("unable to demangle '%s' "
- "(demangler failed with signal %d)"),
- name, crash_signal);
-
- std::string long_msg
- = string_printf ("%s:%d: %s: %s", __FILE__, __LINE__,
- "demangler-warning", short_msg.c_str ());
-
- target_terminal::scoped_restore_terminal_state term_state;
- target_terminal::ours_for_output ();
-
- begin_line ();
- if (core_dump_allowed)
- fprintf_unfiltered (gdb_stderr,
- _("%s\nAttempting to dump core.\n"),
- long_msg.c_str ());
- else
- warn_cant_dump_core (long_msg.c_str ());
-
- demangler_warning (__FILE__, __LINE__, "%s", short_msg.c_str ());
-
- error_reported = 1;
- }
+ {
+#ifdef HAVE_SIGPROCMASK
+ /* If we got the signal, SIGSEGV may still be blocked; restore it. */
+ sigset_t segv_sig_set;
+ sigemptyset (&segv_sig_set);
+ sigaddset (&segv_sig_set, SIGSEGV);
+ gdb_sigmask (SIG_UNBLOCK, &segv_sig_set, NULL);
+#endif
- result = NULL;
- }
+ /* If there was a failure, we can't report it here, because
+ we might be in a background thread. Instead, arrange for
+ the reporting to happen on the main thread. */
+ std::string copy = name;
+ run_on_main_thread ([=] ()
+ {
+ report_failed_demangle (copy.c_str (), core_dump_allowed,
+ crash_signal);
+ });
+
+ result = NULL;
+ }
}
#endif
return *demangled != NULL;
}
-/* C++ symbol_name_matcher_ftype implementation. */
+/* See cp-support.h. */
+
+unsigned int
+cp_search_name_hash (const char *search_name)
+{
+ /* cp_entire_prefix_len assumes a fully-qualified name with no
+ leading "::". */
+ if (startswith (search_name, "::"))
+ search_name += 2;
+
+ unsigned int prefix_len = cp_entire_prefix_len (search_name);
+ if (prefix_len != 0)
+ search_name += prefix_len + 2;
+
+ unsigned int hash = 0;
+ for (const char *string = search_name; *string != '\0'; ++string)
+ {
+ string = skip_spaces (string);
+
+ if (*string == '(')
+ break;
+
+ /* Ignore ABI tags such as "[abi:cxx11]. */
+ if (*string == '['
+ && startswith (string + 1, "abi:")
+ && string[5] != ':')
+ break;
+
+ hash = SYMBOL_HASH_NEXT (hash, *string);
+ }
+ return hash;
+}
+
+/* Helper for cp_symbol_name_matches (i.e., symbol_name_matcher_ftype
+ implementation for symbol_name_match_type::WILD matching). Split
+ to a separate function for unit-testing convenience.
+
+ If SYMBOL_SEARCH_NAME has more scopes than LOOKUP_NAME, we try to
+ match ignoring the extra leading scopes of SYMBOL_SEARCH_NAME.
+ This allows conveniently setting breakpoints on functions/methods
+ inside any namespace/class without specifying the fully-qualified
+ name.
-/* Helper for cp_fq_symbol_name_matches (i.e.,
- symbol_name_matcher_ftype implementation). Split to a separate
- function for unit-testing convenience.
+ E.g., these match:
+
+ [symbol search name] [lookup name]
+ foo::bar::func foo::bar::func
+ foo::bar::func bar::func
+ foo::bar::func func
+
+ While these don't:
+
+ [symbol search name] [lookup name]
+ foo::zbar::func bar::func
+ foo::bar::func foo::func
+
+ See more examples in the test_cp_symbol_name_matches selftest
+ function below.
See symbol_name_matcher_ftype for description of SYMBOL_SEARCH_NAME
and COMP_MATCH_RES.
const char *lookup_name,
size_t lookup_name_len,
strncmp_iw_mode mode,
- completion_match *match)
+ completion_match_result *comp_match_res)
+{
+ const char *sname = symbol_search_name;
+ completion_match_for_lcd *match_for_lcd
+ = (comp_match_res != NULL ? &comp_match_res->match_for_lcd : NULL);
+
+ while (true)
+ {
+ if (strncmp_iw_with_mode (sname, lookup_name, lookup_name_len,
+ mode, language_cplus, match_for_lcd) == 0)
+ {
+ if (comp_match_res != NULL)
+ {
+ /* Note here we set different MATCH and MATCH_FOR_LCD
+ strings. This is because with
+
+ (gdb) b push_bac[TAB]
+
+ we want the completion matches to list
+
+ std::vector<int>::push_back(...)
+ std::vector<char>::push_back(...)
+
+ etc., which are SYMBOL_SEARCH_NAMEs, while we want
+ the input line to auto-complete to
+
+ (gdb) push_back(...)
+
+ which is SNAME, not to
+
+ (gdb) std::vector<
+
+ which would be the regular common prefix between all
+ the matches otherwise. */
+ comp_match_res->set_match (symbol_search_name, sname);
+ }
+ return true;
+ }
+
+ unsigned int len = cp_find_first_component (sname);
+
+ if (sname[len] == '\0')
+ return false;
+
+ gdb_assert (sname[len] == ':');
+ /* Skip the '::'. */
+ sname += len + 2;
+ }
+}
+
+/* C++ symbol_name_matcher_ftype implementation. */
+
+static bool
+cp_fq_symbol_name_matches (const char *symbol_search_name,
+ const lookup_name_info &lookup_name,
+ completion_match_result *comp_match_res)
{
+ /* Get the demangled name. */
+ const std::string &name = lookup_name.cplus ().lookup_name ();
+ completion_match_for_lcd *match_for_lcd
+ = (comp_match_res != NULL ? &comp_match_res->match_for_lcd : NULL);
+ strncmp_iw_mode mode = (lookup_name.completion_mode ()
+ ? strncmp_iw_mode::NORMAL
+ : strncmp_iw_mode::MATCH_PARAMS);
+
if (strncmp_iw_with_mode (symbol_search_name,
- lookup_name, lookup_name_len,
- mode, language_cplus) == 0)
+ name.c_str (), name.size (),
+ mode, language_cplus, match_for_lcd) == 0)
{
- if (match != NULL)
- match->set_match (symbol_search_name);
+ if (comp_match_res != NULL)
+ comp_match_res->set_match (symbol_search_name);
return true;
}
return false;
}
-/* C++ symbol_name_matcher_ftype implementation. */
+/* C++ symbol_name_matcher_ftype implementation for wild matches.
+ Defers work to cp_symbol_name_matches_1. */
static bool
-cp_fq_symbol_name_matches (const char *symbol_search_name,
- const lookup_name_info &lookup_name,
- completion_match *match)
+cp_symbol_name_matches (const char *symbol_search_name,
+ const lookup_name_info &lookup_name,
+ completion_match_result *comp_match_res)
{
/* Get the demangled name. */
const std::string &name = lookup_name.cplus ().lookup_name ();
return cp_symbol_name_matches_1 (symbol_search_name,
name.c_str (), name.size (),
- mode, match);
+ mode, comp_match_res);
}
/* See cp-support.h. */
symbol_name_matcher_ftype *
cp_get_symbol_name_matcher (const lookup_name_info &lookup_name)
{
- return cp_fq_symbol_name_matches;
+ switch (lookup_name.match_type ())
+ {
+ case symbol_name_match_type::FULL:
+ case symbol_name_match_type::EXPRESSION:
+ case symbol_name_match_type::SEARCH_NAME:
+ return cp_fq_symbol_name_matches;
+ case symbol_name_match_type::WILD:
+ return cp_symbol_name_matches;
+ }
+
+ gdb_assert_not_reached ("");
}
#if GDB_SELF_TEST
namespace selftests {
-void
+static void
test_cp_symbol_name_matches ()
{
#define CHECK_MATCH(SYMBOL, INPUT) \
CHECK_MATCH_C ("abc::def::ghi()", "abc::def::ghi ( )");
CHECK_MATCH_C ("function()", "function()");
CHECK_MATCH_C ("bar::function()", "bar::function()");
+
+ /* Wild matching tests follow. */
+
+ /* Tests matching symbols in some scope. */
+ CHECK_MATCH_C ("foo::function()", "function");
+ CHECK_MATCH_C ("foo::function(int)", "function");
+ CHECK_MATCH_C ("foo::bar::function()", "function");
+ CHECK_MATCH_C ("bar::function()", "bar::function");
+ CHECK_MATCH_C ("foo::bar::function()", "bar::function");
+ CHECK_MATCH_C ("foo::bar::function(int)", "bar::function");
+
+ /* Same, with parameters in the lookup name. */
+ CHECK_MATCH_C ("foo::function()", "function()");
+ CHECK_MATCH_C ("foo::bar::function()", "function()");
+ CHECK_MATCH_C ("foo::function(int)", "function(int)");
+ CHECK_MATCH_C ("foo::function()", "foo::function()");
+ CHECK_MATCH_C ("foo::bar::function()", "bar::function()");
+ CHECK_MATCH_C ("foo::bar::function(int)", "bar::function(int)");
+ CHECK_MATCH_C ("bar::function()", "bar::function()");
+
+ CHECK_NOT_MATCH_C ("foo::bar::function(int)", "bar::function()");
+
+ CHECK_MATCH_C ("(anonymous namespace)::bar::function(int)",
+ "bar::function(int)");
+ CHECK_MATCH_C ("foo::(anonymous namespace)::bar::function(int)",
+ "function(int)");
+
+ /* Lookup scope wider than symbol scope, should not match. */
+ CHECK_NOT_MATCH_C ("function()", "bar::function");
+ CHECK_NOT_MATCH_C ("function()", "bar::function()");
+
+ /* Explicit global scope doesn't match. */
+ CHECK_NOT_MATCH_C ("foo::function()", "::function");
+ CHECK_NOT_MATCH_C ("foo::function()", "::function()");
+ CHECK_NOT_MATCH_C ("foo::function(int)", "::function()");
+ CHECK_NOT_MATCH_C ("foo::function(int)", "::function(int)");
+
+ /* Test ABI tag matching/ignoring. */
+
+ /* If the symbol name has an ABI tag, but the lookup name doesn't,
+ then the ABI tag in the symbol name is ignored. */
+ CHECK_MATCH_C ("function[abi:foo]()", "function");
+ CHECK_MATCH_C ("function[abi:foo](int)", "function");
+ CHECK_MATCH_C ("function[abi:foo]()", "function ()");
+ CHECK_NOT_MATCH_C ("function[abi:foo]()", "function (int)");
+
+ CHECK_MATCH_C ("function[abi:foo]()", "function[abi:foo]");
+ CHECK_MATCH_C ("function[abi:foo](int)", "function[abi:foo]");
+ CHECK_MATCH_C ("function[abi:foo]()", "function[abi:foo] ()");
+ CHECK_MATCH_C ("function[abi:foo][abi:bar]()", "function");
+ CHECK_MATCH_C ("function[abi:foo][abi:bar](int)", "function");
+ CHECK_MATCH_C ("function[abi:foo][abi:bar]()", "function[abi:foo]");
+ CHECK_MATCH_C ("function[abi:foo][abi:bar](int)", "function[abi:foo]");
+ CHECK_MATCH_C ("function[abi:foo][abi:bar]()", "function[abi:foo] ()");
+ CHECK_NOT_MATCH_C ("function[abi:foo][abi:bar]()", "function[abi:foo] (int)");
+
+ CHECK_MATCH_C ("function [abi:foo][abi:bar] ( )", "function [abi:foo]");
+
+ /* If the symbol name does not have an ABI tag, while the lookup
+ name has one, then there's no match. */
+ CHECK_NOT_MATCH_C ("function()", "function[abi:foo]()");
+ CHECK_NOT_MATCH_C ("function()", "function[abi:foo]");
}
/* If non-NULL, return STR wrapped in quotes. Otherwise, return a
quote (const char *str)
{
if (str != NULL)
- return std::string (1, '\"') + str + '\"';
+ return std::string (1, '"') + str + '"';
else
return "<null>";
}
NULL,
&maintenance_set_cmdlist,
&maintenance_show_cmdlist);
+
+ gdb_demangle_attempt_core_dump = can_dump_core (LIMIT_CUR);
#endif
#if GDB_SELF_TEST