[cplus] Use the parser in cp-support.c

Daniel Jacobowitz
2004-01-04T22:42:21Z

There are a whole lot of reasonably solid functions in cp-support.c which
attempt to parse demangled names. Now, we have a demangled name parser, so
let's use it.

This patch is a net increase in code, but a very small net decrease in
complexity. I plan to treat the other ad-hoc parsers similarly. This will,
very distantly eventually, bring about improvements in the way we treat
templated functions; GDB is woefully unprepared for the fact that the
mangling will include a return type. We can print their names in
backtraces, but not breakpoint on them (without using rbreak). We also
couldn't do overload resolution based on them even if we'd solved the first
problem of being able to enter their names.

Picking the function name out of a mangled name which does not include the
return type is not too hard. We do that already in several places using
ad-hoc scanners. However, reliably picking the function and the argument
list out of a mangled name which _does_ includes the return type is much
more difficult; consider:

int (*foo(bar))(baz)

Function foo takes a bar and returns an int (*) (baz) thanks to the wonders
of C declarator syntax. This is the sort of problem the parser was designed
for.

--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer

2003-01-04 Daniel Jacobowitz <drow@mvista.com>

* Makefile.in (cp_names_h): Remove.
(cp_demangle_h): New.
(cp-names.tab.o, cp-names-main.tab.o): Use $(cp_demangle_h) and
remove $(cp_names_h).
(cp-support.o): Use $(cp_demangle_h).
* cp-names.y: Don't include cp-names.h.
(cp_comp_to_string): Export.
(cp_canonicalize_string): Move to cp-support.c.
(demangled_name_to_comp, mangled_name_to_comp): New functions.
* cp-support.c: Include "cp-demangle.h".
(cp_canonicalize_string): New function, moved from cp-names.y and
updated.
(class_name_from_physname, method_name_from_physname): Rewritten.
(find_last_component): Removed.
* cp-support.h: Add new opaque types and prototypes.
* dwarf2read.c: Don't include cp-names.h.
* cp-names.h: Remove file.

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.268.2.9
diff -u -p -r1.268.2.9 Makefile.in
--- Makefile.in 4 Jan 2004 19:10:45 -0000 1.268.2.9
+++ Makefile.in 4 Jan 2004 22:28:42 -0000
@@ -579,6 +579,7 @@ coff_sym_h = $(INCLUDE_DIR)/coff/sym.h
coff_symconst_h = $(INCLUDE_DIR)/coff/symconst.h
coff_ecoff_h = $(INCLUDE_DIR)/coff/ecoff.h
coff_internal_h = $(INCLUDE_DIR)/coff/internal.h
+cp_demangle_h = $(INCLUDE_DIR)/cp-demangle.h
dis_asm_h = $(INCLUDE_DIR)/dis-asm.h $(bfd_h)
elf_reloc_macros_h = $(INCLUDE_DIR)/elf/reloc-macros.h
elf_sh_h = $(INCLUDE_DIR)/elf/sh.h
@@ -654,7 +655,6 @@ command_h = command.h
complaints_h = complaints.h
completer_h = completer.h
cp_abi_h = cp-abi.h
-cp_names_h = cp-names.h
cp_support_h = cp-support.h $(symtab_h)
dcache_h = dcache.h
defs_h = defs.h $(config_h) $(ansidecl_h) $(gdb_locale_h) $(gdb_signals_h) \
@@ -1439,11 +1439,9 @@ c-exp.tab.c: c-exp.y
-rm c-exp.tmp
mv c-exp.new ./c-exp.tab.c

-cp-names.tab.o: cp-names.tab.c $(safe_ctype_h) $(cp_names_h) \
- $(srcdir)/../include/cp-demangle.h
+cp-names.tab.o: cp-names.tab.c $(safe_ctype_h) $(cp_demangle_h)

-cp-names-main.tab.o: cp-names.tab.c $(safe_ctype_h) $(cp_names_h) \
- $(srcdir)/../include/cp-demangle.h
+cp-names-main.tab.o: cp-names.tab.c $(safe_ctype_h) $(cp_demangle_h)
$(CC) -c $(INTERNAL_CFLAGS) -DTEST_CPNAMES \
-o cp-names-main.tab.o cp-names.tab.c
test-cpnames: cp-names-main.tab.o $(LIBIBERTY)
@@ -1708,7 +1706,8 @@ cp-namespace.o: cp-namespace.c $(defs_h)
$(gdbtypes_h) $(dictionary_h) $(command_h)
cp-support.o: cp-support.c $(defs_h) $(cp_support_h) $(gdb_string_h) \
$(demangle_h) $(gdb_assert_h) $(gdbcmd_h) $(dictionary_h) \
- $(objfiles_h) $(frame_h) $(symtab_h) $(block_h) $(complaints_h)
+ $(objfiles_h) $(frame_h) $(symtab_h) $(block_h) $(complaints_h) \
+ $(cp_demangle_h)
cpu32bug-rom.o: cpu32bug-rom.c $(defs_h) $(gdbcore_h) $(target_h) \
$(monitor_h) $(serial_h) $(regcache_h) $(m68k_tdep_h)
cp-valprint.o: cp-valprint.c $(defs_h) $(gdb_obstack_h) $(symtab_h) \
Index: cp-names.y
===================================================================
RCS file: /cvs/src/src/gdb/Attic/cp-names.y,v
retrieving revision 1.1.2.16
diff -u -p -r1.1.2.16 cp-names.y
--- cp-names.y 4 Jan 2004 19:10:46 -0000 1.1.2.16
+++ cp-names.y 4 Jan 2004 22:28:42 -0000
@@ -43,8 +43,6 @@ Foundation, Inc., 59 Temple Place - Suit
#define IN_GDB
#include "cp-demangle.h"

-#include "cp-names.h"
-
static const char *lexptr, *prev_lexptr;

static struct d_comp *d_qualify (struct d_comp *, int, int);
@@ -2005,7 +2003,7 @@ symbol_end (const char *lexptr)
return p;
}

-static char *
+char *
cp_comp_to_string (struct d_comp *result, int estimated_len)
{
char *str, *prefix = NULL, *buf;
@@ -2036,26 +2034,57 @@ cp_comp_to_string (struct d_comp *result
return (buf);
}

-/* Return the canonicalized form of STRING, or NULL if STRING can not be
- parsed. */
+/* Convert a demangled name to a d_comp tree. *DI_P is set to the
+ struct d_info that should be freed when finished with the tree. */

-char *
-cp_canonicalize_string (const char *string)
+struct d_comp *
+demangled_name_to_comp (const char *demangled_name, struct d_info **di_p)
{
- int len = strlen (string);
- char *ret;
+ int len = strlen (demangled_name);

len = len + len / 8;
+ lexptr = demangled_name;

- lexptr = string;
di = cp_v3_d_init_info_alloc (NULL, DMGL_PARAMS | DMGL_ANSI, len);
+
if (yyparse () || result == NULL)
- return NULL;
+ {
+ cp_v3_d_free_info (di);
+ return NULL;
+ }

- ret = cp_comp_to_string (result, len);
+ *di_p = di;
+ return result;
+}

- cp_v3_d_free_info (di);
+/* Convert a mangled name to a d_comp tree. *DI_P is set to the
+ struct d_info 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. OPTIONS will be passed to the demangler.
+
+ This could be done much more efficiently for v3 mangled names by exposing
+ d_demangle from the demangler. */
+
+struct d_comp *
+mangled_name_to_comp (const char *mangled_name, int options,
+ struct d_info **di_p, char **demangled_p)
+{
+ char *demangled_name = cplus_demangle (mangled_name, options);
+ int len;
+ struct d_comp *ret;
+
+ if (demangled_name == NULL)
+ return NULL;
+
+ ret = demangled_name_to_comp (demangled_name, di_p);
+
+ if (ret == NULL)
+ {
+ free (demangled_name);
+ return NULL;
+ }

+ *demangled_p = demangled_name;
return ret;
}

Index: cp-support.c
===================================================================
RCS file: /cvs/src/src/gdb/cp-support.c,v
retrieving revision 1.1.6.4
diff -u -p -r1.1.6.4 cp-support.c
--- cp-support.c 20 Dec 2003 18:16:48 -0000 1.1.6.4
+++ cp-support.c 4 Jan 2004 22:28:42 -0000
@@ -1,5 +1,5 @@
/* Helper routines for C++ support in GDB.
- Copyright 2002, 2003 Free Software Foundation, Inc.
+ Copyright 2002, 2003, 2004 Free Software Foundation, Inc.

Contributed by MontaVista Software.

@@ -35,6 +35,9 @@
#include "complaints.h"
#include "gdbtypes.h"

+#define IN_GDB
+#include "cp-demangle.h"
+
/* Functions related to demangled name parsing. */

static const char *find_last_component (const char *name);
@@ -63,78 +66,31 @@ struct cmd_list_element *maint_cplus_cmd
static void maint_cplus_command (char *arg, int from_tty);
static void first_component_command (char *arg, int from_tty);

-/* 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? */
+/* Return the canonicalized form of STRING, or NULL if STRING can not be
+ parsed. */

-/* Find the last component of the demangled C++ name NAME. NAME
- must be a method name including arguments, in order to correctly
- locate the last component.
+/* FIXME: Should we also return NULL for things that trivially do not require
+ any change? i.e. alphanumeric strings. */

- This function return a pointer to the first colon before the
- last component, or NULL if the name had only one component. */
-
-static const char *
-find_last_component (const char *name)
+char *
+cp_canonicalize_string (const char *string)
{
- const char *p;
- int depth;
-
- /* Functions can have local classes, so we need to find the
- beginning of the last argument list, not the end of the first
- one. */
- p = name + strlen (name) - 1;
- while (p > name && *p != ')')
- p--;
-
- if (p == name)
- return NULL;
+ struct d_info *di;
+ struct d_comp *ret_comp;
+ char *ret;
+ int len = strlen (string);

- /* P now points at the `)' at the end of the argument list. Walk
- back to the beginning. */
- p--;
- depth = 1;
- while (p > name && depth > 0)
- {
- if (*p == '<' || *p == '(')
- depth--;
- else if (*p == '>' || *p == ')')
- depth++;
- p--;
- }
+ len = len + len / 8;

- if (p == name)
+ ret_comp = demangled_name_to_comp (string, &di);
+ if (ret_comp == NULL)
return NULL;

- while (p > name && *p != ':')
- p--;
+ ret = cp_comp_to_string (ret_comp, len);

- if (p == name || p == name + 1 || p[-1] != ':')
- return NULL;
+ cp_v3_d_free_info (di);

- return p - 1;
+ return ret;
}

/* Return the name of the class containing method PHYSNAME. */
@@ -142,22 +98,63 @@ find_last_component (const char *name)
char *
class_name_from_physname (const char *physname)
{
- char *ret = NULL;
- const char *end;
- int depth = 0;
- char *demangled_name = cplus_demangle (physname, DMGL_ANSI | DMGL_PARAMS);
+ struct d_info *di;
+ char *demangled_name, *ret;
+ struct d_comp *ret_comp, *prev_comp;
+ int done;

- if (demangled_name == NULL)
+ ret_comp = mangled_name_to_comp (physname, DMGL_ANSI, &di, &demangled_name);
+ if (ret_comp == NULL)
return NULL;

- end = find_last_component (demangled_name);
- if (end != NULL)
+ done = 0;
+ prev_comp = NULL;
+ while (!done)
+ switch (ret_comp->type)
+ {
+ case D_COMP_TYPED_NAME:
+ prev_comp = NULL;
+ ret_comp = d_right (ret_comp);
+ break;
+ case D_COMP_QUAL_NAME:
+ case D_COMP_LOCAL_NAME:
+ prev_comp = ret_comp;
+ ret_comp = d_right (ret_comp);
+ break;
+ case D_COMP_CONST:
+ case D_COMP_RESTRICT:
+ case D_COMP_VOLATILE:
+ case D_COMP_CONST_THIS:
+ case D_COMP_RESTRICT_THIS:
+ case D_COMP_VOLATILE_THIS:
+ case D_COMP_VENDOR_TYPE_QUAL:
+ prev_comp = NULL;
+ ret_comp = d_left (ret_comp);
+ break;
+ case D_COMP_NAME:
+ case D_COMP_TEMPLATE:
+ case D_COMP_CTOR:
+ case D_COMP_DTOR:
+ case D_COMP_OPERATOR:
+ case D_COMP_EXTENDED_OPERATOR:
+ done = 1;
+ break;
+ default:
+ done = 1;
+ prev_comp = NULL;
+ ret_comp = NULL;
+ break;
+ }
+
+ ret = NULL;
+ if (prev_comp != NULL)
{
- ret = xmalloc (end - demangled_name + 1);
- memcpy (ret, demangled_name, end - demangled_name);
- ret[end - demangled_name] = '\0';
+ *prev_comp = *d_left (prev_comp);
+ /* The ten is completely arbitrary; we don't have a good estimate. */
+ ret = cp_comp_to_string (prev_comp, 10);
}

+ cp_v3_d_free_info (di);
xfree (demangled_name);
return ret;
}
@@ -167,42 +164,83 @@ class_name_from_physname (const char *ph
char *
method_name_from_physname (const char *physname)
{
- char *ret = NULL;
- const char *end;
- int depth = 0;
- char *demangled_name = cplus_demangle (physname, DMGL_ANSI | DMGL_PARAMS);
+ struct d_info *di;
+ char *demangled_name, *ret;
+ struct d_comp *ret_comp;
+ int done;

- if (demangled_name == NULL)
+ ret_comp = mangled_name_to_comp (physname, DMGL_ANSI, &di, &demangled_name);
+ if (ret_comp == NULL)
return NULL;

- end = find_last_component (demangled_name);
- if (end != NULL)
- {
- char *args;
- int len;
-
- /* Skip "::". */
- end = end + 2;
-
- /* Find the argument list, if any. */
- args = strchr (end, '(');
- if (args == NULL)
- len = strlen (end + 2);
- else
- {
- args --;
- while (*args == ' ')
- args --;
- len = args - end + 1;
- }
- ret = xmalloc (len + 1);
- memcpy (ret, end, len);
- ret[len] = 0;
- }
+ done = 0;
+ while (!done)
+ switch (ret_comp->type)
+ {
+ case D_COMP_QUAL_NAME:
+ case D_COMP_LOCAL_NAME:
+ case D_COMP_TYPED_NAME:
+ ret_comp = d_right (ret_comp);
+ break;
+ case D_COMP_CONST:
+ case D_COMP_RESTRICT:
+ case D_COMP_VOLATILE:
+ case D_COMP_CONST_THIS:
+ case D_COMP_RESTRICT_THIS:
+ case D_COMP_VOLATILE_THIS:
+ case D_COMP_VENDOR_TYPE_QUAL:
+ ret_comp = d_left (ret_comp);
+ break;
+ case D_COMP_NAME:
+ case D_COMP_TEMPLATE:
+ case D_COMP_CTOR:
+ case D_COMP_DTOR:
+ case D_COMP_OPERATOR:
+ case D_COMP_EXTENDED_OPERATOR:
+ done = 1;
+ break;
+ default:
+ done = 1;
+ ret_comp = NULL;
+ break;
+ }
+
+ ret = NULL;
+ if (ret_comp != NULL)
+ /* The ten is completely arbitrary; we don't have a good estimate. */
+ ret = cp_comp_to_string (ret_comp, 10);

+ cp_v3_d_free_info (di);
xfree (demangled_name);
return ret;
}
+
+/* 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.
Index: cp-support.h
===================================================================
RCS file: /cvs/src/src/gdb/cp-support.h,v
retrieving revision 1.1.6.3
diff -u -p -r1.1.6.3 cp-support.h
--- cp-support.h 14 Dec 2003 20:27:10 -0000 1.1.6.3
+++ cp-support.h 4 Jan 2004 22:28:42 -0000
@@ -1,5 +1,5 @@
/* Helper routines for C++ support in GDB.
- Copyright 2002, 2003 Free Software Foundation, Inc.
+ Copyright 2002, 2003, 2004 Free Software Foundation, Inc.

Contributed by MontaVista Software.
Namespace support contributed by David Carlton.
@@ -35,6 +35,8 @@ struct obstack;
struct block;
struct objfile;
struct type;
+struct d_comp;
+struct d_info;

/* This struct is designed to store data from using directives. It
says that names from namespace INNER should be visible within
@@ -52,6 +54,8 @@ struct using_direct

/* Functions from cp-support.c. */

+extern char *cp_canonicalize_string (const char *string);
+
extern char *class_name_from_physname (const char *physname);

extern char *method_name_from_physname (const char *physname);
@@ -107,6 +111,18 @@ extern struct type *cp_lookup_nested_typ

extern void cp_check_possible_namespace_symbols (const char *name,
struct objfile *objfile);
+
+/* Functions from cp-names.y. */
+
+extern struct d_comp *demangled_name_to_comp (const char *demangled_name,
+ struct d_info **di_p);
+
+extern struct d_comp *mangled_name_to_comp (const char *mangled_name,
+ int options,
+ struct d_info **di_p,
+ char **demangled_p);
+
+extern char *cp_comp_to_string (struct d_comp *result, int estimated_len);

/* The list of "maint cplus" commands. */

Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.67.2.5
diff -u -p -r1.67.2.5 dwarf2read.c
--- dwarf2read.c 30 Dec 2003 21:01:20 -0000 1.67.2.5
+++ dwarf2read.c 4 Jan 2004 22:28:43 -0000
@@ -1,5 +1,5 @@
/* DWARF 2 debugging format support for GDB.
- Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
Free Software Foundation, Inc.

Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology,
@@ -44,7 +44,6 @@
#include "dwarf2expr.h"
#include "dwarf2loc.h"
#include "cp-support.h"
-#include "cp-names.h"

#include <fcntl.h>
#include "gdb_string.h"
Index: cp-names.h
===================================================================
RCS file: cp-names.h
diff -N cp-names.h
--- cp-names.h 24 Dec 2003 22:35:25 -0000 1.1.2.1
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,24 +0,0 @@
-/* YACC parser for C++ names, for GDB.
-
- Copyright 2003
- Free Software Foundation, Inc.
-
-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 2 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, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* Return the canonicalized form of STRING, or NULL if STRING can not be
- parsed. */
-char *cp_canonicalize_string (const char *string);