diff --git a/gdb/cp-name-parser.y b/gdb/cp-name-parser.y index f745a31..f7060fa 100644 --- a/gdb/cp-name-parser.y +++ b/gdb/cp-name-parser.y @@ -1979,6 +1979,27 @@ cp_demangled_name_parse_free (struct demangle_parse_info *parse_info) free (parse_info); } +/* Merge the two parse trees given by DEST and SRC. The parse tree + in SRC is attached to DEST at the node represented by TARGET. + SRC is then freed. */ + +void +cp_merge_demangle_parse_infos (struct demangle_parse_info *dest, + struct demangle_component *target, + struct demangle_parse_info *src) + +{ + struct demangle_info *di; + + memcpy (target, src->tree, sizeof (struct demangle_component)); + di = dest->info; + while (di->next != NULL) + di = di->next; + di->next = src->info; + src->info = NULL; + cp_demangled_name_parse_free (src); +} + /* A cleanup wrapper for cp_demangled_name_parse_free. */ static void diff --git a/gdb/cp-support.c b/gdb/cp-support.c index b67dedc..fc94353 100644 --- a/gdb/cp-support.c +++ b/gdb/cp-support.c @@ -86,6 +86,17 @@ static const char *operator_tokens[] = /* new[] and delete[] require special whitespace handling */ }; +/* A vector used to define a free list for typedef replacement + (replace_typedefs/inspect_type). See cp_canonicalize_string_no_typdefs + and inspect_type for more information. */ +typedef char *namep; +DEF_VEC_P (namep); + +static void +replace_typedefs (struct demangle_parse_info *info, + struct demangle_component *ret_comp, + VEC (namep) *free_list); + /* Return 1 if STRING is clearly already in canonical form. This function is conservative; things which it does not recognize are assumed to be non-canonical, and the parser will sort them out @@ -117,6 +128,182 @@ cp_already_canonical (const char *string) return 0; } +/* Inspect the given RET_COMP for its type. If it is a typedef, + replace the node with the typedef's tree, storing any memory allocations + on the FREE_LIST. */ + +static void +inspect_type (struct demangle_parse_info *info, + struct demangle_component *ret_comp, + VEC (namep) *free_list) +{ + 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'; + sym = lookup_symbol (name, 0, VAR_DOMAIN, 0); + if (sym != NULL) + { + struct type *type = SYMBOL_TYPE (sym); + + /* If the type is a typedef, replace it. */ + if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF) + { + struct demangle_parse_info *i; + struct ui_file *buf = mem_fileopen (); + struct cleanup *cleanup = make_cleanup_ui_file_delete (buf); + + CHECK_TYPEDEF (type); + type_print (type, "", buf, -1); + name = ui_file_xstrdup (buf, NULL); + VEC_safe_push (namep, free_list, name); + do_cleanups (cleanup); + + /* 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. */ + replace_typedefs (info, ret_comp, free_list); + } + 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) + { + xfree (name); + name = canon; + } + + ret_comp->u.s_name.s = name; + ret_comp->u.s_name.len = strlen (name); + } + } + } +} + +/* Walk the parse tree given by RET_COMP, replacing any typedefs with + their basic types. Any required memory allocations are added + to the FREE_LIST, which must be free'd by a caller. */ + +static void +replace_typedefs (struct demangle_parse_info *info, + struct demangle_component *ret_comp, + VEC (namep) *free_list) +{ + if (ret_comp) + { + switch (ret_comp->type) + { + case DEMANGLE_COMPONENT_ARGLIST: + /* "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. */ + 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)); + } + + replace_typedefs (info, d_left (ret_comp), free_list); + replace_typedefs (info, d_right (ret_comp), free_list); + break; + + case DEMANGLE_COMPONENT_NAME: + inspect_type (info, ret_comp, free_list); + break; + + case DEMANGLE_COMPONENT_FUNCTION_TYPE: + case DEMANGLE_COMPONENT_LOCAL_NAME: + case DEMANGLE_COMPONENT_TYPED_NAME: + case DEMANGLE_COMPONENT_CTOR: + case DEMANGLE_COMPONENT_ARRAY_TYPE: + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + replace_typedefs (info, d_right (ret_comp), free_list); + break; + + case DEMANGLE_COMPONENT_POINTER: + replace_typedefs (info, d_left (ret_comp), free_list); + 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. */ + +char * +cp_canonicalize_string_no_typedefs (const char *string) +{ + char *ret; + unsigned int estimated_len; + struct demangle_parse_info *info; + VEC (namep) *free_list; + + ret = NULL; + free_list = VEC_alloc (namep, 10); + 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, free_list); + + /* 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); + + /* Free any memory allocated during typedef replacement. */ + if (!VEC_empty (namep, free_list)) + { + int i; + char *iter; + + for (i = 0; VEC_iterate (namep, free_list, i, iter); ++i) + xfree (iter); + } + + /* Free the vector used for the free list. */ + VEC_free (namep, free_list); + + /* 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; +} + /* 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. */ diff --git a/gdb/cp-support.h b/gdb/cp-support.h index 12bb6cd..ba2e2d2 100644 --- a/gdb/cp-support.h +++ b/gdb/cp-support.h @@ -110,6 +110,8 @@ struct using_direct extern char *cp_canonicalize_string (const char *string); +extern char *cp_canonicalize_string_no_typedefs (const char *string); + extern char *cp_class_name_from_physname (const char *physname); extern char *method_name_from_physname (const char *physname); @@ -196,6 +198,9 @@ extern char *cp_comp_to_string (struct demangle_component *result, extern void cp_demangled_name_parse_free (struct demangle_parse_info *); extern struct cleanup *make_cleanup_cp_demangled_name_parse_free (struct demangle_parse_info *); +extern void cp_merge_demangle_parse_infos (struct demangle_parse_info *, + struct demangle_component *, + struct demangle_parse_info *); /* The list of "maint cplus" commands. */ diff --git a/gdb/linespec.c b/gdb/linespec.c index 94bb86f..a85c3d0 100644 --- a/gdb/linespec.c +++ b/gdb/linespec.c @@ -222,7 +222,7 @@ find_methods (struct type *t, char *name, enum language language, /* NAME is typed by the user: it needs to be canonicalized before passing to lookup_symbol. */ - canon = cp_canonicalize_string (name); + canon = cp_canonicalize_string_no_typedefs (name); if (canon != NULL) { name = canon; @@ -1315,7 +1315,7 @@ decode_compound (char **argptr, int funfirstline, char *the_real_saved_arg, char *p) { struct symtabs_and_lines values; - char *p2; + char *p2, *name; char *saved_arg2 = *argptr; char *temp_end; struct symbol *sym; @@ -1324,6 +1324,7 @@ decode_compound (char **argptr, int funfirstline, struct type *t; char *saved_java_argptr = NULL; char *saved_arg; + struct cleanup *cleanup; /* If the user specified any completer quote characters in the input, strip them. They are superfluous. */ @@ -1586,7 +1587,21 @@ decode_compound (char **argptr, int funfirstline, *argptr = (*p == '\'') ? p + 1 : p; /* Look up entire name. */ - sym = lookup_symbol (copy, get_selected_block (0), VAR_DOMAIN, 0); + name = copy; + + cleanup = make_cleanup (null_cleanup, NULL); + if (current_language->la_language == language_cplus) + { + char *canon = cp_canonicalize_string_no_typedefs (copy); + if (canon != NULL) + { + name = canon; + make_cleanup (xfree, name); + } + } + + sym = lookup_symbol (name, get_selected_block (0), VAR_DOMAIN, 0); + do_cleanups (cleanup); if (sym) return symbol_found (funfirstline, canonical, copy, sym, NULL, NULL); else @@ -1727,7 +1742,7 @@ find_method (int funfirstline, struct linespec_result *canonical, strcpy (name, SYMBOL_NATURAL_NAME (sym_class)); strcat (name, "::"); strcat (name, copy); - canon = cp_canonicalize_string (name); + canon = cp_canonicalize_string_no_typedefs (name); if (canon != NULL) { xfree (name); @@ -2069,15 +2084,31 @@ decode_variable (char *copy, int funfirstline, struct linespec_result *canonical, struct symtab *file_symtab) { + char *name; struct symbol *sym; + struct cleanup *cleanup; struct minimal_symbol *msymbol; - sym = lookup_symbol (copy, + name = copy; + cleanup = make_cleanup (null_cleanup, NULL); + if (current_language->la_language == language_cplus) + { + char *canon = cp_canonicalize_string_no_typedefs (copy); + + if (canon != NULL) + { + name = canon; + make_cleanup (xfree, name); + } + } + + sym = lookup_symbol (name, (file_symtab ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (file_symtab), STATIC_BLOCK) : get_selected_block (0)), VAR_DOMAIN, 0); + do_cleanups (cleanup); if (sym != NULL) return symbol_found (funfirstline, canonical, copy, sym, file_symtab, NULL);