X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fcp-support.c;h=562c6f155c7f48fc6dbf445ca0447213b13eb845;hb=268a13a5a3f7c6b9b6ffc5ac2d1b24eb41f3fbdc;hp=497a8f32013d8c9bac57f096c1e811e54872979b;hpb=7b6bb8daaceb9ecf3f42dea57ae82733d6a3b2f6;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/cp-support.c b/gdb/cp-support.c index 497a8f3201..562c6f155c 100644 --- a/gdb/cp-support.c +++ b/gdb/cp-support.c @@ -1,6 +1,5 @@ /* Helper routines for C++ support in GDB. - Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011 - Free Software Foundation, Inc. + Copyright (C) 2002-2019 Free Software Foundation, Inc. Contributed by MontaVista Software. @@ -21,9 +20,7 @@ #include "defs.h" #include "cp-support.h" -#include "gdb_string.h" #include "demangle.h" -#include "gdb_assert.h" #include "gdbcmd.h" #include "dictionary.h" #include "objfiles.h" @@ -32,13 +29,14 @@ #include "block.h" #include "complaints.h" #include "gdbtypes.h" -#include "exceptions.h" #include "expression.h" #include "value.h" - +#include "cp-abi.h" +#include "namespace.h" +#include +#include "gdbsupport/gdb_setjmp.h" #include "safe-ctype.h" - -#include "psymtab.h" +#include "gdbsupport/selftest.h" #define d_left(dc) (dc)->u.s_binary.left #define d_right(dc) (dc)->u.s_binary.right @@ -50,42 +48,49 @@ static unsigned int cp_find_first_component_aux (const char *name, 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 *overload_list); -static void make_symbol_overload_list_using (const char *func_name, - const char *namespace); +static void add_symbol_overload_list_using + (const char *func_name, const char *the_namespace, + std::vector *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 *overload_list); /* The list of "maint cplus" commands. */ struct cmd_list_element *maint_cplus_cmd_list = NULL; -/* The actual commands. */ - -static void maint_cplus_command (char *arg, int from_tty); -static void first_component_command (char *arg, int from_tty); - -/* Operator validation. - NOTE: Multi-byte operators (usually the assignment variety - operator) must appear before the single byte version, i.e., "+=" - before "+". */ -static const char *operator_tokens[] = +/* A list of typedefs which should not be substituted by replace_typedefs. */ +static const char * const ignore_typedefs[] = { - "++", "+=", "+", "->*", "->", "--", "-=", "-", "*=", "*", - "/=", "/", "%=", "%", "!=", "==", "!", "&&", "<<=", "<<", - ">>=", ">>", "<=", "<", ">=", ">", "~", "&=", "&", "|=", - "||", "|", "^=", "^", "=", "()", "[]", ",", "new", "delete" - /* new[] and delete[] require special whitespace handling */ + "std::istream", "std::iostream", "std::ostream", "std::string" }; +static void + replace_typedefs (struct demangle_parse_info *info, + struct demangle_component *ret_comp, + canonicalization_ftype *finder, + void *data); + +/* A convenience function to copy STRING into OBSTACK, returning a pointer + to the newly allocated string and saving the number of bytes saved in LEN. + + It does not copy the terminating '\0' byte! */ + +static char * +copy_string_to_obstack (struct obstack *obstack, const char *string, + long *len) +{ + *len = strlen (string); + return (char *) obstack_copy (obstack, string, *len); +} + /* Return 1 if STRING is clearly already in canonical form. This function is conservative; things which it does not recognize are assumed to be non-canonical, and the parser will sort them out @@ -117,33 +122,467 @@ cp_already_canonical (const char *string) return 0; } +/* Inspect the given RET_COMP for its type. If it is a typedef, + replace the node with the typedef's tree. + + Returns 1 if any typedef substitutions were made, 0 otherwise. */ + +static int +inspect_type (struct demangle_parse_info *info, + struct demangle_component *ret_comp, + canonicalization_ftype *finder, + void *data) +{ + char *name; + struct symbol *sym; + + /* Copy the symbol's name from RET_COMP and look it up + in the symbol table. */ + name = (char *) alloca (ret_comp->u.s_name.len + 1); + memcpy (name, ret_comp->u.s_name.s, ret_comp->u.s_name.len); + name[ret_comp->u.s_name.len] = '\0'; + + /* Ignore any typedefs that should not be substituted. */ + for (int i = 0; i < ARRAY_SIZE (ignore_typedefs); ++i) + { + if (strcmp (name, ignore_typedefs[i]) == 0) + return 0; + } + + sym = NULL; + + try + { + sym = lookup_symbol (name, 0, VAR_DOMAIN, 0).symbol; + } + catch (const gdb_exception &except) + { + return 0; + } + + if (sym != NULL) + { + struct type *otype = SYMBOL_TYPE (sym); + + if (finder != NULL) + { + const char *new_name = (*finder) (otype, data); + + if (new_name != NULL) + { + ret_comp->u.s_name.s = new_name; + ret_comp->u.s_name.len = strlen (new_name); + return 1; + } + + return 0; + } + + /* If the type is a typedef or namespace alias, replace it. */ + if (TYPE_CODE (otype) == TYPE_CODE_TYPEDEF + || TYPE_CODE (otype) == TYPE_CODE_NAMESPACE) + { + long len; + int is_anon; + struct type *type; + std::unique_ptr i; + + /* Get the real type of the typedef. */ + type = check_typedef (otype); + + /* 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 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_NAME (type) == NULL + && (TYPE_CODE (type) == TYPE_CODE_ENUM + || TYPE_CODE (type) == TYPE_CODE_STRUCT + || TYPE_CODE (type) == TYPE_CODE_UNION)); + if (is_anon) + { + struct type *last = otype; + + /* Find the last typedef for the type. */ + while (TYPE_TARGET_TYPE (last) != NULL + && (TYPE_CODE (TYPE_TARGET_TYPE (last)) + == TYPE_CODE_TYPEDEF)) + last = TYPE_TARGET_TYPE (last); + + /* If there is only one typedef for this anonymous type, + do not substitute it. */ + if (type == otype) + return 0; + else + /* Use the last typedef seen as the type for this + anonymous type. */ + type = last; + } + + string_file buf; + try + { + type_print (type, "", &buf, -1); + } + /* If type_print threw an exception, there is little point + in continuing, so just bow out gracefully. */ + catch (const gdb_exception_error &except) + { + return 0; + } + + len = buf.size (); + name = (char *) obstack_copy0 (&info->obstack, buf.c_str (), len); + + /* Turn the result into a new tree. Note that this + tree will contain pointers into NAME, so NAME cannot + be free'd until all typedef conversion is done and + the final result is converted into a string. */ + i = cp_demangled_name_to_comp (name, NULL); + if (i != NULL) + { + /* Merge the two trees. */ + cp_merge_demangle_parse_infos (info, ret_comp, i.get ()); + + /* Replace any newly introduced typedefs -- but not + if the type is anonymous (that would lead to infinite + looping). */ + if (!is_anon) + replace_typedefs (info, ret_comp, finder, data); + } + else + { + /* This shouldn't happen unless the type printer has + output something that the name parser cannot grok. + Nonetheless, an ounce of prevention... + + Canonicalize the name again, and store it in the + current node (RET_COMP). */ + std::string canon = cp_canonicalize_string_no_typedefs (name); + + if (!canon.empty ()) + { + /* Copy the canonicalization into the obstack. */ + name = copy_string_to_obstack (&info->obstack, canon.c_str (), &len); + } + + ret_comp->u.s_name.s = name; + ret_comp->u.s_name.len = len; + } + + return 1; + } + } + + return 0; +} + +/* Replace any typedefs appearing in the qualified name + (DEMANGLE_COMPONENT_QUAL_NAME) represented in RET_COMP for the name parse + given in INFO. */ + +static void +replace_typedefs_qualified_name (struct demangle_parse_info *info, + struct demangle_component *ret_comp, + canonicalization_ftype *finder, + void *data) +{ + string_file buf; + struct demangle_component *comp = ret_comp; + + /* Walk each node of the qualified name, reconstructing the name of + this element. With every node, check for any typedef substitutions. + If a substitution has occurred, replace the qualified name node + with a DEMANGLE_COMPONENT_NAME node representing the new, typedef- + substituted name. */ + while (comp->type == DEMANGLE_COMPONENT_QUAL_NAME) + { + if (d_left (comp)->type == DEMANGLE_COMPONENT_NAME) + { + struct demangle_component newobj; + + 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.len = buf.size (); + if (inspect_type (info, &newobj, finder, data)) + { + char *s; + long slen; + + /* A typedef was substituted in NEW. Convert it to a + string and replace the top DEMANGLE_COMPONENT_QUAL_NAME + node. */ + + buf.clear (); + gdb::unique_xmalloc_ptr n + = cp_comp_to_string (&newobj, 100); + if (n == NULL) + { + /* If something went astray, abort typedef substitutions. */ + return; + } + + s = copy_string_to_obstack (&info->obstack, n.get (), &slen); + + d_left (ret_comp)->type = DEMANGLE_COMPONENT_NAME; + d_left (ret_comp)->u.s_name.s = s; + d_left (ret_comp)->u.s_name.len = slen; + d_right (ret_comp) = d_right (comp); + comp = ret_comp; + continue; + } + } + else + { + /* The current node is not a name, so simply replace any + typedefs in it. Then print it to the stream to continue + checking for more typedefs in the tree. */ + replace_typedefs (info, d_left (comp), finder, data); + gdb::unique_xmalloc_ptr name + = cp_comp_to_string (d_left (comp), 100); + if (name == NULL) + { + /* If something went astray, abort typedef substitutions. */ + return; + } + buf.puts (name.get ()); + } + + buf.write ("::", 2); + comp = d_right (comp); + } + + /* If the next component is DEMANGLE_COMPONENT_NAME, save the qualified + name assembled above and append the name given by COMP. Then use this + reassembled name to check for a typedef. */ + + if (comp->type == DEMANGLE_COMPONENT_NAME) + { + buf.write (comp->u.s_name.s, comp->u.s_name.len); + + /* Replace the top (DEMANGLE_COMPONENT_QUAL_NAME) node + 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.len = buf.size (); + inspect_type (info, ret_comp, finder, data); + } + else + replace_typedefs (info, comp, finder, data); +} + + +/* A function to check const and volatile qualifiers for argument types. + + "Parameter declarations that differ only in the presence + or absence of `const' and/or `volatile' are equivalent." + C++ Standard N3290, clause 13.1.3 #4. */ + +static void +check_cv_qualifiers (struct demangle_component *ret_comp) +{ + while (d_left (ret_comp) != NULL + && (d_left (ret_comp)->type == DEMANGLE_COMPONENT_CONST + || d_left (ret_comp)->type == DEMANGLE_COMPONENT_VOLATILE)) + { + d_left (ret_comp) = d_left (d_left (ret_comp)); + } +} + +/* Walk the parse tree given by RET_COMP, replacing any typedefs with + their basic types. */ + +static void +replace_typedefs (struct demangle_parse_info *info, + struct demangle_component *ret_comp, + canonicalization_ftype *finder, + void *data) +{ + if (ret_comp) + { + if (finder != NULL + && (ret_comp->type == DEMANGLE_COMPONENT_NAME + || ret_comp->type == DEMANGLE_COMPONENT_QUAL_NAME + || ret_comp->type == DEMANGLE_COMPONENT_TEMPLATE + || ret_comp->type == DEMANGLE_COMPONENT_BUILTIN_TYPE)) + { + gdb::unique_xmalloc_ptr local_name + = cp_comp_to_string (ret_comp, 10); + + if (local_name != NULL) + { + struct symbol *sym = NULL; + + sym = NULL; + try + { + sym = lookup_symbol (local_name.get (), 0, + VAR_DOMAIN, 0).symbol; + } + catch (const gdb_exception &except) + { + } + + if (sym != NULL) + { + struct type *otype = SYMBOL_TYPE (sym); + const char *new_name = (*finder) (otype, data); + + if (new_name != NULL) + { + ret_comp->type = DEMANGLE_COMPONENT_NAME; + ret_comp->u.s_name.s = new_name; + ret_comp->u.s_name.len = strlen (new_name); + return; + } + } + } + } + + switch (ret_comp->type) + { + case DEMANGLE_COMPONENT_ARGLIST: + check_cv_qualifiers (ret_comp); + /* Fall through */ + + case DEMANGLE_COMPONENT_FUNCTION_TYPE: + case DEMANGLE_COMPONENT_TEMPLATE: + case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: + case DEMANGLE_COMPONENT_TYPED_NAME: + replace_typedefs (info, d_left (ret_comp), finder, data); + replace_typedefs (info, d_right (ret_comp), finder, data); + break; + + case DEMANGLE_COMPONENT_NAME: + inspect_type (info, ret_comp, finder, data); + break; + + case DEMANGLE_COMPONENT_QUAL_NAME: + replace_typedefs_qualified_name (info, ret_comp, finder, data); + break; + + case DEMANGLE_COMPONENT_LOCAL_NAME: + case DEMANGLE_COMPONENT_CTOR: + case DEMANGLE_COMPONENT_ARRAY_TYPE: + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + replace_typedefs (info, d_right (ret_comp), finder, data); + break; + + case DEMANGLE_COMPONENT_CONST: + case DEMANGLE_COMPONENT_RESTRICT: + case DEMANGLE_COMPONENT_VOLATILE: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + case DEMANGLE_COMPONENT_CONST_THIS: + case DEMANGLE_COMPONENT_RESTRICT_THIS: + case DEMANGLE_COMPONENT_POINTER: + case DEMANGLE_COMPONENT_REFERENCE: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + replace_typedefs (info, d_left (ret_comp), finder, data); + break; + + default: + break; + } + } +} + +/* Parse STRING and convert it to canonical form, resolving any + typedefs. If parsing fails, or if STRING is already canonical, + return the empty string. Otherwise return the canonical form. If + FINDER is not NULL, then type components are passed to FINDER to be + looked up. DATA is passed verbatim to FINDER. */ + +std::string +cp_canonicalize_string_full (const char *string, + canonicalization_ftype *finder, + void *data) +{ + std::string ret; + unsigned int estimated_len; + std::unique_ptr info; + + estimated_len = strlen (string) * 2; + info = cp_demangled_name_to_comp (string, NULL); + if (info != NULL) + { + /* Replace all the typedefs in the tree. */ + replace_typedefs (info.get (), info->tree, finder, data); + + /* Convert the tree back into a string. */ + gdb::unique_xmalloc_ptr us = cp_comp_to_string (info->tree, + estimated_len); + gdb_assert (us); + + ret = us.get (); + /* Finally, compare the original string with the computed + name, returning NULL if they are the same. */ + if (ret == string) + return std::string (); + } + + return ret; +} + +/* Like cp_canonicalize_string_full, but always passes NULL for + FINDER. */ + +std::string +cp_canonicalize_string_no_typedefs (const char *string) +{ + return cp_canonicalize_string_full (string, NULL, NULL); +} + /* Parse STRING and convert it to canonical form. If parsing fails, - or if STRING is already canonical, return NULL. Otherwise return - the canonical form. The return value is allocated via xmalloc. */ + or if STRING is already canonical, return the empty string. + Otherwise return the canonical form. */ -char * +std::string cp_canonicalize_string (const char *string) { - struct demangle_component *ret_comp; + std::unique_ptr info; unsigned int estimated_len; - char *ret; if (cp_already_canonical (string)) - return NULL; + return std::string (); - ret_comp = cp_demangled_name_to_comp (string, NULL); - if (ret_comp == NULL) - return NULL; + info = cp_demangled_name_to_comp (string, NULL); + if (info == NULL) + return std::string (); estimated_len = strlen (string) * 2; - ret = cp_comp_to_string (ret_comp, estimated_len); + gdb::unique_xmalloc_ptr us (cp_comp_to_string (info->tree, + estimated_len)); - if (strcmp (string, ret) == 0) + if (!us) { - xfree (ret); - return NULL; + warning (_("internal error: string \"%s\" failed to be canonicalized"), + string); + return std::string (); } + std::string ret (us.get ()); + + if (ret == string) + return std::string (); + return ret; } @@ -153,44 +592,48 @@ cp_canonicalize_string (const char *string) freed when finished with the tree, or NULL if none was needed. OPTIONS will be passed to the demangler. */ -static struct demangle_component * +static std::unique_ptr mangled_name_to_comp (const char *mangled_name, int options, void **memory, char **demangled_p) { - struct demangle_component *ret; char *demangled_name; /* If it looks like a v3 mangled name, then try to go directly to trees. */ if (mangled_name[0] == '_' && mangled_name[1] == 'Z') { + struct demangle_component *ret; + ret = cplus_demangle_v3_components (mangled_name, options, memory); if (ret) { + std::unique_ptr info (new demangle_parse_info); + info->tree = ret; *demangled_p = NULL; - return ret; + return info; } } /* If it doesn't, or if that failed, then try to demangle the name. */ - demangled_name = cplus_demangle (mangled_name, options); + demangled_name = gdb_demangle (mangled_name, options); if (demangled_name == NULL) return NULL; /* If we could demangle the name, parse it to build the component tree. */ - ret = cp_demangled_name_to_comp (demangled_name, NULL); + std::unique_ptr info + = cp_demangled_name_to_comp (demangled_name, NULL); - if (ret == NULL) + if (info == NULL) { xfree (demangled_name); return NULL; } *demangled_p = demangled_name; - return ret; + return info; } /* Return the name of the class containing method PHYSNAME. */ @@ -199,16 +642,19 @@ char * cp_class_name_from_physname (const char *physname) { void *storage = NULL; - char *demangled_name = NULL, *ret; + char *demangled_name = NULL; + gdb::unique_xmalloc_ptr ret; struct demangle_component *ret_comp, *prev_comp, *cur_comp; + std::unique_ptr info; int done; - ret_comp = mangled_name_to_comp (physname, DMGL_ANSI, - &storage, &demangled_name); - if (ret_comp == NULL) + info = mangled_name_to_comp (physname, DMGL_ANSI, + &storage, &demangled_name); + if (info == NULL) return NULL; done = 0; + ret_comp = info->tree; /* First strip off any qualifiers, if we have a function or method. */ @@ -266,7 +712,6 @@ cp_class_name_from_physname (const char *physname) break; } - ret = NULL; if (cur_comp != NULL && prev_comp != NULL) { /* We want to discard the rightmost child of PREV_COMP. */ @@ -277,9 +722,8 @@ cp_class_name_from_physname (const char *physname) } xfree (storage); - if (demangled_name) - xfree (demangled_name); - return ret; + xfree (demangled_name); + return ret.release (); } /* Return the child of COMP which is the basename of a method, @@ -346,72 +790,75 @@ char * method_name_from_physname (const char *physname) { void *storage = NULL; - char *demangled_name = NULL, *ret; + char *demangled_name = NULL; + gdb::unique_xmalloc_ptr ret; struct demangle_component *ret_comp; + std::unique_ptr info; - ret_comp = mangled_name_to_comp (physname, DMGL_ANSI, - &storage, &demangled_name); - if (ret_comp == NULL) + info = mangled_name_to_comp (physname, DMGL_ANSI, + &storage, &demangled_name); + if (info == NULL) return NULL; - ret_comp = unqualified_name_from_comp (ret_comp); + ret_comp = unqualified_name_from_comp (info->tree); - ret = NULL; if (ret_comp != NULL) /* The ten is completely arbitrary; we don't have a good estimate. */ ret = cp_comp_to_string (ret_comp, 10); xfree (storage); - if (demangled_name) - xfree (demangled_name); - return ret; + xfree (demangled_name); + return ret.release (); } /* 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 cp_func_name (const char *full_name) { - char *ret; + gdb::unique_xmalloc_ptr ret; struct demangle_component *ret_comp; + std::unique_ptr info; - ret_comp = cp_demangled_name_to_comp (full_name, NULL); - if (!ret_comp) - return NULL; + info = cp_demangled_name_to_comp (full_name, NULL); + if (!info) + return nullptr; - ret_comp = unqualified_name_from_comp (ret_comp); + ret_comp = unqualified_name_from_comp (info->tree); - ret = NULL; if (ret_comp != NULL) ret = cp_comp_to_string (ret_comp, 10); return ret; } -/* DEMANGLED_NAME is the name of a function, including parameters and - (optionally) a return type. Return the name of the function without - parameters or return type, or NULL if we can not parse the name. */ +/* Helper for cp_remove_params. DEMANGLED_NAME is the name of a + function, including parameters and (optionally) a return type. + Return the name of the function without parameters or return type, + or NULL if we can not parse the name. If REQUIRE_PARAMS is false, + then tolerate a non-existing or unbalanced parameter list. */ -char * -cp_remove_params (const char *demangled_name) +static gdb::unique_xmalloc_ptr +cp_remove_params_1 (const char *demangled_name, bool require_params) { - int done = 0; + bool done = false; struct demangle_component *ret_comp; - char *ret = NULL; + std::unique_ptr info; + gdb::unique_xmalloc_ptr ret; if (demangled_name == NULL) return NULL; - ret_comp = cp_demangled_name_to_comp (demangled_name, NULL); - if (ret_comp == NULL) + info = cp_demangled_name_to_comp (demangled_name, NULL); + if (info == NULL) return NULL; /* First strip off any qualifiers, if we have a function or method. */ + ret_comp = info->tree; while (!done) switch (ret_comp->type) { @@ -425,17 +872,63 @@ cp_remove_params (const char *demangled_name) ret_comp = d_left (ret_comp); break; default: - done = 1; + done = true; break; } /* What we have now should be a function. Return its name. */ if (ret_comp->type == DEMANGLE_COMPONENT_TYPED_NAME) ret = cp_comp_to_string (d_left (ret_comp), 10); + else if (!require_params + && (ret_comp->type == DEMANGLE_COMPONENT_NAME + || ret_comp->type == DEMANGLE_COMPONENT_QUAL_NAME + || ret_comp->type == DEMANGLE_COMPONENT_TEMPLATE)) + ret = cp_comp_to_string (ret_comp, 10); return ret; } +/* DEMANGLED_NAME is the name of a function, including parameters and + (optionally) a return type. Return the name of the function + without parameters or return type, or NULL if we can not parse the + name. */ + +gdb::unique_xmalloc_ptr +cp_remove_params (const char *demangled_name) +{ + return cp_remove_params_1 (demangled_name, true); +} + +/* See cp-support.h. */ + +gdb::unique_xmalloc_ptr +cp_remove_params_if_any (const char *demangled_name, bool completion_mode) +{ + /* Trying to remove parameters from the empty string fails. If + 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 make_unique_xstrdup (""); + + gdb::unique_xmalloc_ptr without_params + = cp_remove_params_1 (demangled_name, false); + + if (without_params == NULL && completion_mode) + { + std::string copy = demangled_name; + + while (!copy.empty ()) + { + copy.pop_back (); + without_params = cp_remove_params_1 (copy.c_str (), false); + if (without_params != NULL) + break; + } + } + + return without_params; +} + /* Here are some random pieces of trivia to keep in mind while trying to take apart demangled names: @@ -489,10 +982,6 @@ cp_find_first_component (const char *name) the recursion easier, it also stops if it reaches an unexpected ')' or '>' if the value of PERMISSIVE is nonzero. */ -/* Let's optimize away calls to strlen("operator"). */ - -#define LENGTH_OF_OPERATOR 8 - static unsigned int cp_find_first_component_aux (const char *name, int permissive) { @@ -554,19 +1043,25 @@ cp_find_first_component_aux (const char *name, int permissive) return strlen (name); } case '\0': - case ':': return index; + case ':': + /* ':' marks a component iff the next character is also a ':'. + Otherwise it is probably malformed input. */ + if (name[index + 1] == ':') + return index; + break; case 'o': /* Operator names can screw up the recursion. */ if (operator_possible - && strncmp (name + index, "operator", - LENGTH_OF_OPERATOR) == 0) + && startswith (name + index, CP_OPERATOR_STR)) { - index += LENGTH_OF_OPERATOR; + index += CP_OPERATOR_LEN; while (ISSPACE(name[index])) ++index; switch (name[index]) { + case '\0': + return index; /* Skip over one less than the appropriate number of characters: the for loop will skip over the last one. */ @@ -618,8 +1113,7 @@ cp_find_first_component_aux (const char *name, int permissive) 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++ @@ -649,128 +1143,103 @@ cp_entire_prefix_len (const char *name) /* 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 *overload_list) { - int newsize; - int i; - 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) + for (symbol *listed_sym : *overload_list) if (strcmp (SYMBOL_LINKAGE_NAME (sym), - SYMBOL_LINKAGE_NAME (sym_return_val[i])) == 0) + SYMBOL_LINKAGE_NAME (listed_sym)) == 0) return; /* Get the demangled name without parameters */ - sym_name = cp_remove_params (SYMBOL_NATURAL_NAME (sym)); + gdb::unique_xmalloc_ptr sym_name + = cp_remove_params (SYMBOL_NATURAL_NAME (sym)); if (!sym_name) return; /* skip symbols that cannot match */ - if (strcmp (sym_name, oload_name) != 0) - { - xfree (sym_name); - return; - } - - xfree (sym_name); + 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 make_symbol_overload_list (const char *func_name, - const char *namespace) + const char *the_namespace) { - struct cleanup *old_cleanups; const char *name; + std::vector overload_list; - sym_return_val_size = 100; - sym_return_val_index = 0; - sym_return_val = xmalloc ((sym_return_val_size + 1) * - sizeof (struct symbol *)); - sym_return_val[0] = NULL; - - old_cleanups = make_cleanup (xfree, sym_return_val); + overload_list.reserve (100); - make_symbol_overload_list_using (func_name, namespace); + add_symbol_overload_list_using (func_name, the_namespace, &overload_list); - if (namespace[0] == '\0') + if (the_namespace[0] == '\0') name = func_name; else { char *concatenated_name - = alloca (strlen (namespace) + 2 + strlen (func_name) + 1); - strcpy (concatenated_name, namespace); + = (char *) alloca (strlen (the_namespace) + 2 + strlen (func_name) + 1); + strcpy (concatenated_name, the_namespace); strcat (concatenated_name, "::"); strcat (concatenated_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 *overload_list) { - struct dict_iterator iter; + struct block_iterator iter; struct symbol *sym; - const struct dictionary *dict = BLOCK_DICT (block); + lookup_name_info lookup_name (name, symbol_name_match_type::FULL); - for (sym = dict_iter_name_first (dict, name, &iter); - sym != NULL; - sym = dict_iter_name_next (name, &iter)) - overload_list_add_symbol (sym, name); + ALL_BLOCK_SYMBOLS_WITH_NAME (block, lookup_name, iter, sym) + 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 *namespace) +add_symbol_overload_list_namespace (const char *func_name, + const char *the_namespace, + std::vector *overload_list) { const char *name; const struct block *block = NULL; - if (namespace[0] == '\0') + if (the_namespace[0] == '\0') name = func_name; else { char *concatenated_name - = alloca (strlen (namespace) + 2 + strlen (func_name) + 1); + = (char *) alloca (strlen (the_namespace) + 2 + strlen (func_name) + 1); - strcpy (concatenated_name, namespace); + strcpy (concatenated_name, the_namespace); strcat (concatenated_name, "::"); strcat (concatenated_name, func_name); name = concatenated_name; @@ -778,11 +1247,13 @@ make_symbol_overload_list_namespace (const char *func_name, /* Look in the static block. */ block = block_static_block (get_selected_block (0)); - make_symbol_overload_list_block (name, block); + if (block) + add_symbol_overload_list_block (name, block, overload_list); /* Look in the global block. */ block = block_global_block (block); - make_symbol_overload_list_block (name, block); + if (block) + add_symbol_overload_list_block (name, block, overload_list); } @@ -790,15 +1261,16 @@ make_symbol_overload_list_namespace (const char *func_name, 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 *overload_list) { - char *namespace; - char *type_name; + char *the_namespace; + const char *type_name; int i, prefix_len; while (TYPE_CODE (type) == TYPE_CODE_PTR - || TYPE_CODE (type) == TYPE_CODE_REF + || TYPE_IS_REFERENCE (type) || TYPE_CODE (type) == TYPE_CODE_ARRAY || TYPE_CODE (type) == TYPE_CODE_TYPEDEF) { @@ -817,50 +1289,36 @@ make_symbol_overload_list_adl_namespace (struct type *type, if (prefix_len != 0) { - namespace = alloca (prefix_len + 1); - strncpy (namespace, type_name, prefix_len); - namespace[prefix_len] = '\0'; + the_namespace = (char *) alloca (prefix_len + 1); + strncpy (the_namespace, type_name, prefix_len); + the_namespace[prefix_len] = '\0'; - make_symbol_overload_list_namespace (func_name, namespace); + add_symbol_overload_list_namespace (func_name, the_namespace, + overload_list); } /* Check public base type */ - if (TYPE_CODE (type) == TYPE_CODE_CLASS) + if (TYPE_CODE (type) == TYPE_CODE_STRUCT) 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 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) -{ - 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; -} - -/* Used for cleanups to reset the "searched" flag in case of an - error. */ +/* Adds to OVERLOAD_LIST the overload list overload candidates for + FUNC_NAME found through argument dependent lookup. */ -static void -reset_directive_searched (void *data) +void +add_symbol_overload_list_adl (gdb::array_view arg_types, + const char *func_name, + std::vector *overload_list) { - struct using_direct *direct = data; - direct->searched = 0; + 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, @@ -869,8 +1327,9 @@ reset_directive_searched (void *data) make_symbol_overload_list. */ static void -make_symbol_overload_list_using (const char *func_name, - const char *namespace) +add_symbol_overload_list_using (const char *func_name, + const char *the_namespace, + std::vector *overload_list) { struct using_direct *current; const struct block *block; @@ -895,25 +1354,22 @@ make_symbol_overload_list_using (const char *func_name, if (current->alias != NULL || current->declaration != NULL) continue; - if (strcmp (namespace, current->import_dest) == 0) + if (strcmp (the_namespace, current->import_dest) == 0) { /* Mark this import as searched so that the recursive call does not search it again. */ - struct cleanup *old_chain; - current->searched = 1; - old_chain = make_cleanup (reset_directive_searched, - current); - - make_symbol_overload_list_using (func_name, - current->import_src); + scoped_restore reset_directive_searched + = make_scoped_restore (¤t->searched, 1); - current->searched = 0; - discard_cleanups (old_chain); + 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, namespace); + add_symbol_overload_list_namespace (func_name, the_namespace, + overload_list); } /* This does the bulk of the work of finding overloaded symbols. @@ -921,62 +1377,66 @@ make_symbol_overload_list_using (const char *func_name, (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 *overload_list) { - struct symbol *sym; - struct symtab *s; - struct objfile *objfile; const struct block *b, *surrounding_static_block = 0; - struct dict_iterator iter; - const struct dictionary *dict; /* 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_PRIMARY_SYMTABS (objfile, s) - { - QUIT; - b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 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_PRIMARY_SYMTABS (objfile, s) - { - QUIT; - b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 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; - rtti_sym = lookup_symbol (name, block, STRUCT_DOMAIN, NULL); + /* Use VAR_DOMAIN here as NAME may be a typedef. PR 18141, 18417. + Classes "live" in both STRUCT_DOMAIN and VAR_DOMAIN. */ + rtti_sym = lookup_symbol (name, block, VAR_DOMAIN, NULL).symbol; if (rtti_sym == NULL) { @@ -990,11 +1450,11 @@ cp_lookup_rtti_type (const char *name, struct block *block) return NULL; } - rtti_type = SYMBOL_TYPE (rtti_sym); + rtti_type = check_typedef (SYMBOL_TYPE (rtti_sym)); switch (TYPE_CODE (rtti_type)) { - case TYPE_CODE_CLASS: + case TYPE_CODE_STRUCT: break; case TYPE_CODE_NAMESPACE: /* chastain/2003-11-26: the symbol tables often contain fake @@ -1011,144 +1471,687 @@ cp_lookup_rtti_type (const char *name, struct block *block) return rtti_type; } -/* Don't allow just "maintenance cplus". */ +#ifdef HAVE_WORKING_FORK -static void -maint_cplus_command (char *arg, int from_tty) -{ - printf_unfiltered (_("\"maintenance cplus\" must be followed by the name of a command.\n")); - help_list (maint_cplus_cmd_list, - "maintenance cplus ", - -1, gdb_stdout); -} +/* If nonzero, attempt to catch crashes in the demangler and print + useful debugging information. */ -/* This is a front end for cp_find_first_component, for unit testing. - Be careful when using it: see the NOTE above - cp_find_first_component. */ +static int catch_demangler_crashes = 1; -static void -first_component_command (char *arg, int from_tty) -{ - int len; - char *prefix; +/* Stack context and environment for demangler crash recovery. */ - if (!arg) - return; +static SIGJMP_BUF gdb_demangle_jmp_buf; - len = cp_find_first_component (arg); - prefix = alloca (len + 1); +/* If nonzero, attempt to dump core from the signal handler. */ - memcpy (prefix, arg, len); - prefix[len] = '\0'; +static int gdb_demangle_attempt_core_dump = 1; - printf_unfiltered ("%s\n", prefix); +/* Signal handler for gdb_demangle. */ + +static void +gdb_demangle_signal_handler (int signo) +{ + if (gdb_demangle_attempt_core_dump) + { + if (fork () == 0) + dump_core (); + + gdb_demangle_attempt_core_dump = 0; + } + + SIGLONGJMP (gdb_demangle_jmp_buf, signo); } -extern initialize_file_ftype _initialize_cp_support; /* -Wmissing-prototypes */ +#endif -#define SKIP_SPACE(P) \ - do \ - { \ - while (*(P) == ' ' || *(P) == '\t') \ - ++(P); \ - } \ - while (0) +/* A wrapper for bfd_demangle. */ -/* Returns the length of the operator name or 0 if INPUT does not - point to a valid C++ operator. INPUT should start with - "operator". */ -int -cp_validate_operator (const char *input) +char * +gdb_demangle (const char *name, int options) { - int i; - char *copy; - const char *p; - struct expression *expr; - struct value *val; - struct gdb_exception except; + char *result = NULL; + 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); - p = input; + if (!core_dump_allowed) + gdb_demangle_attempt_core_dump = 0; + } - if (strncmp (p, "operator", 8) == 0) + if (catch_demangler_crashes) { - int valid = 0; +#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; +#else + sa.sa_flags = 0; +#endif + sigaction (SIGSEGV, &sa, &old_sa); +#else + ofunc = signal (SIGSEGV, gdb_demangle_signal_handler); +#endif + + crash_signal = SIGSETJMP (gdb_demangle_jmp_buf); + } +#endif - p += 8; - SKIP_SPACE (p); - for (i = 0; - i < sizeof (operator_tokens) / sizeof (operator_tokens[0]); - ++i) + if (crash_signal == 0) + result = bfd_demangle (NULL, name, options); + +#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) { - int length = strlen (operator_tokens[i]); + static int error_reported = 0; - /* By using strncmp here, we MUST have operator_tokens - ordered! See additional notes where operator_tokens is - defined above. */ - if (strncmp (p, operator_tokens[i], length) == 0) + if (!error_reported) { - const char *op = p; + std::string short_msg + = string_printf (_("unable to demangle '%s' " + "(demangler failed with signal %d)"), + name, crash_signal); - valid = 1; - p += length; + std::string long_msg + = string_printf ("%s:%d: %s: %s", __FILE__, __LINE__, + "demangler-warning", short_msg.c_str ()); - if (strncmp (op, "new", 3) == 0 - || strncmp (op, "delete", 6) == 0) - { + target_terminal::scoped_restore_terminal_state term_state; + target_terminal::ours_for_output (); - /* Special case: new[] and delete[]. We must be - careful to swallow whitespace before/in "[]". */ - SKIP_SPACE (p); + 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 ()); - if (*p == '[') - { - ++p; - SKIP_SPACE (p); - if (*p == ']') - ++p; - else - valid = 0; - } - } + demangler_warning (__FILE__, __LINE__, "%s", short_msg.c_str ()); - if (valid) - return (p - input); + error_reported = 1; } + + result = NULL; } + } +#endif - /* Check input for a conversion operator. */ + return result; +} - /* Skip past base typename. */ - while (*p != '*' && *p != '&' && *p != 0 && *p != ' ') - ++p; - SKIP_SPACE (p); +/* See cp-support.h. */ - /* Add modifiers '*' / '&'. */ - while (*p == '*' || *p == '&') - { - ++p; - SKIP_SPACE (p); - } +int +gdb_sniff_from_mangled_name (const char *mangled, char **demangled) +{ + *demangled = gdb_demangle (mangled, DMGL_PARAMS | DMGL_ANSI); + return *demangled != NULL; +} + +/* 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. + + 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. - /* Check for valid type. [Remember: input starts with - "operator".] */ - copy = savestring (input + 8, p - input - 8); - expr = NULL; - val = NULL; - TRY_CATCH (except, RETURN_MASK_ALL) + See symbol_name_matcher_ftype for description of SYMBOL_SEARCH_NAME + and COMP_MATCH_RES. + + LOOKUP_NAME/LOOKUP_NAME_LEN is the name we're looking up. + + See strncmp_iw_with_mode for description of MODE. +*/ + +static bool +cp_symbol_name_matches_1 (const char *symbol_search_name, + const char *lookup_name, + size_t lookup_name_len, + strncmp_iw_mode mode, + 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) { - expr = parse_expression (copy); - val = evaluate_type (expr); + 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::push_back(...) + std::vector::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; } - xfree (copy); - if (expr) - xfree (expr); + unsigned int len = cp_find_first_component (sname); + + if (sname[len] == '\0') + return false; - if (val != NULL && value_type (val) != NULL) - return (p - input); + gdb_assert (sname[len] == ':'); + /* Skip the '::'. */ + sname += len + 2; } +} - return 0; +/* 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, + name.c_str (), name.size (), + mode, language_cplus, match_for_lcd) == 0) + { + if (comp_match_res != NULL) + comp_match_res->set_match (symbol_search_name); + return true; + } + + return false; +} + +/* C++ symbol_name_matcher_ftype implementation for wild matches. + Defers work to cp_symbol_name_matches_1. */ + +static bool +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 (); + + strncmp_iw_mode mode = (lookup_name.completion_mode () + ? strncmp_iw_mode::NORMAL + : strncmp_iw_mode::MATCH_PARAMS); + + return cp_symbol_name_matches_1 (symbol_search_name, + name.c_str (), name.size (), + mode, comp_match_res); +} + +/* See cp-support.h. */ + +symbol_name_matcher_ftype * +cp_get_symbol_name_matcher (const lookup_name_info &lookup_name) +{ + 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 +test_cp_symbol_name_matches () +{ +#define CHECK_MATCH(SYMBOL, INPUT) \ + SELF_CHECK (cp_symbol_name_matches_1 (SYMBOL, \ + INPUT, sizeof (INPUT) - 1, \ + strncmp_iw_mode::MATCH_PARAMS, \ + NULL)) + +#define CHECK_NOT_MATCH(SYMBOL, INPUT) \ + SELF_CHECK (!cp_symbol_name_matches_1 (SYMBOL, \ + INPUT, sizeof (INPUT) - 1, \ + strncmp_iw_mode::MATCH_PARAMS, \ + NULL)) + + /* Like CHECK_MATCH, and also check that INPUT (and all substrings + that start at index 0) completes to SYMBOL. */ +#define CHECK_MATCH_C(SYMBOL, INPUT) \ + do \ + { \ + CHECK_MATCH (SYMBOL, INPUT); \ + for (size_t i = 0; i < sizeof (INPUT) - 1; i++) \ + SELF_CHECK (cp_symbol_name_matches_1 (SYMBOL, INPUT, i, \ + strncmp_iw_mode::NORMAL, \ + NULL)); \ + } while (0) + + /* Like CHECK_NOT_MATCH, and also check that INPUT does NOT complete + to SYMBOL. */ +#define CHECK_NOT_MATCH_C(SYMBOL, INPUT) \ + do \ + { \ + CHECK_NOT_MATCH (SYMBOL, INPUT); \ + SELF_CHECK (!cp_symbol_name_matches_1 (SYMBOL, INPUT, \ + sizeof (INPUT) - 1, \ + strncmp_iw_mode::NORMAL, \ + NULL)); \ + } while (0) + + /* Lookup name without parens matches all overloads. */ + CHECK_MATCH_C ("function()", "function"); + CHECK_MATCH_C ("function(int)", "function"); + + /* Check whitespace around parameters is ignored. */ + CHECK_MATCH_C ("function()", "function ()"); + CHECK_MATCH_C ("function ( )", "function()"); + CHECK_MATCH_C ("function ()", "function( )"); + CHECK_MATCH_C ("func(int)", "func( int )"); + CHECK_MATCH_C ("func(int)", "func ( int ) "); + CHECK_MATCH_C ("func ( int )", "func( int )"); + CHECK_MATCH_C ("func ( int )", "func ( int ) "); + + /* Check symbol name prefixes aren't incorrectly matched. */ + CHECK_NOT_MATCH ("func", "function"); + CHECK_NOT_MATCH ("function", "func"); + CHECK_NOT_MATCH ("function()", "func"); + + /* Check that if the lookup name includes parameters, only the right + overload matches. */ + CHECK_MATCH_C ("function(int)", "function(int)"); + CHECK_NOT_MATCH_C ("function(int)", "function()"); + + /* Check that whitespace within symbol names is not ignored. */ + CHECK_NOT_MATCH_C ("function", "func tion"); + CHECK_NOT_MATCH_C ("func__tion", "func_ _tion"); + CHECK_NOT_MATCH_C ("func11tion", "func1 1tion"); + + /* Check the converse, which can happen with template function, + where the return type is part of the demangled name. */ + CHECK_NOT_MATCH_C ("func tion", "function"); + CHECK_NOT_MATCH_C ("func1 1tion", "func11tion"); + CHECK_NOT_MATCH_C ("func_ _tion", "func__tion"); + + /* Within parameters too. */ + CHECK_NOT_MATCH_C ("func(param)", "func(par am)"); + + /* Check handling of whitespace around C++ operators. */ + CHECK_NOT_MATCH_C ("operator<<", "opera tor<<"); + CHECK_NOT_MATCH_C ("operator<<", "operator< <"); + CHECK_NOT_MATCH_C ("operator<<", "operator < <"); + CHECK_NOT_MATCH_C ("operator==", "operator= ="); + CHECK_NOT_MATCH_C ("operator==", "operator = ="); + CHECK_MATCH_C ("operator<<", "operator <<"); + CHECK_MATCH_C ("operator<<()", "operator <<"); + CHECK_NOT_MATCH_C ("operator<<()", "operator<<(int)"); + CHECK_NOT_MATCH_C ("operator<<(int)", "operator<<()"); + CHECK_MATCH_C ("operator==", "operator =="); + CHECK_MATCH_C ("operator==()", "operator =="); + CHECK_MATCH_C ("operator <<", "operator<<"); + CHECK_MATCH_C ("operator ==", "operator=="); + CHECK_MATCH_C ("operator bool", "operator bool"); + CHECK_MATCH_C ("operator bool ()", "operator bool"); + CHECK_MATCH_C ("operatorX<<", "operatorX < <"); + CHECK_MATCH_C ("Xoperator<<", "Xoperator < <"); + + CHECK_MATCH_C ("operator()(int)", "operator()(int)"); + CHECK_MATCH_C ("operator()(int)", "operator ( ) ( int )"); + CHECK_MATCH_C ("operator()(int)", "operator ( ) < long > ( int )"); + /* The first "()" is not the parameter list. */ + CHECK_NOT_MATCH ("operator()(int)", "operator"); + + /* Misc user-defined operator tests. */ + + CHECK_NOT_MATCH_C ("operator/=()", "operator ^="); + /* Same length at end of input. */ + CHECK_NOT_MATCH_C ("operator>>", "operator[]"); + /* Same length but not at end of input. */ + CHECK_NOT_MATCH_C ("operator>>()", "operator[]()"); + + CHECK_MATCH_C ("base::operator char*()", "base::operator char*()"); + CHECK_MATCH_C ("base::operator char*()", "base::operator char * ()"); + CHECK_MATCH_C ("base::operator char**()", "base::operator char * * ()"); + CHECK_MATCH ("base::operator char**()", "base::operator char * *"); + CHECK_MATCH_C ("base::operator*()", "base::operator*()"); + CHECK_NOT_MATCH_C ("base::operator char*()", "base::operatorc"); + CHECK_NOT_MATCH ("base::operator char*()", "base::operator char"); + CHECK_NOT_MATCH ("base::operator char*()", "base::operat"); + + /* Check handling of whitespace around C++ scope operators. */ + CHECK_NOT_MATCH_C ("foo::bar", "foo: :bar"); + CHECK_MATCH_C ("foo::bar", "foo :: bar"); + CHECK_MATCH_C ("foo :: bar", "foo::bar"); + + CHECK_MATCH_C ("abc::def::ghi()", "abc::def::ghi()"); + CHECK_MATCH_C ("abc::def::ghi ( )", "abc::def::ghi()"); + 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 + "" string (with no quotes). */ + +static std::string +quote (const char *str) +{ + if (str != NULL) + return std::string (1, '\"') + str + '\"'; + else + return ""; +} + +/* Check that removing parameter info out of NAME produces EXPECTED. + COMPLETION_MODE indicates whether we're testing normal and + completion mode. FILE and LINE are used to provide better test + location information in case ithe check fails. */ + +static void +check_remove_params (const char *file, int line, + const char *name, const char *expected, + bool completion_mode) +{ + gdb::unique_xmalloc_ptr result + = cp_remove_params_if_any (name, completion_mode); + + if ((expected == NULL) != (result == NULL) + || (expected != NULL + && strcmp (result.get (), expected) != 0)) + { + error (_("%s:%d: make-paramless self-test failed: (completion=%d) " + "\"%s\" -> %s, expected %s"), + file, line, completion_mode, name, + quote (result.get ()).c_str (), quote (expected).c_str ()); + } +} + +/* Entry point for cp_remove_params unit tests. */ + +static void +test_cp_remove_params () +{ + /* Check that removing parameter info out of NAME produces EXPECTED. + Checks both normal and completion modes. */ +#define CHECK(NAME, EXPECTED) \ + do \ + { \ + check_remove_params (__FILE__, __LINE__, NAME, EXPECTED, false); \ + check_remove_params (__FILE__, __LINE__, NAME, EXPECTED, true); \ + } \ + while (0) + + /* Similar, but used when NAME is incomplete -- i.e., is has + unbalanced parentheses. In this case, looking for the exact name + should fail / return empty. */ +#define CHECK_INCOMPL(NAME, EXPECTED) \ + do \ + { \ + check_remove_params (__FILE__, __LINE__, NAME, NULL, false); \ + check_remove_params (__FILE__, __LINE__, NAME, EXPECTED, true); \ + } \ + while (0) + + CHECK ("function()", "function"); + CHECK_INCOMPL ("function(", "function"); + CHECK ("function() const", "function"); + + CHECK ("(anonymous namespace)::A::B::C", + "(anonymous namespace)::A::B::C"); + + CHECK ("A::(anonymous namespace)", + "A::(anonymous namespace)"); + + CHECK_INCOMPL ("A::(anonymou", "A"); + + CHECK ("A::foo()", + "A::foo"); + + CHECK_INCOMPL ("A::foo(", + "A::foo"); + + CHECK ("A::foo<(anonymous namespace)::B>::func(int)", + "A::foo<(anonymous namespace)::B>::func"); + + CHECK_INCOMPL ("A::foo<(anonymous namespace)::B>::func(in", + "A::foo<(anonymous namespace)::B>::func"); + + CHECK_INCOMPL ("A::foo<(anonymous namespace)::B>::", + "A::foo<(anonymous namespace)::B>"); + + CHECK_INCOMPL ("A::foo<(anonymous namespace)::B>:", + "A::foo<(anonymous namespace)::B>"); + + CHECK ("A::foo<(anonymous namespace)::B>", + "A::foo<(anonymous namespace)::B>"); + + CHECK_INCOMPL ("A::foo<(anonymous namespace)::B", + "A::foo"); + + /* Shouldn't this parse? Looks like a bug in + cp_demangled_name_to_comp. See PR c++/22411. */ +#if 0 + CHECK ("A::foo::func(int)", + "A::foo::func"); +#else + CHECK_INCOMPL ("A::foo::func(int)", + "A::foo"); +#endif + + CHECK_INCOMPL ("A::foo