| /* Helper routines for C++ support in GDB. | |
| Copyright (C) 2002-2018 Free Software Foundation, Inc. | |
| Contributed by MontaVista Software. | |
| This file is part of GDB. | |
| This program is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 3 of the License, or | |
| (at your option) any later version. | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
| #include "defs.h" | |
| #include "cp-support.h" | |
| #include "demangle.h" | |
| #include "gdbcmd.h" | |
| #include "dictionary.h" | |
| #include "objfiles.h" | |
| #include "frame.h" | |
| #include "symtab.h" | |
| #include "block.h" | |
| #include "complaints.h" | |
| #include "gdbtypes.h" | |
| #include "expression.h" | |
| #include "value.h" | |
| #include "cp-abi.h" | |
| #include "namespace.h" | |
| #include <signal.h> | |
| #include "gdb_setjmp.h" | |
| #include "safe-ctype.h" | |
| #include "selftest.h" | |
| #define d_left(dc) (dc)->u.s_binary.left | |
| #define d_right(dc) (dc)->u.s_binary.right | |
| /* Functions related to demangled name parsing. */ | |
| static unsigned int cp_find_first_component_aux (const char *name, | |
| int permissive); | |
| 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; | |
| static void overload_list_add_symbol (struct symbol *sym, | |
| const char *oload_name); | |
| static void make_symbol_overload_list_using (const char *func_name, | |
| const char *the_namespace); | |
| static void make_symbol_overload_list_qualified (const char *func_name); | |
| /* The list of "maint cplus" commands. */ | |
| struct cmd_list_element *maint_cplus_cmd_list = NULL; | |
| /* A list of typedefs which should not be substituted by replace_typedefs. */ | |
| static const char * const ignore_typedefs[] = | |
| { | |
| "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 | |
| afterwards. This speeds up the critical path for alphanumeric | |
| identifiers. */ | |
| static int | |
| cp_already_canonical (const char *string) | |
| { | |
| /* Identifier start character [a-zA-Z_]. */ | |
| if (!ISIDST (string[0])) | |
| return 0; | |
| /* These are the only two identifiers which canonicalize to other | |
| than themselves or an error: unsigned -> unsigned int and | |
| signed -> int. */ | |
| if (string[0] == 'u' && strcmp (&string[1], "nsigned") == 0) | |
| return 0; | |
| else if (string[0] == 's' && strcmp (&string[1], "igned") == 0) | |
| return 0; | |
| /* Identifier character [a-zA-Z0-9_]. */ | |
| while (ISIDNUM (string[1])) | |
| string++; | |
| if (string[1] == '\0') | |
| return 1; | |
| else | |
| 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) | |
| { | |
| int i; | |
| 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 (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 (except, RETURN_MASK_ALL) | |
| { | |
| return 0; | |
| } | |
| END_CATCH | |
| 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<demangle_parse_info> i; | |
| /* Get the real type of the typedef. */ | |
| type = check_typedef (otype); | |
| /* 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 | |
| && strcmp (TYPE_NAME (type), name) == 0) | |
| return 0; | |
| is_anon = (TYPE_TAG_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 (except, RETURN_MASK_ERROR) | |
| { | |
| return 0; | |
| } | |
| END_CATCH | |
| 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<char> 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<char> 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<char> 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 (except, RETURN_MASK_ALL) | |
| { | |
| } | |
| END_CATCH | |
| 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<demangle_parse_info> 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<char> 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 the empty string. | |
| Otherwise return the canonical form. */ | |
| std::string | |
| cp_canonicalize_string (const char *string) | |
| { | |
| std::unique_ptr<demangle_parse_info> info; | |
| unsigned int estimated_len; | |
| if (cp_already_canonical (string)) | |
| return std::string (); | |
| info = cp_demangled_name_to_comp (string, NULL); | |
| if (info == NULL) | |
| return std::string (); | |
| estimated_len = strlen (string) * 2; | |
| gdb::unique_xmalloc_ptr<char> us (cp_comp_to_string (info->tree, | |
| estimated_len)); | |
| if (!us) | |
| { | |
| 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; | |
| } | |
| /* Convert a mangled name to a demangle_component tree. *MEMORY is | |
| set to the block of used memory that should be freed when finished | |
| with the tree. DEMANGLED_P is set to the char * that should be | |
| freed when finished with the tree, or NULL if none was needed. | |
| OPTIONS will be passed to the demangler. */ | |
| static std::unique_ptr<demangle_parse_info> | |
| mangled_name_to_comp (const char *mangled_name, int options, | |
| void **memory, char **demangled_p) | |
| { | |
| 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<demangle_parse_info> info (new demangle_parse_info); | |
| info->tree = ret; | |
| *demangled_p = NULL; | |
| return info; | |
| } | |
| } | |
| /* If it doesn't, or if that failed, then try to demangle the | |
| name. */ | |
| 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. */ | |
| std::unique_ptr<demangle_parse_info> info | |
| = cp_demangled_name_to_comp (demangled_name, NULL); | |
| if (info == NULL) | |
| { | |
| xfree (demangled_name); | |
| return NULL; | |
| } | |
| *demangled_p = demangled_name; | |
| return info; | |
| } | |
| /* Return the name of the class containing method PHYSNAME. */ | |
| char * | |
| cp_class_name_from_physname (const char *physname) | |
| { | |
| void *storage = NULL; | |
| char *demangled_name = NULL; | |
| gdb::unique_xmalloc_ptr<char> ret; | |
| struct demangle_component *ret_comp, *prev_comp, *cur_comp; | |
| std::unique_ptr<demangle_parse_info> info; | |
| int done; | |
| 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. */ | |
| while (!done) | |
| switch (ret_comp->type) | |
| { | |
| case DEMANGLE_COMPONENT_CONST: | |
| case DEMANGLE_COMPONENT_RESTRICT: | |
| case DEMANGLE_COMPONENT_VOLATILE: | |
| case DEMANGLE_COMPONENT_CONST_THIS: | |
| case DEMANGLE_COMPONENT_RESTRICT_THIS: | |
| case DEMANGLE_COMPONENT_VOLATILE_THIS: | |
| case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: | |
| ret_comp = d_left (ret_comp); | |
| break; | |
| default: | |
| done = 1; | |
| break; | |
| } | |
| /* If what we have now is a function, discard the argument list. */ | |
| if (ret_comp->type == DEMANGLE_COMPONENT_TYPED_NAME) | |
| ret_comp = d_left (ret_comp); | |
| /* If what we have now is a template, strip off the template | |
| arguments. The left subtree may be a qualified name. */ | |
| if (ret_comp->type == DEMANGLE_COMPONENT_TEMPLATE) | |
| ret_comp = d_left (ret_comp); | |
| /* What we have now should be a name, possibly qualified. | |
| Additional qualifiers could live in the left subtree or the right | |
| subtree. Find the last piece. */ | |
| done = 0; | |
| prev_comp = NULL; | |
| cur_comp = ret_comp; | |
| while (!done) | |
| switch (cur_comp->type) | |
| { | |
| case DEMANGLE_COMPONENT_QUAL_NAME: | |
| case DEMANGLE_COMPONENT_LOCAL_NAME: | |
| prev_comp = cur_comp; | |
| cur_comp = d_right (cur_comp); | |
| break; | |
| case DEMANGLE_COMPONENT_TEMPLATE: | |
| case DEMANGLE_COMPONENT_NAME: | |
| case DEMANGLE_COMPONENT_CTOR: | |
| case DEMANGLE_COMPONENT_DTOR: | |
| case DEMANGLE_COMPONENT_OPERATOR: | |
| case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: | |
| done = 1; | |
| break; | |
| default: | |
| done = 1; | |
| cur_comp = NULL; | |
| break; | |
| } | |
| if (cur_comp != NULL && prev_comp != NULL) | |
| { | |
| /* We want to discard the rightmost child of PREV_COMP. */ | |
| *prev_comp = *d_left (prev_comp); | |
| /* The ten is completely arbitrary; we don't have a good | |
| estimate. */ | |
| ret = cp_comp_to_string (ret_comp, 10); | |
| } | |
| xfree (storage); | |
| xfree (demangled_name); | |
| return ret.release (); | |
| } | |
| /* Return the child of COMP which is the basename of a method, | |
| variable, et cetera. All scope qualifiers are discarded, but | |
| template arguments will be included. The component tree may be | |
| modified. */ | |
| static struct demangle_component * | |
| unqualified_name_from_comp (struct demangle_component *comp) | |
| { | |
| struct demangle_component *ret_comp = comp, *last_template; | |
| int done; | |
| done = 0; | |
| last_template = NULL; | |
| while (!done) | |
| switch (ret_comp->type) | |
| { | |
| case DEMANGLE_COMPONENT_QUAL_NAME: | |
| case DEMANGLE_COMPONENT_LOCAL_NAME: | |
| ret_comp = d_right (ret_comp); | |
| break; | |
| case DEMANGLE_COMPONENT_TYPED_NAME: | |
| ret_comp = d_left (ret_comp); | |
| break; | |
| case DEMANGLE_COMPONENT_TEMPLATE: | |
| gdb_assert (last_template == NULL); | |
| last_template = ret_comp; | |
| ret_comp = d_left (ret_comp); | |
| break; | |
| case DEMANGLE_COMPONENT_CONST: | |
| case DEMANGLE_COMPONENT_RESTRICT: | |
| case DEMANGLE_COMPONENT_VOLATILE: | |
| case DEMANGLE_COMPONENT_CONST_THIS: | |
| case DEMANGLE_COMPONENT_RESTRICT_THIS: | |
| case DEMANGLE_COMPONENT_VOLATILE_THIS: | |
| case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: | |
| ret_comp = d_left (ret_comp); | |
| break; | |
| case DEMANGLE_COMPONENT_NAME: | |
| case DEMANGLE_COMPONENT_CTOR: | |
| case DEMANGLE_COMPONENT_DTOR: | |
| case DEMANGLE_COMPONENT_OPERATOR: | |
| case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: | |
| done = 1; | |
| break; | |
| default: | |
| return NULL; | |
| break; | |
| } | |
| if (last_template) | |
| { | |
| d_left (last_template) = ret_comp; | |
| return last_template; | |
| } | |
| return ret_comp; | |
| } | |
| /* Return the name of the method whose linkage name is PHYSNAME. */ | |
| char * | |
| method_name_from_physname (const char *physname) | |
| { | |
| void *storage = NULL; | |
| char *demangled_name = NULL; | |
| gdb::unique_xmalloc_ptr<char> ret; | |
| struct demangle_component *ret_comp; | |
| std::unique_ptr<demangle_parse_info> info; | |
| info = mangled_name_to_comp (physname, DMGL_ANSI, | |
| &storage, &demangled_name); | |
| if (info == NULL) | |
| return NULL; | |
| ret_comp = unqualified_name_from_comp (info->tree); | |
| 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); | |
| 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. */ | |
| char * | |
| cp_func_name (const char *full_name) | |
| { | |
| gdb::unique_xmalloc_ptr<char> ret; | |
| struct demangle_component *ret_comp; | |
| std::unique_ptr<demangle_parse_info> info; | |
| info = cp_demangled_name_to_comp (full_name, NULL); | |
| if (!info) | |
| return NULL; | |
| ret_comp = unqualified_name_from_comp (info->tree); | |
| if (ret_comp != NULL) | |
| ret = cp_comp_to_string (ret_comp, 10); | |
| return ret.release (); | |
| } | |
| /* 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. */ | |
| static gdb::unique_xmalloc_ptr<char> | |
| cp_remove_params_1 (const char *demangled_name, bool require_params) | |
| { | |
| bool done = false; | |
| struct demangle_component *ret_comp; | |
| std::unique_ptr<demangle_parse_info> info; | |
| gdb::unique_xmalloc_ptr<char> ret; | |
| if (demangled_name == NULL) | |
| return 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) | |
| { | |
| case DEMANGLE_COMPONENT_CONST: | |
| case DEMANGLE_COMPONENT_RESTRICT: | |
| case DEMANGLE_COMPONENT_VOLATILE: | |
| case DEMANGLE_COMPONENT_CONST_THIS: | |
| case DEMANGLE_COMPONENT_RESTRICT_THIS: | |
| case DEMANGLE_COMPONENT_VOLATILE_THIS: | |
| case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: | |
| ret_comp = d_left (ret_comp); | |
| break; | |
| default: | |
| 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<char> | |
| cp_remove_params (const char *demangled_name) | |
| { | |
| return cp_remove_params_1 (demangled_name, true); | |
| } | |
| /* See cp-support.h. */ | |
| gdb::unique_xmalloc_ptr<char> | |
| 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 gdb::unique_xmalloc_ptr<char> (xstrdup ("")); | |
| gdb::unique_xmalloc_ptr<char> 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: | |
| - Names can contain function arguments or templates, so the process | |
| has to be, to some extent recursive: maybe keep track of your | |
| depth based on encountering <> and (). | |
| - Parentheses don't just have to happen at the end of a name: they | |
| can occur even if the name in question isn't a function, because | |
| a template argument might be a type that's a function. | |
| - Conversely, even if you're trying to deal with a function, its | |
| demangled name might not end with ')': it could be a const or | |
| volatile class method, in which case it ends with "const" or | |
| "volatile". | |
| - Parentheses are also used in anonymous namespaces: a variable | |
| 'foo' in an anonymous namespace gets demangled as "(anonymous | |
| namespace)::foo". | |
| - And operator names can contain parentheses or angle brackets. */ | |
| /* FIXME: carlton/2003-03-13: We have several functions here with | |
| overlapping functionality; can we combine them? Also, do they | |
| handle all the above considerations correctly? */ | |
| /* This returns the length of first component of NAME, which should be | |
| the demangled name of a C++ variable/function/method/etc. | |
| Specifically, it returns the index of the first colon forming the | |
| boundary of the first component: so, given 'A::foo' or 'A::B::foo' | |
| it returns the 1, and given 'foo', it returns 0. */ | |
| /* The character in NAME indexed by the return value is guaranteed to | |
| always be either ':' or '\0'. */ | |
| /* NOTE: carlton/2003-03-13: This function is currently only intended | |
| for internal use: it's probably not entirely safe when called on | |
| user-generated input, because some of the 'index += 2' lines in | |
| cp_find_first_component_aux might go past the end of malformed | |
| input. */ | |
| unsigned int | |
| cp_find_first_component (const char *name) | |
| { | |
| return cp_find_first_component_aux (name, 0); | |
| } | |
| /* Helper function for cp_find_first_component. Like that function, | |
| it returns the length of the first component of NAME, but to make | |
| the recursion easier, it also stops if it reaches an unexpected ')' | |
| or '>' if the value of PERMISSIVE is nonzero. */ | |
| static unsigned int | |
| cp_find_first_component_aux (const char *name, int permissive) | |
| { | |
| unsigned int index = 0; | |
| /* 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 | |
| this variable tells us whether or not we should treat the string | |
| 'operator' as starting an operator. */ | |
| int operator_possible = 1; | |
| for (;; ++index) | |
| { | |
| switch (name[index]) | |
| { | |
| case '<': | |
| /* Template; eat it up. The calls to cp_first_component | |
| should only return (I hope!) when they reach the '>' | |
| terminating the component or a '::' between two | |
| components. (Hence the '+ 2'.) */ | |
| index += 1; | |
| for (index += cp_find_first_component_aux (name + index, 1); | |
| name[index] != '>'; | |
| index += cp_find_first_component_aux (name + index, 1)) | |
| { | |
| if (name[index] != ':') | |
| { | |
| demangled_name_complaint (name); | |
| return strlen (name); | |
| } | |
| index += 2; | |
| } | |
| operator_possible = 1; | |
| break; | |
| case '(': | |
| /* Similar comment as to '<'. */ | |
| index += 1; | |
| for (index += cp_find_first_component_aux (name + index, 1); | |
| name[index] != ')'; | |
| index += cp_find_first_component_aux (name + index, 1)) | |
| { | |
| if (name[index] != ':') | |
| { | |
| demangled_name_complaint (name); | |
| return strlen (name); | |
| } | |
| index += 2; | |
| } | |
| operator_possible = 1; | |
| break; | |
| case '>': | |
| case ')': | |
| if (permissive) | |
| return index; | |
| else | |
| { | |
| demangled_name_complaint (name); | |
| return strlen (name); | |
| } | |
| case '\0': | |
| 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 | |
| && startswith (name + index, CP_OPERATOR_STR)) | |
| { | |
| 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. */ | |
| case '<': | |
| if (name[index + 1] == '<') | |
| index += 1; | |
| else | |
| index += 0; | |
| break; | |
| case '>': | |
| case '-': | |
| if (name[index + 1] == '>') | |
| index += 1; | |
| else | |
| index += 0; | |
| break; | |
| case '(': | |
| index += 1; | |
| break; | |
| default: | |
| index += 0; | |
| break; | |
| } | |
| } | |
| operator_possible = 0; | |
| break; | |
| case ' ': | |
| case ',': | |
| case '.': | |
| case '&': | |
| case '*': | |
| /* NOTE: carlton/2003-04-18: I'm not sure what the precise | |
| set of relevant characters are here: it's necessary to | |
| include any character that can show up before 'operator' | |
| in a demangled name, and it's safe to include any | |
| character that can't be part of an identifier's name. */ | |
| operator_possible = 1; | |
| break; | |
| default: | |
| operator_possible = 0; | |
| break; | |
| } | |
| } | |
| } | |
| /* Complain about a demangled name that we don't know how to parse. | |
| NAME is the demangled name in question. */ | |
| static void | |
| demangled_name_complaint (const char *name) | |
| { | |
| complaint (&symfile_complaints, | |
| "unexpected demangled name '%s'", name); | |
| } | |
| /* If NAME is the fully-qualified name of a C++ | |
| function/variable/method/etc., this returns the length of its | |
| entire prefix: all of the namespaces and classes that make up its | |
| name. Given 'A::foo', it returns 1, given 'A::B::foo', it returns | |
| 4, given 'foo', it returns 0. */ | |
| unsigned int | |
| cp_entire_prefix_len (const char *name) | |
| { | |
| unsigned int current_len = cp_find_first_component (name); | |
| unsigned int previous_len = 0; | |
| while (name[current_len] != '\0') | |
| { | |
| gdb_assert (name[current_len] == ':'); | |
| previous_len = current_len; | |
| /* Skip the '::'. */ | |
| current_len += 2; | |
| current_len += cp_find_first_component (name + current_len); | |
| } | |
| return previous_len; | |
| } | |
| /* 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. */ | |
| static void | |
| overload_list_add_symbol (struct symbol *sym, | |
| const char *oload_name) | |
| { | |
| 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) | |
| return; | |
| /* Get the demangled name without parameters */ | |
| sym_name = cp_remove_params (SYMBOL_NATURAL_NAME (sym)); | |
| if (!sym_name) | |
| return; | |
| /* skip symbols that cannot match */ | |
| 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; | |
| } | |
| /* Return a null-terminated list of pointers to function symbols that | |
| are named FUNC_NAME and are visible within NAMESPACE. */ | |
| struct symbol ** | |
| make_symbol_overload_list (const char *func_name, | |
| const char *the_namespace) | |
| { | |
| struct cleanup *old_cleanups; | |
| const char *name; | |
| 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); | |
| make_symbol_overload_list_using (func_name, the_namespace); | |
| if (the_namespace[0] == '\0') | |
| name = func_name; | |
| else | |
| { | |
| char *concatenated_name | |
| = (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 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) | |
| { | |
| 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); | |
| } | |
| /* 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) | |
| { | |
| const char *name; | |
| const struct block *block = NULL; | |
| if (the_namespace[0] == '\0') | |
| name = func_name; | |
| else | |
| { | |
| char *concatenated_name | |
| = (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; | |
| } | |
| /* Look in the static block. */ | |
| block = block_static_block (get_selected_block (0)); | |
| if (block) | |
| make_symbol_overload_list_block (name, block); | |
| /* Look in the global block. */ | |
| block = block_global_block (block); | |
| if (block) | |
| make_symbol_overload_list_block (name, block); | |
| } | |
| /* Search the namespace of the given type and namespace of and public | |
| base types. */ | |
| static void | |
| make_symbol_overload_list_adl_namespace (struct type *type, | |
| const char *func_name) | |
| { | |
| char *the_namespace; | |
| const char *type_name; | |
| int i, prefix_len; | |
| while (TYPE_CODE (type) == TYPE_CODE_PTR | |
| || TYPE_IS_REFERENCE (type) | |
| || TYPE_CODE (type) == TYPE_CODE_ARRAY | |
| || TYPE_CODE (type) == TYPE_CODE_TYPEDEF) | |
| { | |
| if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF) | |
| type = check_typedef(type); | |
| else | |
| type = TYPE_TARGET_TYPE (type); | |
| } | |
| type_name = TYPE_NAME (type); | |
| if (type_name == NULL) | |
| return; | |
| prefix_len = cp_entire_prefix_len (type_name); | |
| if (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, the_namespace); | |
| } | |
| /* Check public base type */ | |
| 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); | |
| } | |
| } | |
| /* Adds 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; | |
| } | |
| /* This applies the using directives to add namespaces to search in, | |
| and then searches for overloads in all of those namespaces. It | |
| adds the symbols found to sym_return_val. Arguments are as in | |
| make_symbol_overload_list. */ | |
| static void | |
| make_symbol_overload_list_using (const char *func_name, | |
| const char *the_namespace) | |
| { | |
| struct using_direct *current; | |
| const struct block *block; | |
| /* First, go through the using directives. If any of them apply, | |
| look in the appropriate namespaces for new functions to match | |
| on. */ | |
| for (block = get_selected_block (0); | |
| block != NULL; | |
| block = BLOCK_SUPERBLOCK (block)) | |
| for (current = block_using (block); | |
| current != NULL; | |
| current = current->next) | |
| { | |
| /* Prevent recursive calls. */ | |
| if (current->searched) | |
| continue; | |
| /* If this is a namespace alias or imported declaration ignore | |
| it. */ | |
| if (current->alias != NULL || current->declaration != NULL) | |
| continue; | |
| if (strcmp (the_namespace, current->import_dest) == 0) | |
| { | |
| /* Mark this import as searched so that the recursive call | |
| does not search it again. */ | |
| scoped_restore reset_directive_searched | |
| = make_scoped_restore (¤t->searched, 1); | |
| make_symbol_overload_list_using (func_name, | |
| current->import_src); | |
| } | |
| } | |
| /* Now, add names for this namespace. */ | |
| make_symbol_overload_list_namespace (func_name, the_namespace); | |
| } | |
| /* This does the bulk of the work of finding overloaded symbols. | |
| FUNC_NAME is the name of the overloaded function we're looking for | |
| (possibly including namespace info). */ | |
| static void | |
| make_symbol_overload_list_qualified (const char *func_name) | |
| { | |
| 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); | |
| } | |
| /* 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); | |
| 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); | |
| } | |
| 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); | |
| } | |
| } | |
| /* Lookup the rtti type for a class name. */ | |
| struct type * | |
| cp_lookup_rtti_type (const char *name, struct block *block) | |
| { | |
| struct symbol * rtti_sym; | |
| struct type * rtti_type; | |
| /* 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) | |
| { | |
| warning (_("RTTI symbol not found for class '%s'"), name); | |
| return NULL; | |
| } | |
| if (SYMBOL_CLASS (rtti_sym) != LOC_TYPEDEF) | |
| { | |
| warning (_("RTTI symbol for class '%s' is not a type"), name); | |
| return NULL; | |
| } | |
| rtti_type = check_typedef (SYMBOL_TYPE (rtti_sym)); | |
| switch (TYPE_CODE (rtti_type)) | |
| { | |
| case TYPE_CODE_STRUCT: | |
| break; | |
| case TYPE_CODE_NAMESPACE: | |
| /* chastain/2003-11-26: the symbol tables often contain fake | |
| symbols for namespaces with the same name as the struct. | |
| This warning is an indication of a bug in the lookup order | |
| or a bug in the way that the symbol tables are populated. */ | |
| warning (_("RTTI symbol for class '%s' is a namespace"), name); | |
| return NULL; | |
| default: | |
| warning (_("RTTI symbol for class '%s' has bad type"), name); | |
| return NULL; | |
| } | |
| return rtti_type; | |
| } | |
| #ifdef HAVE_WORKING_FORK | |
| /* If nonzero, attempt to catch crashes in the demangler and print | |
| useful debugging information. */ | |
| static int catch_demangler_crashes = 1; | |
| /* Stack context and environment for demangler crash recovery. */ | |
| static SIGJMP_BUF gdb_demangle_jmp_buf; | |
| /* If nonzero, attempt to dump core from the signal handler. */ | |
| static int gdb_demangle_attempt_core_dump = 1; | |
| /* 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); | |
| } | |
| #endif | |
| /* A wrapper for bfd_demangle. */ | |
| char * | |
| gdb_demangle (const char *name, int options) | |
| { | |
| 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); | |
| if (!core_dump_allowed) | |
| gdb_demangle_attempt_core_dump = 0; | |
| } | |
| 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; | |
| #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 | |
| 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) | |
| { | |
| 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; | |
| } | |
| result = NULL; | |
| } | |
| } | |
| #endif | |
| return result; | |
| } | |
| /* See cp-support.h. */ | |
| 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. | |
| 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) | |
| { | |
| 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, | |
| 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()<long>(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 | |
| "<null>" string (with no quotes). */ | |
| static std::string | |
| quote (const char *str) | |
| { | |
| if (str != NULL) | |
| return std::string (1, '\"') + str + '\"'; | |
| else | |
| return "<null>"; | |
| } | |
| /* 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<char> 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<int>()", | |
| "A::foo<int>"); | |
| CHECK_INCOMPL ("A::foo<int>(", | |
| "A::foo<int>"); | |
| 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<void(int)>::func(int)", | |
| "A::foo<void(int)>::func"); | |
| #else | |
| CHECK_INCOMPL ("A::foo<void(int)>::func(int)", | |
| "A::foo"); | |
| #endif | |
| CHECK_INCOMPL ("A::foo<void(int", | |
| "A::foo"); | |
| #undef CHECK | |
| #undef CHECK_INCOMPL | |
| } | |
| } // namespace selftests | |
| #endif /* GDB_SELF_CHECK */ | |
| /* Don't allow just "maintenance cplus". */ | |
| static void | |
| maint_cplus_command (const 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 ", | |
| all_commands, gdb_stdout); | |
| } | |
| /* 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 void | |
| first_component_command (const char *arg, int from_tty) | |
| { | |
| int len; | |
| char *prefix; | |
| if (!arg) | |
| return; | |
| len = cp_find_first_component (arg); | |
| prefix = (char *) alloca (len + 1); | |
| memcpy (prefix, arg, len); | |
| prefix[len] = '\0'; | |
| printf_unfiltered ("%s\n", prefix); | |
| } | |
| /* Implement "info vtbl". */ | |
| static void | |
| info_vtbl_command (const char *arg, int from_tty) | |
| { | |
| struct value *value; | |
| value = parse_and_eval (arg); | |
| cplus_print_vtable (value); | |
| } | |
| void | |
| _initialize_cp_support (void) | |
| { | |
| add_prefix_cmd ("cplus", class_maintenance, | |
| maint_cplus_command, | |
| _("C++ maintenance commands."), | |
| &maint_cplus_cmd_list, | |
| "maintenance cplus ", | |
| 0, &maintenancelist); | |
| add_alias_cmd ("cp", "cplus", | |
| class_maintenance, 1, | |
| &maintenancelist); | |
| add_cmd ("first_component", | |
| class_maintenance, | |
| first_component_command, | |
| _("Print the first class/namespace component of NAME."), | |
| &maint_cplus_cmd_list); | |
| add_info ("vtbl", info_vtbl_command, | |
| _("Show the virtual function table for a C++ object.\n\ | |
| Usage: info vtbl EXPRESSION\n\ | |
| Evaluate EXPRESSION and display the virtual function table for the\n\ | |
| resulting object.")); | |
| #ifdef HAVE_WORKING_FORK | |
| add_setshow_boolean_cmd ("catch-demangler-crashes", class_maintenance, | |
| &catch_demangler_crashes, _("\ | |
| Set whether to attempt to catch demangler crashes."), _("\ | |
| Show whether to attempt to catch demangler crashes."), _("\ | |
| If enabled GDB will attempt to catch demangler crashes and\n\ | |
| display the offending symbol."), | |
| NULL, | |
| NULL, | |
| &maintenance_set_cmdlist, | |
| &maintenance_show_cmdlist); | |
| #endif | |
| #if GDB_SELF_TEST | |
| selftests::register_test ("cp_symbol_name_matches", | |
| selftests::test_cp_symbol_name_matches); | |
| selftests::register_test ("cp_remove_params", | |
| selftests::test_cp_remove_params); | |
| #endif | |
| } |