This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RFA: Correct field names for class methods


On Mon, Sep 09, 2002 at 07:30:27PM -0400, Elena Zannoni wrote:
> Daniel Jacobowitz writes:
>  > Right now, the "name" field of a method is not always reliable.  There's
>  > special-cased code all over the linespec, function calling, struct lookup,
>  > etc. code to handle this.  Among the problems:
>  > 
>  >   - v3 stabs emit __comp_ctor etc.
>  >   - v2 stabs emit constructors and destructors in the same fieldlist
>  >   - v2 stabs emit mangled operator names
>  > 
>  > This patch does not remove any of the special cases, but renders it
>  > all obsolete, to be cleaned up in a forthcoming patch.  This will greatly
>  > simplify the revised method printing code that I'm working on, a necessary
>  > cleanup as we move towards namespace support.  It pushes the stabs special
>  > casing back into stabs related code as much as practical.
>  > 
>  > Elena, this does a bit of its ugliness in read_member_functions, so I'd like
>  > your approval before I go ahead with it.
> 
> 
> See below. I have some questions and some general comments on the
> structure of the patch.
> 
>  > 
>  > Comments, anyone?
>  > 
>  > -- 
>  > Daniel Jacobowitz
>  > MontaVista Software                         Debian GNU/Linux Developer
>  > 
>  > 2002-08-26  Daniel Jacobowitz  <drow@mvista.com>
>  > 
>  > 	* gdbtypes.c (check_stub_method): Make static.
>  > 	(update_method_from_physname, check_stub_method_group)
>  > 	(find_last_component, class_name_from_physname)
>  > 	(method_name_from_physname): New functions.
>  > 	* gdbtypes.h: Update prototypes.
>  > 
>  > 	* stabsread.c: Include "cp-abi.h".
> 
> Makefile?

Oops, thank you.

> 
>  > 	(read_member_functions): Correct method names for operators
>  > 	and v3 constructors/destructors.  Separate v2 constructors and
>  > 	destructors.
>  > 
>  > 	* cp-valprint.c (cp_print_class_method): Call
>  > 	check_stub_method_group instead of check_stub_method.
>  > 	* p-valprint.c (pascal_object_print_class_method): Likewise.
>  > 	* valops.c (search_struct_method): Likewise.
>  > 	(find_method_list, value_struct_elt_for_reference): Likewise.
>  > 
>  > Index: cp-valprint.c
>  > ===================================================================
>  > RCS file: /cvs/src/src/gdb/cp-valprint.c,v
>  > retrieving revision 1.13
>  > diff -u -p -r1.13 cp-valprint.c
>  > --- cp-valprint.c	29 Jul 2002 22:55:26 -0000	1.13
>  > +++ cp-valprint.c	27 Aug 2002 02:02:55 -0000
>  > @@ -97,13 +97,12 @@ cp_print_class_method (char *valaddr,
>  >  	  f = TYPE_FN_FIELDLIST1 (domain, i);
>  >  	  len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
>  >  
>  > +	  check_stub_method_group (domain, i);
>  >  	  for (j = 0; j < len2; j++)
>  >  	    {
>  >  	      QUIT;
> 
> Did you mean to leave this QUIT?

No, it should probably go, for the same reasons as the others.

>  >  	      if (TYPE_FN_FIELD_VOFFSET (f, j) == offset)
>  >  		{
>  > -		  if (TYPE_FN_FIELD_STUB (f, j))
>  > -		    check_stub_method (domain, i, j);
>  >  		  kind = "virtual ";
>  >  		  goto common;
>  >  		}
>  > @@ -129,15 +128,11 @@ cp_print_class_method (char *valaddr,
>  >  	  f = TYPE_FN_FIELDLIST1 (domain, i);
>  >  	  len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
>  >  
>  > +	  check_stub_method_group (f, j);
>  >  	  for (j = 0; j < len2; j++)
>  >  	    {
>  > -	      QUIT;
>  > -	      if (TYPE_FN_FIELD_STUB (f, j))
>  > -		check_stub_method (domain, i, j);
>  >  	      if (STREQ (SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j)))
>  > -		{
>  > -		  goto common;
>  > -		}
>  > +		goto common;
>  >  	    }
>  >  	}
>  >      }
>  > Index: gdbtypes.c
>  > ===================================================================
>  > RCS file: /cvs/src/src/gdb/gdbtypes.c,v
>  > retrieving revision 1.56
>  > diff -u -p -r1.56 gdbtypes.c
>  > --- gdbtypes.c	20 Aug 2002 19:57:32 -0000	1.56
>  > +++ gdbtypes.c	27 Aug 2002 02:02:55 -0000
>  > @@ -1672,7 +1672,7 @@ safe_parse_type (char *p, int length)
>  >     which info used to be in the stab's but was removed to hack back
>  >     the space required for them.  */
>  >  
>  > -void
>  > +static void
>  >  check_stub_method (struct type *type, int method_id, int signature_id)
>  >  {
>  >    struct fn_field *f;
>  > @@ -1781,6 +1781,54 @@ check_stub_method (struct type *type, in
>  >    xfree (demangled_name);
>  >  }
>  >  
> 
> Could you add some comments about what this function does?
> Actually, since it is used only in stabsread.c, why not move it there?
> I think a lot of this c++ specific stuff really doesn't belong in gdbtypes.c.
> You can move all the new functions, except for check_stub_method_group to
> stabsread.c. They are called from there only.

update_method_name_from_physname?  OK - at first I thought I would need
it in more places but that doesn't seem to be true.  DWARF-2 has its
own quirks, but it always gets the method's _name_ right.  I'll move it
to stabsread.c and make it static.  That even lets me plug the memory
leak.

>  > +void
>  > +update_method_name_from_physname (char **old_name, char *physname)
>  > +{
>  > +  char *method_name;
>  > +
>  > +  method_name = method_name_from_physname (physname);
>  > +
>  > +  if (method_name == NULL)
>  > +    error ("bad physname %s\n", physname);
>  > +
>  > +  if (strcmp (*old_name, method_name) != 0)
>  > +    *old_name = method_name;
>  > +  else
>  > +    xfree (method_name);
>  > +}
>  > +
> 
> Could you add some comments here too?

Sure.

> 
>  > +void
>  > +check_stub_method_group (struct type *type, int method_id)
>  > +{


> Did you forget to post a piece of the patch? I don't see the function
> below being called anywhere.

My ulterior motives are leaking again!  I added
class_name_from_physname because it is the exact parallel to
method_name_from_physname, and because I will need it in future
patches.  I can hold it till later if you prefer, but I'd rather just
slip it in now.  It's a pretty obvious function.

>  > +/* Return the name of the class containing method PHYSNAME.  */
>  > +
>  > +char *
>  > +class_name_from_physname (const char *physname)
>  > +{


> Since you are at it, could you insert examples of mangled names,
> physnames, etc in the comment?

Sure.  I wrote up a big table for it and then I even fixed the bug the
table pointed out to me (needed a case to handle just destructors).

> 
> 
>  > +	  tmp_sublist = sublist;
>  > +	  while (tmp_sublist != NULL)
>  > +	    {
>  > +	      if (tmp_sublist->fn_field.is_stub)
>  > +		has_stub = 1;
>  > +	      if (tmp_sublist->fn_field.physname[0] == '_'
>  > +		  && tmp_sublist->fn_field.physname[1] == 'Z')
>  > +		is_v3 = 1;
>  > +
>  > +	      if (is_destructor_name (tmp_sublist->fn_field.physname))
>  > +		has_destructor++;
>  > +	      else
> 
>  > +		has_nondestructor++;
> 
> Dumb question, but, what is a nondestructor? Maybe a different variable
> name would be a bit more enlightening.

Anything that isn't a destructor.  I've changed it to has_other - is
that clearer?

>  > +
>  > +	      tmp_sublist = tmp_sublist->next;
>  > +	    }
>  > +
>  > +	  if (has_destructor && has_nondestructor)
> 
> 
> Comments needed, for the c++ challenged. What does it mean to have both
> a destructor and a nondestructor?

It's explained in the big comment up above; I've clarified the wording. 
Basically, what happens is... wait... let me paste the revised comment:

      The caveat: GCC 2.95.x (and earlier?) put constructors and
      destructors in the same method group.  We need to split this into
      two groups, because they should have different names.  So for
      each method group we check whether it contains both routines
      whose physname appears to be a destructor (the physnames for
      destructors are always provided, due to quirks in v2 mangling)
      and routines whose physname does not appear to be a destructor. 
      If so then we break up the list into two halves.  Even if the
      constructors and destructors aren't in the same group the
      destructor will still lack the leading tilde, so that also needs
      to be fixed.

> 
>  > +	    {
>  > +	      struct next_fnfieldlist *destr_fnlist;
>  > +	      struct next_fnfield *last_sublist;
>  > +
>  > +	      /* Create a new fn_fieldlist for the destructors.  */;
>  > +	      destr_fnlist = (struct next_fnfieldlist *)
>  > +		xmalloc (sizeof (struct next_fnfieldlist));
>  > +	      make_cleanup (xfree, destr_fnlist);
>  > +	      memset (destr_fnlist, 0, sizeof (struct next_fnfieldlist));
>  > +	      destr_fnlist->fn_fieldlist.name
>  > +		= obconcat (&objfile->type_obstack, "", "~",
>  > +			    new_fnlist->fn_fieldlist.name);
>  > +
>  > +	      destr_fnlist->fn_fieldlist.fn_fields = (struct fn_field *)
>  > +		obstack_alloc (&objfile->type_obstack,
>  > +			       sizeof (struct fn_field) * has_destructor);
>  > +	      memset (destr_fnlist->fn_fieldlist.fn_fields, 0,
>  > +		  sizeof (struct fn_field) * has_destructor);
>  > +	      tmp_sublist = sublist;
>  > +	      last_sublist = NULL;
> 
> 
>  > +	      i = 0;
> 
> I am confused. Why is i always 0? Or it isn't?

Oops!  It doesn't really matter, since there's always one destructor
(until we support in-charge/not-in-charge destructors eventually).  But
I've fixed that.  Should have been i++ below.

Thanks for all the comments; here's a revised version.

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

2002-09-10  Daniel Jacobowitz  <drow@mvista.com>

	* gdbtypes.c (check_stub_method): Make static.
	(check_stub_method_group, find_last_component)
	(class_name_from_physname, method_name_from_physname): New functions.
	* gdbtypes.h: Update prototypes.

	* stabsread.c: Include "cp-abi.h".
	(update_method_name_from_physname): New function.
	(read_member_functions): Correct method names for operators
	and v3 constructors/destructors.  Separate v2 constructors and
	destructors.
	* Makefile.in (stabsread.o): Update dependencies.

	* cp-valprint.c (cp_print_class_method): Call
	check_stub_method_group instead of check_stub_method.  Remove
	extraneous QUITs.
	* p-valprint.c (pascal_object_print_class_method): Likewise.
	* valops.c (search_struct_method): Likewise.
	(find_method_list, value_struct_elt_for_reference): Likewise.

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.257
diff -u -p -r1.257 Makefile.in
--- Makefile.in	2 Sep 2002 18:09:06 -0000	1.257
+++ Makefile.in	10 Sep 2002 16:35:15 -0000
@@ -2174,7 +2174,7 @@ stabsread.o: stabsread.c $(defs_h) $(gdb
 	$(symtab_h) $(gdbtypes_h) $(expression_h) $(symfile_h) $(objfiles_h) \
 	$(aout_stab_gnu_h) $(libaout_h) $(aout_aout64_h) $(gdb_stabs_h) \
 	$(buildsym_h) $(complaints_h) $(demangle_h) $(language_h) \
-	$(doublest_h) $(stabsread_h)
+	$(doublest_h) $(stabsread_h) $(cp_abi_h)
 stack.o: stack.c $(defs_h) $(gdb_string_h) $(value_h) $(symtab_h) \
 	$(gdbtypes_h) $(expression_h) $(language_h) $(frame_h) $(gdbcmd_h) \
 	$(gdbcore_h) $(target_h) $(breakpoint_h) $(demangle_h) $(inferior_h) \
Index: cp-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/cp-valprint.c,v
retrieving revision 1.13
diff -u -p -r1.13 cp-valprint.c
--- cp-valprint.c	29 Jul 2002 22:55:26 -0000	1.13
+++ cp-valprint.c	10 Sep 2002 16:35:15 -0000
@@ -97,13 +97,11 @@ cp_print_class_method (char *valaddr,
 	  f = TYPE_FN_FIELDLIST1 (domain, i);
 	  len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
 
+	  check_stub_method_group (domain, i);
 	  for (j = 0; j < len2; j++)
 	    {
-	      QUIT;
 	      if (TYPE_FN_FIELD_VOFFSET (f, j) == offset)
 		{
-		  if (TYPE_FN_FIELD_STUB (f, j))
-		    check_stub_method (domain, i, j);
 		  kind = "virtual ";
 		  goto common;
 		}
@@ -129,15 +127,11 @@ cp_print_class_method (char *valaddr,
 	  f = TYPE_FN_FIELDLIST1 (domain, i);
 	  len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
 
+	  check_stub_method_group (f, j);
 	  for (j = 0; j < len2; j++)
 	    {
-	      QUIT;
-	      if (TYPE_FN_FIELD_STUB (f, j))
-		check_stub_method (domain, i, j);
 	      if (STREQ (SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j)))
-		{
-		  goto common;
-		}
+		goto common;
 	    }
 	}
     }
Index: gdbtypes.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbtypes.c,v
retrieving revision 1.56
diff -u -p -r1.56 gdbtypes.c
--- gdbtypes.c	20 Aug 2002 19:57:32 -0000	1.56
+++ gdbtypes.c	10 Sep 2002 16:35:16 -0000
@@ -1672,7 +1672,7 @@ safe_parse_type (char *p, int length)
    which info used to be in the stab's but was removed to hack back
    the space required for them.  */
 
-void
+static void
 check_stub_method (struct type *type, int method_id, int signature_id)
 {
   struct fn_field *f;
@@ -1781,6 +1781,49 @@ check_stub_method (struct type *type, in
   xfree (demangled_name);
 }
 
+/* This is the external interface to check_stub_method, above.  This function
+   unstubs all of the signatures for TYPE's METHOD_ID method name.  After
+   calling this function TYPE_FN_FIELD_STUB will be cleared for each signature
+   and TYPE_FN_FIELDLIST_NAME will be correct.
+
+   This function unfortunately can not die until stabs do.  */
+
+void
+check_stub_method_group (struct type *type, int method_id)
+{
+  int len = TYPE_FN_FIELDLIST_LENGTH (type, method_id);
+  struct fn_field *f = TYPE_FN_FIELDLIST1 (type, method_id);
+  int j, found_stub;
+
+  for (j = 0; j < len; j++)
+    if (TYPE_FN_FIELD_STUB (f, j))
+      {
+	found_stub = 1;
+	check_stub_method (type, method_id, j);
+      }
+
+  /* GNU v3 methods with incorrect names were corrected when we read in
+     type information, because it was cheaper to do it then.  The only GNU v2
+     methods with incorrect method names are operators and destructors;
+     destructors were also corrected when we read in type information.
+
+     Therefore the only thing we need to handle here are v2 operator
+     names.  */
+  if (found_stub && strncmp (TYPE_FN_FIELD_PHYSNAME (f, 0), "_Z", 2) != 0)
+    {
+      int ret;
+      char dem_opname[256];
+
+      ret = cplus_demangle_opname (TYPE_FN_FIELDLIST_NAME (type, method_id),
+				   dem_opname, DMGL_ANSI);
+      if (!ret)
+	ret = cplus_demangle_opname (TYPE_FN_FIELDLIST_NAME (type, method_id),
+				     dem_opname, 0);
+      if (ret)
+	TYPE_FN_FIELDLIST_NAME (type, method_id) = xstrdup (dem_opname);
+    }
+}
+
 const struct cplus_struct_type cplus_struct_default;
 
 void
@@ -3435,6 +3478,120 @@ build_gdbtypes (void)
 	       "__bfd_vma", (struct objfile *) NULL);
 }
 
+/* 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.
+
+   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)
+{
+  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;
+
+  /* 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--;
+    }
+
+  if (p == name)
+    return NULL;
+
+  while (p > name && *p != ':')
+    p--;
+
+  if (p == name || p == name + 1 || p[-1] != ':')
+    return NULL;
+
+  return p - 1;
+}
+
+/* Return the name of the class containing method PHYSNAME.  */
+
+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);
+
+  if (demangled_name == NULL)
+    return NULL;
+
+  end = find_last_component (demangled_name);
+  if (end != NULL)
+    {
+      ret = xmalloc (end - demangled_name + 1);
+      memcpy (ret, demangled_name, end - demangled_name);
+      ret[end - demangled_name] = '\0';
+    }
+
+  xfree (demangled_name);
+  return ret;
+}
+
+/* Return the name of the method whose linkage name is PHYSNAME.  */
+
+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);
+
+  if (demangled_name == 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;
+    }
+
+  xfree (demangled_name);
+  return ret;
+}
 
 extern void _initialize_gdbtypes (void);
 void
Index: gdbtypes.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbtypes.h,v
retrieving revision 1.35
diff -u -p -r1.35 gdbtypes.h
--- gdbtypes.h	10 Aug 2002 05:12:40 -0000	1.35
+++ gdbtypes.h	10 Sep 2002 16:35:16 -0000
@@ -1124,11 +1124,15 @@ extern struct type *check_typedef (struc
 
 #define CHECK_TYPEDEF(TYPE) (TYPE) = check_typedef (TYPE)
 
-extern void check_stub_method (struct type *, int, int);
+extern void check_stub_method_group (struct type *, int);
 
 extern struct type *lookup_primitive_typename (char *);
 
 extern char *gdb_mangle_name (struct type *, int, int);
+
+extern char *class_name_from_physname (const char *physname);
+
+extern char *method_name_from_physname (const char *physname);
 
 extern struct type *builtin_type (char **);
 
Index: p-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/p-valprint.c,v
retrieving revision 1.13
diff -u -p -r1.13 p-valprint.c
--- p-valprint.c	19 Aug 2002 13:12:09 -0000	1.13
+++ p-valprint.c	10 Sep 2002 16:35:16 -0000
@@ -620,13 +620,11 @@ pascal_object_print_class_method (char *
 	  f = TYPE_FN_FIELDLIST1 (domain, i);
 	  len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
 
+	  check_stub_method_group (domain, i);
 	  for (j = 0; j < len2; j++)
 	    {
-	      QUIT;
 	      if (TYPE_FN_FIELD_VOFFSET (f, j) == offset)
 		{
-		  if (TYPE_FN_FIELD_STUB (f, j))
-		    check_stub_method (domain, i, j);
 		  kind = "virtual ";
 		  goto common;
 		}
@@ -646,15 +644,11 @@ pascal_object_print_class_method (char *
 	  f = TYPE_FN_FIELDLIST1 (domain, i);
 	  len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
 
+	  check_stub_method_group (domain, i);
 	  for (j = 0; j < len2; j++)
 	    {
-	      QUIT;
-	      if (TYPE_FN_FIELD_STUB (f, j))
-		check_stub_method (domain, i, j);
 	      if (STREQ (SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j)))
-		{
-		  goto common;
-		}
+		goto common;
 	    }
 	}
     }
Index: stabsread.c
===================================================================
RCS file: /cvs/src/src/gdb/stabsread.c,v
retrieving revision 1.38
diff -u -p -r1.38 stabsread.c
--- stabsread.c	1 Aug 2002 17:18:32 -0000	1.38
+++ stabsread.c	10 Sep 2002 16:35:17 -0000
@@ -44,6 +44,7 @@
 #include "demangle.h"
 #include "language.h"
 #include "doublest.h"
+#include "cp-abi.h"
 
 #include <ctype.h>
 
@@ -3080,6 +3081,27 @@ rs6000_builtin_type (int typenum)
 
 /* This page contains subroutines of read_type.  */
 
+/* Replace *OLD_NAME with the method name portion of PHYSNAME.  */
+
+static void
+update_method_name_from_physname (char **old_name, char *physname)
+{
+  char *method_name;
+
+  method_name = method_name_from_physname (physname);
+
+  if (method_name == NULL)
+    error ("bad physname %s\n", physname);
+
+  if (strcmp (*old_name, method_name) != 0)
+    {
+      xfree (*old_name);
+      *old_name = method_name;
+    }
+  else
+    xfree (method_name);
+}
+
 /* Read member function stabs info for C++ classes.  The form of each member
    function data is:
 
@@ -3377,6 +3399,164 @@ read_member_functions (struct field_info
 	}
       else
 	{
+	  int has_stub = 0;
+	  int has_destructor = 0, has_other = 0;
+	  int is_v3 = 0;
+	  struct next_fnfield *tmp_sublist;
+
+	  /* Various versions of GCC emit various mostly-useless
+	     strings in the name field for special member functions.
+
+	     For stub methods, we need to defer correcting the name
+	     until we are ready to unstub the method, because the current
+	     name string is used by gdb_mangle_name.  The only stub methods
+	     of concern here are GNU v2 operators; other methods have their
+	     names correct (see caveat below).
+
+	     For non-stub methods, in GNU v3, we have a complete physname.
+	     Therefore we can safely correct the name now.  This primarily
+	     affects constructors and destructors, whose name will be
+	     __comp_ctor or __comp_dtor instead of Foo or ~Foo.  Cast
+	     operators will also have incorrect names; for instance,
+	     "operator int" will be named "operator i" (i.e. the type is
+	     mangled).
+
+	     For non-stub methods in GNU v2, we have no easy way to
+	     know if we have a complete physname or not.  For most
+	     methods the result depends on the platform (if CPLUS_MARKER
+	     can be `$' or `.', it will use minimal debug information, or
+	     otherwise the full physname will be included).
+
+	     Rather than dealing with this, we take a different approach.
+	     For v3 mangled names, we can use the full physname; for v2,
+	     we use cplus_demangle_opname (which is actually v2 specific),
+	     because the only interesting names are all operators - once again
+	     barring the caveat below.  Skip this process if any method in the
+	     group is a stub, to prevent our fouling up the workings of
+	     gdb_mangle_name.
+
+	     The caveat: GCC 2.95.x (and earlier?) put constructors and
+	     destructors in the same method group.  We need to split this
+	     into two groups, because they should have different names.
+	     So for each method group we check whether it contains both
+	     routines whose physname appears to be a destructor (the physnames
+	     for and destructors are always provided, due to quirks in v2
+	     mangling) and routines whose physname does not appear to be a
+	     destructor.  If so then we break up the list into two halves.
+	     Even if the constructors and destructors aren't in the same group
+	     the destructor will still lack the leading tilde, so that also
+	     needs to be fixed.
+
+	     So, to summarize what we expect and handle here:
+
+	        Given         Given          Real         Real       Action
+	     method name     physname      physname   method name
+
+	     __opi            [none]     __opi__3Foo  operator int    opname
+	                                                           [now or later]
+	     Foo              _._3Foo       _._3Foo      ~Foo       separate and
+	                                                               rename
+	     operator i     _ZN3FoocviEv _ZN3FoocviEv operator int    demangle
+	     __comp_ctor  _ZN3FooC1ERKS_ _ZN3FooC1ERKS_   Foo         demangle
+	  */
+
+	  tmp_sublist = sublist;
+	  while (tmp_sublist != NULL)
+	    {
+	      if (tmp_sublist->fn_field.is_stub)
+		has_stub = 1;
+	      if (tmp_sublist->fn_field.physname[0] == '_'
+		  && tmp_sublist->fn_field.physname[1] == 'Z')
+		is_v3 = 1;
+
+	      if (is_destructor_name (tmp_sublist->fn_field.physname))
+		has_destructor++;
+	      else
+		has_other++;
+
+	      tmp_sublist = tmp_sublist->next;
+	    }
+
+	  if (has_destructor && has_other)
+	    {
+	      struct next_fnfieldlist *destr_fnlist;
+	      struct next_fnfield *last_sublist;
+
+	      /* Create a new fn_fieldlist for the destructors.  */
+
+	      destr_fnlist = (struct next_fnfieldlist *)
+		xmalloc (sizeof (struct next_fnfieldlist));
+	      make_cleanup (xfree, destr_fnlist);
+	      memset (destr_fnlist, 0, sizeof (struct next_fnfieldlist));
+	      destr_fnlist->fn_fieldlist.name
+		= obconcat (&objfile->type_obstack, "", "~",
+			    new_fnlist->fn_fieldlist.name);
+
+	      destr_fnlist->fn_fieldlist.fn_fields = (struct fn_field *)
+		obstack_alloc (&objfile->type_obstack,
+			       sizeof (struct fn_field) * has_destructor);
+	      memset (destr_fnlist->fn_fieldlist.fn_fields, 0,
+		  sizeof (struct fn_field) * has_destructor);
+	      tmp_sublist = sublist;
+	      last_sublist = NULL;
+	      i = 0;
+	      while (tmp_sublist != NULL)
+		{
+		  if (!is_destructor_name (tmp_sublist->fn_field.physname))
+		    {
+		      tmp_sublist = tmp_sublist->next;
+		      continue;
+		    }
+		  
+		  destr_fnlist->fn_fieldlist.fn_fields[i++]
+		    = tmp_sublist->fn_field;
+		  if (last_sublist)
+		    last_sublist->next = tmp_sublist->next;
+		  else
+		    sublist = tmp_sublist->next;
+		  last_sublist = tmp_sublist;
+		  tmp_sublist = tmp_sublist->next;
+		}
+
+	      destr_fnlist->fn_fieldlist.length = has_destructor;
+	      destr_fnlist->next = fip->fnlist;
+	      fip->fnlist = destr_fnlist;
+	      nfn_fields++;
+	      total_length += has_destructor;
+	      length -= has_destructor;
+	    }
+	  else if (is_v3)
+	    {
+	      /* v3 mangling prevents the use of abbreviated physnames,
+		 so we can do this here.  There are stubbed methods in v3
+		 only:
+		 - in -gstabs instead of -gstabs+
+		 - or for static methods, which are output as a function type
+		   instead of a method type.  */
+
+	      update_method_name_from_physname (&new_fnlist->fn_fieldlist.name,
+						sublist->fn_field.physname);
+	    }
+	  else if (has_destructor && new_fnlist->fn_fieldlist.name[0] != '~')
+	    {
+	      new_fnlist->fn_fieldlist.name = concat ("~", main_fn_name, NULL);
+	      xfree (main_fn_name);
+	    }
+	  else if (!has_stub)
+	    {
+	      char dem_opname[256];
+	      int ret;
+	      ret = cplus_demangle_opname (new_fnlist->fn_fieldlist.name,
+					      dem_opname, DMGL_ANSI);
+	      if (!ret)
+		ret = cplus_demangle_opname (new_fnlist->fn_fieldlist.name,
+					     dem_opname, 0);
+	      if (ret)
+		new_fnlist->fn_fieldlist.name
+		  = obsavestring (dem_opname, strlen (dem_opname),
+				  &objfile->type_obstack);
+	    }
+
 	  new_fnlist->fn_fieldlist.fn_fields = (struct fn_field *)
 	    obstack_alloc (&objfile->type_obstack,
 			   sizeof (struct fn_field) * length);
Index: valops.c
===================================================================
RCS file: /cvs/src/src/gdb/valops.c,v
retrieving revision 1.69
diff -u -p -r1.69 valops.c
--- valops.c	21 Aug 2002 17:24:31 -0000	1.69
+++ valops.c	10 Sep 2002 16:35:18 -0000
@@ -2302,12 +2302,11 @@ search_struct_method (char *name, struct
 	  struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
 	  name_matched = 1;
 
+	  check_stub_method_group (type, i);
 	  if (j > 0 && args == 0)
 	    error ("cannot resolve overloaded method `%s': no arguments supplied", name);
 	  else if (j == 0 && args == 0)
 	    {
-	      if (TYPE_FN_FIELD_STUB (f, j))
-		check_stub_method (type, i, j);
 	      v = value_fn_field (arg1p, f, j, type, offset);
 	      if (v != NULL)
 		return v;
@@ -2315,8 +2314,6 @@ search_struct_method (char *name, struct
 	  else
 	    while (j >= 0)
 	      {
-		if (TYPE_FN_FIELD_STUB (f, j))
-		  check_stub_method (type, i, j);
 		if (!typecmp (TYPE_FN_FIELD_STATIC_P (f, j),
 			      TYPE_VARARGS (TYPE_FN_FIELD_TYPE (f, j)),
 			      TYPE_NFIELDS (TYPE_FN_FIELD_TYPE (f, j)),
@@ -2555,20 +2552,15 @@ find_method_list (struct value **argp, c
       char *fn_field_name = TYPE_FN_FIELDLIST_NAME (type, i);
       if (fn_field_name && (strcmp_iw (fn_field_name, method) == 0))
 	{
-	  /* Resolve any stub methods.  */
 	  int len = TYPE_FN_FIELDLIST_LENGTH (type, i);
 	  struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
-	  int j;
 
 	  *num_fns = len;
 	  *basetype = type;
 	  *boffset = offset;
 
-	  for (j = 0; j < len; j++)
-	    {
-	      if (TYPE_FN_FIELD_STUB (f, j))
-		check_stub_method (type, i, j);
-	    }
+	  /* Resolve any stub methods.  */
+	  check_stub_method_group (type, i);
 
 	  return f;
 	}
@@ -3094,6 +3086,8 @@ value_struct_elt_for_reference (struct t
 	  int j = TYPE_FN_FIELDLIST_LENGTH (t, i);
 	  struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i);
 
+	  check_stub_method_group (t, i);
+
 	  if (intype == 0 && j > 1)
 	    error ("non-unique member `%s' requires type instantiation", name);
 	  if (intype)
@@ -3107,8 +3101,6 @@ value_struct_elt_for_reference (struct t
 	  else
 	    j = 0;
 
-	  if (TYPE_FN_FIELD_STUB (f, j))
-	    check_stub_method (t, i, j);
 	  if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
 	    {
 	      return value_from_longest


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]