/* Helper routines for C++ support in GDB.
- Copyright (C) 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2002-2014 Free Software Foundation, Inc.
Contributed by MontaVista Software.
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
-#include <ctype.h>
#include "cp-support.h"
-#include "gdb_string.h"
+#include <string.h>
#include "demangle.h"
#include "gdb_assert.h"
#include "gdbcmd.h"
#include "block.h"
#include "complaints.h"
#include "gdbtypes.h"
+#include "exceptions.h"
+#include "expression.h"
+#include "value.h"
+#include "cp-abi.h"
+
+#include "safe-ctype.h"
#define d_left(dc) (dc)->u.s_binary.left
#define d_right(dc) (dc)->u.s_binary.right
/* Functions/variables related to overload resolution. */
-static int sym_return_val_size;
+static int sym_return_val_size = -1;
static int sym_return_val_index;
static struct symbol **sym_return_val;
static void make_symbol_overload_list_qualified (const char *func_name);
-static void read_in_psymtabs (const char *oload_name);
-
/* The list of "maint cplus" commands. */
struct cmd_list_element *maint_cplus_cmd_list = NULL;
static void maint_cplus_command (char *arg, int from_tty);
static void first_component_command (char *arg, int from_tty);
-/* Return the canonicalized form of STRING, or NULL if STRING can not be
- parsed. The return value is allocated via xmalloc.
+/* 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 obstack_copy (obstack, string, *len);
+}
+
+/* A cleanup wrapper for cp_demangled_name_parse_free. */
+
+static void
+do_demangled_name_parse_free_cleanup (void *data)
+{
+ struct demangle_parse_info *info = (struct demangle_parse_info *) data;
+
+ cp_demangled_name_parse_free (info);
+}
+
+/* Create a cleanup for C++ name parsing. */
+
+struct cleanup *
+make_cleanup_cp_demangled_name_parse_free (struct demangle_parse_info *info)
+{
+ return make_cleanup (do_demangled_name_parse_free_cleanup, info);
+}
+
+/* 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;
+ volatile struct gdb_exception except;
+
+ /* 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_CATCH (except, RETURN_MASK_ALL)
+ {
+ sym = lookup_symbol (name, 0, VAR_DOMAIN, 0);
+ }
+
+ if (except.reason >= 0 && 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;
+ struct demangle_parse_info *i;
+ struct ui_file *buf;
+
+ /* 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;
+ }
+
+ buf = mem_fileopen ();
+ TRY_CATCH (except, RETURN_MASK_ERROR)
+ {
+ type_print (type, "", buf, -1);
+ }
+
+ /* If type_print threw an exception, there is little point
+ in continuing, so just bow out gracefully. */
+ if (except.reason < 0)
+ {
+ ui_file_delete (buf);
+ return 0;
+ }
+
+ name = ui_file_obsavestring (buf, &info->obstack, &len);
+ ui_file_delete (buf);
+
+ /* 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);
+
+ /* 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). */
+ char *canon = cp_canonicalize_string_no_typedefs (name);
+
+ if (canon != NULL)
+ {
+ /* Copy the canonicalization into the obstack and
+ free CANON. */
+ name = copy_string_to_obstack (&info->obstack, canon, &len);
+ xfree (canon);
+ }
+
+ 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)
+{
+ long len;
+ char *name;
+ struct ui_file *buf = mem_fileopen ();
+ 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 new;
+
+ ui_file_write (buf, d_left (comp)->u.s_name.s,
+ d_left (comp)->u.s_name.len);
+ name = ui_file_obsavestring (buf, &info->obstack, &len);
+ new.type = DEMANGLE_COMPONENT_NAME;
+ new.u.s_name.s = name;
+ new.u.s_name.len = len;
+ if (inspect_type (info, &new, finder, data))
+ {
+ char *n, *s;
+ long slen;
- drow/2005-03-07: Should we also return NULL for things that trivially do
- not require any change? e.g. simple identifiers. This could be more
- efficient. */
+ /* A typedef was substituted in NEW. Convert it to a
+ string and replace the top DEMANGLE_COMPONENT_QUAL_NAME
+ node. */
+
+ ui_file_rewind (buf);
+ n = cp_comp_to_string (&new, 100);
+ if (n == NULL)
+ {
+ /* If something went astray, abort typedef substitutions. */
+ ui_file_delete (buf);
+ return;
+ }
+
+ s = copy_string_to_obstack (&info->obstack, n, &slen);
+ xfree (n);
+
+ 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);
+ name = cp_comp_to_string (d_left (comp), 100);
+ if (name == NULL)
+ {
+ /* If something went astray, abort typedef substitutions. */
+ ui_file_delete (buf);
+ return;
+ }
+ fputs_unfiltered (name, buf);
+ xfree (name);
+ }
+
+ ui_file_write (buf, "::", 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)
+ {
+ ui_file_write (buf, comp->u.s_name.s, comp->u.s_name.len);
+ name = ui_file_obsavestring (buf, &info->obstack, &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 = name;
+ ret_comp->u.s_name.len = len;
+ inspect_type (info, ret_comp, finder, data);
+ }
+ else
+ replace_typedefs (info, comp, finder, data);
+
+ ui_file_delete (buf);
+}
+
+
+/* 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))
+ {
+ char *local_name = cp_comp_to_string (ret_comp, 10);
+
+ if (local_name != NULL)
+ {
+ struct symbol *sym;
+ volatile struct gdb_exception except;
+
+ sym = NULL;
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ sym = lookup_symbol (local_name, 0, VAR_DOMAIN, 0);
+ }
+ xfree (local_name);
+
+ if (except.reason >= 0 && 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:
+ 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 NULL.
+ Otherwise return the canonical form. The return value is allocated via
+ xmalloc. If FINDER is not NULL, then type components are passed to
+ FINDER to be looked up. DATA is passed verbatim to FINDER. */
+
+char *
+cp_canonicalize_string_full (const char *string,
+ canonicalization_ftype *finder,
+ void *data)
+{
+ char *ret;
+ unsigned int estimated_len;
+ struct demangle_parse_info *info;
+
+ ret = NULL;
+ 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, info->tree, finder, data);
+
+ /* Convert the tree back into a string. */
+ ret = cp_comp_to_string (info->tree, estimated_len);
+ gdb_assert (ret != NULL);
+
+ /* Free the parse information. */
+ cp_demangled_name_parse_free (info);
+
+ /* Finally, compare the original string with the computed
+ name, returning NULL if they are the same. */
+ if (strcmp (string, ret) == 0)
+ {
+ xfree (ret);
+ return NULL;
+ }
+ }
+
+ return ret;
+}
+
+/* Like cp_canonicalize_string_full, but always passes NULL for
+ FINDER. */
+
+char *
+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. */
char *
cp_canonicalize_string (const char *string)
{
- void *storage;
- struct demangle_component *ret_comp;
+ struct demangle_parse_info *info;
+ unsigned int estimated_len;
char *ret;
- int len = strlen (string);
- len = len + len / 8;
+ if (cp_already_canonical (string))
+ return NULL;
- ret_comp = cp_demangled_name_to_comp (string, &storage, NULL);
- if (ret_comp == NULL)
+ info = cp_demangled_name_to_comp (string, NULL);
+ if (info == NULL)
return NULL;
- ret = cp_comp_to_string (ret_comp, len);
+ estimated_len = strlen (string) * 2;
+ ret = cp_comp_to_string (info->tree, estimated_len);
+ cp_demangled_name_parse_free (info);
- xfree (storage);
+ if (ret == NULL)
+ {
+ warning (_("internal error: string \"%s\" failed to be canonicalized"),
+ string);
+ return NULL;
+ }
+
+ if (strcmp (string, ret) == 0)
+ {
+ xfree (ret);
+ return NULL;
+ }
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. */
+/* 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 struct demangle_component *
+static struct demangle_parse_info *
mangled_name_to_comp (const char *mangled_name, int options,
void **memory, char **demangled_p)
{
- struct demangle_component *ret;
char *demangled_name;
- int len;
+ struct demangle_parse_info *info;
/* If it looks like a v3 mangled name, then try to go directly
to trees. */
if (mangled_name[0] == '_' && mangled_name[1] == 'Z')
{
- ret = cplus_demangle_v3_components (mangled_name, options, memory);
+ struct demangle_component *ret;
+
+ ret = cplus_demangle_v3_components (mangled_name,
+ options, memory);
if (ret)
{
+ info = cp_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);
+ /* 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. */
- ret = cp_demangled_name_to_comp (demangled_name, memory, NULL);
+ /* If we could demangle the name, parse it to build the component
+ tree. */
+ info = cp_demangled_name_to_comp (demangled_name, NULL);
- if (ret == NULL)
+ if (info == NULL)
{
- free (demangled_name);
+ xfree (demangled_name);
return NULL;
}
*demangled_p = demangled_name;
- return ret;
+ return info;
}
/* Return the name of the class containing method PHYSNAME. */
char *
cp_class_name_from_physname (const char *physname)
{
- void *storage;
+ void *storage = NULL;
char *demangled_name = NULL, *ret;
struct demangle_component *ret_comp, *prev_comp, *cur_comp;
+ struct demangle_parse_info *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. */
+ /* First strip off any qualifiers, if we have a function or
+ method. */
while (!done)
switch (ret_comp->type)
{
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. */
+ /* 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;
{
/* 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. */
+ /* 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);
+ xfree (demangled_name);
+ cp_demangled_name_parse_free (info);
return ret;
}
-/* 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. */
+/* 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)
char *
method_name_from_physname (const char *physname)
{
- void *storage;
+ void *storage = NULL;
char *demangled_name = NULL, *ret;
struct demangle_component *ret_comp;
- int done;
+ struct demangle_parse_info *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. */
+ /* 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);
+ xfree (demangled_name);
+ cp_demangled_name_parse_free (info);
return ret;
}
char *
cp_func_name (const char *full_name)
{
- void *storage;
char *ret;
struct demangle_component *ret_comp;
- int done;
+ struct demangle_parse_info *info;
- ret_comp = cp_demangled_name_to_comp (full_name, &storage, NULL);
- if (!ret_comp)
+ info = cp_demangled_name_to_comp (full_name, NULL);
+ if (!info)
return NULL;
- 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);
- xfree (storage);
+ cp_demangled_name_parse_free (info);
return ret;
}
(optionally) a return type. Return the name of the function without
parameters or return type, or NULL if we can not parse the name. */
-static char *
-remove_params (const char *demangled_name)
+char *
+cp_remove_params (const char *demangled_name)
{
int done = 0;
struct demangle_component *ret_comp;
- void *storage;
+ struct demangle_parse_info *info;
char *ret = NULL;
if (demangled_name == NULL)
return NULL;
- ret_comp = cp_demangled_name_to_comp (demangled_name, &storage, 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)
{
if (ret_comp->type == DEMANGLE_COMPONENT_TYPED_NAME)
ret = cp_comp_to_string (d_left (ret_comp), 10);
- xfree (storage);
+ cp_demangled_name_parse_free (info);
return ret;
}
case 'o':
/* Operator names can screw up the recursion. */
if (operator_possible
- && strncmp (name + index, "operator", LENGTH_OF_OPERATOR) == 0)
+ && strncmp (name + index, "operator",
+ LENGTH_OF_OPERATOR) == 0)
{
index += LENGTH_OF_OPERATOR;
- while (isspace(name[index]))
+ while (ISSPACE(name[index]))
++index;
switch (name[index])
{
/* 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. */
+ completion list. */
static void
-overload_list_add_symbol (struct symbol *sym, const char *oload_name)
+overload_list_add_symbol (struct symbol *sym,
+ const char *oload_name)
{
int newsize;
int i;
char *sym_name;
- /* If there is no type information, we can't do anything, so skip */
+ /* 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. */
+ /* 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 = remove_params (SYMBOL_NATURAL_NAME (sym));
+ sym_name = cp_remove_params (SYMBOL_NATURAL_NAME (sym));
if (!sym_name)
return;
xfree (sym_name);
- /* We have a match for an overload instance, so add SYM to the current list
- * of overload instances */
+ /* 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 = (struct symbol **)
+ xrealloc ((char *) sym_return_val, newsize);
}
sym_return_val[sym_return_val_index++] = sym;
sym_return_val[sym_return_val_index] = NULL;
const char *namespace)
{
struct cleanup *old_cleanups;
+ const char *name;
sym_return_val_size = 100;
sym_return_val_index = 0;
make_symbol_overload_list_using (func_name, namespace);
+ if (namespace[0] == '\0')
+ name = func_name;
+ else
+ {
+ char *concatenated_name
+ = alloca (strlen (namespace) + 2 + strlen (func_name) + 1);
+ strcpy (concatenated_name, 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;
+
+ for (sym = block_iter_name_first (block, name, &iter);
+ sym != NULL;
+ sym = block_iter_name_next (name, &iter))
+ 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 *namespace)
+{
+ const char *name;
+ const struct block *block = NULL;
+
+ if (namespace[0] == '\0')
+ name = func_name;
+ else
+ {
+ char *concatenated_name
+ = alloca (strlen (namespace) + 2 + strlen (func_name) + 1);
+
+ strcpy (concatenated_name, 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 *namespace;
+ const char *type_name;
+ int i, prefix_len;
+
+ while (TYPE_CODE (type) == TYPE_CODE_PTR
+ || TYPE_CODE (type) == TYPE_CODE_REF
+ || 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)
+ {
+ namespace = alloca (prefix_len + 1);
+ strncpy (namespace, type_name, prefix_len);
+ namespace[prefix_len] = '\0';
+
+ make_symbol_overload_list_namespace (func_name, namespace);
+ }
+
+ /* Check public base type */
+ if (TYPE_CODE (type) == TYPE_CODE_CLASS)
+ 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;
+}
+
+/* Used for cleanups to reset the "searched" flag in case of an
+ error. */
+
+static void
+reset_directive_searched (void *data)
+{
+ struct using_direct *direct = data;
+ direct->searched = 0;
+}
+
/* 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_using (const char *func_name,
const char *namespace)
{
- const struct using_direct *current;
+ 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 (current = block_using (get_selected_block (0));
- current != NULL;
- current = current->next)
- {
- if (strcmp (namespace, current->outer) == 0)
- {
- make_symbol_overload_list_using (func_name,
- current->inner);
- }
- }
+ 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 (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);
+
+ current->searched = 0;
+ discard_cleanups (old_chain);
+ }
+ }
/* Now, add names for this namespace. */
-
- if (namespace[0] == '\0')
- {
- make_symbol_overload_list_qualified (func_name);
- }
- else
- {
- char *concatenated_name
- = alloca (strlen (namespace) + 2 + strlen (func_name) + 1);
- strcpy (concatenated_name, namespace);
- strcat (concatenated_name, "::");
- strcat (concatenated_name, func_name);
- make_symbol_overload_list_qualified (concatenated_name);
- }
+ make_symbol_overload_list_namespace (func_name, namespace);
}
/* This does the bulk of the work of finding overloaded symbols.
static void
make_symbol_overload_list_qualified (const char *func_name)
{
- 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. */
+ /* Look through the partial symtabs for all symbols which begin by
+ matching FUNC_NAME. Make sure we read that symbol table in. */
- read_in_psymtabs (func_name);
+ 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))
- {
- dict = BLOCK_DICT (b);
-
- for (sym = dict_iter_name_first (dict, func_name, &iter);
- sym;
- sym = dict_iter_name_next (func_name, &iter))
- {
- overload_list_add_symbol (sym, func_name);
- }
- }
+ make_symbol_overload_list_block (func_name, b);
surrounding_static_block = block_static_block (get_selected_block (0));
{
QUIT;
b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK);
- dict = BLOCK_DICT (b);
-
- for (sym = dict_iter_name_first (dict, func_name, &iter);
- sym;
- sym = dict_iter_name_next (func_name, &iter))
- {
- overload_list_add_symbol (sym, func_name);
- }
+ make_symbol_overload_list_block (func_name, b);
}
ALL_PRIMARY_SYMTABS (objfile, s)
/* Don't do this block twice. */
if (b == surrounding_static_block)
continue;
- dict = BLOCK_DICT (b);
-
- for (sym = dict_iter_name_first (dict, func_name, &iter);
- sym;
- sym = dict_iter_name_next (func_name, &iter))
- {
- overload_list_add_symbol (sym, func_name);
- }
+ make_symbol_overload_list_block (func_name, b);
}
}
-/* Look through the partial symtabs for all symbols which begin
- by matching FUNC_NAME. Make sure we read that symbol table in. */
-
-static void
-read_in_psymtabs (const char *func_name)
-{
- struct partial_symtab *ps;
- struct objfile *objfile;
-
- ALL_PSYMTABS (objfile, ps)
- {
- if (ps->readin)
- continue;
-
- if ((lookup_partial_symbol (ps, func_name, NULL, 1, VAR_DOMAIN)
- != NULL)
- || (lookup_partial_symbol (ps, func_name, NULL, 0, VAR_DOMAIN)
- != NULL))
- psymtab_to_symtab (ps);
- }
-}
-
-/* Lookup the rtti type for a class name. */
+/* 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;
- rtti_sym = lookup_symbol (name, block, STRUCT_DOMAIN, NULL, NULL);
+ rtti_sym = lookup_symbol (name, block, STRUCT_DOMAIN, NULL);
if (rtti_sym == NULL)
{
return rtti_type;
}
+/* A wrapper for bfd_demangle. */
+
+char *
+gdb_demangle (const char *name, int options)
+{
+ return bfd_demangle (NULL, name, options);
+}
+
/* Don't allow just "maintenance cplus". */
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);
+ 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);
}
/* This is a front end for cp_find_first_component, for unit testing.
static void
first_component_command (char *arg, int from_tty)
{
- int len = cp_find_first_component (arg);
- char *prefix = alloca (len + 1);
+ int len;
+ char *prefix;
+
+ if (!arg)
+ return;
+
+ len = cp_find_first_component (arg);
+ prefix = alloca (len + 1);
memcpy (prefix, arg, len);
prefix[len] = '\0';
extern initialize_file_ftype _initialize_cp_support; /* -Wmissing-prototypes */
+
+/* Implement "info vtbl". */
+
+static void
+info_vtbl_command (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,
+ 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."));
}