Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* RFA: Correct field names for class methods
@ 2002-08-26 20:30 Daniel Jacobowitz
  2002-08-28 10:26 ` David Carlton
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Daniel Jacobowitz @ 2002-08-26 20:30 UTC (permalink / raw)
  To: gdb-patches, ezannoni

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.

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".
	(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;
 	      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);
 }
 
+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);
+}
+
+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);
+      }
+
+  /* We can handle only the v2 case here, because the only stabs with
+     incorrect field names in v3 are constructors and destructors, and
+     the only stub methods in v3 are static methods.  */
+  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 +3483,118 @@ build_gdbtypes (void)
 	       "__bfd_vma", (struct objfile *) NULL);
 }
 
+/* Find the last component of the demangled C++ name NAME.
+
+   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	27 Aug 2002 02:02:56 -0000
@@ -1124,11 +1124,17 @@ 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 void update_method_name_from_physname (char **old_name, char *physname);
 
 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	27 Aug 2002 02:02:56 -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	27 Aug 2002 02:02:57 -0000
@@ -44,6 +44,7 @@
 #include "demangle.h"
 #include "language.h"
 #include "doublest.h"
+#include "cp-abi.h"
 
 #include <ctype.h>
 
@@ -3377,6 +3378,127 @@ read_member_functions (struct field_info
 	}
       else
 	{
+	  int has_stub = 0;
+	  int has_nondestructor = 0, has_destructor = 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 some methods, we have a complete physname, so we
+	     could fix this up now.  For stub methods we will do this
+	     later, in check_stub_method_group.  For non-stub methods,
+	     we have no clear way to know whether or not the physname
+	     is correct; g++ 2.95.x only reliably emits full physnames
+	     for operators which do not start with the method name
+	     (constructors, destructors fall in this category; there
+	     may be others?).  But for other methods it may or may not
+	     emit a full physname depending on the platform (if
+	     CPLUS_MARKER can be `$' or `.', it will use minimal debug
+	     information, but not otherwise).
+
+	     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, because the only interesting
+	     names are all operators.  Skip if any method in the group
+	     is a stub, to prevent our fouling up the workings of
+	     gdb_mangle_name.
+
+	     Another thing that we need to clean up here: GCC 2.95.x
+	     puts constructors and destructors in the same group.  We
+	     need to split this into two groups.  */
+
+	  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++;
+
+	      tmp_sublist = tmp_sublist->next;
+	    }
+
+	  if (has_destructor && has_nondestructor)
+	    {
+	      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, who 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_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	27 Aug 2002 02:02:58 -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


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: RFA: Correct field names for class methods
  2002-08-26 20:30 RFA: Correct field names for class methods Daniel Jacobowitz
@ 2002-08-28 10:26 ` David Carlton
  2002-08-28 11:36   ` Daniel Jacobowitz
  2002-08-29 21:07 ` Jim Blandy
  2002-09-09 16:32 ` Elena Zannoni
  2 siblings, 1 reply; 12+ messages in thread
From: David Carlton @ 2002-08-28 10:26 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: gdb-patches, ezannoni

In article <20020827031346.GA16591@nevyn.them.org>, Daniel Jacobowitz
<drow@mvista.com> writes:
 
> +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);
> +}

I'm pretty sure this is a memory leak.  How about replacing the last
if clause by

  xfree(*old_name);
  *old_name = method_name;

That should get rid of the memory leak and avoid a superfluous
strcmp.

(Also, the ChangeLog entry has the name of this function written
incorrectly.)

David Carlton
carlton@math.stanford.edu


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: RFA: Correct field names for class methods
  2002-08-28 10:26 ` David Carlton
@ 2002-08-28 11:36   ` Daniel Jacobowitz
  2002-08-28 11:50     ` David Carlton
  0 siblings, 1 reply; 12+ messages in thread
From: Daniel Jacobowitz @ 2002-08-28 11:36 UTC (permalink / raw)
  To: David Carlton; +Cc: gdb-patches, ezannoni

On Wed, Aug 28, 2002 at 10:23:06AM -0700, David Carlton wrote:
> In article <20020827031346.GA16591@nevyn.them.org>, Daniel Jacobowitz
> <drow@mvista.com> writes:
>  
> > +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);
> > +}
> 
> I'm pretty sure this is a memory leak.  How about replacing the last
> if clause by
> 
>   xfree(*old_name);
>   *old_name = method_name;
> 
> That should get rid of the memory leak and avoid a superfluous
> strcmp.

No can do.  Look at where TYPE_NAME is allocated; sometimes (often? 
Not sure.) it is on the obstack.  We're not consistent about that.  We
need to be, someday, but that's a separate cleanup.

> (Also, the ChangeLog entry has the name of this function written
> incorrectly.)

Oops, thanks!

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: RFA: Correct field names for class methods
  2002-08-28 11:36   ` Daniel Jacobowitz
@ 2002-08-28 11:50     ` David Carlton
  0 siblings, 0 replies; 12+ messages in thread
From: David Carlton @ 2002-08-28 11:50 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: gdb-patches, ezannoni

In article <20020828173429.GA5873@nevyn.them.org>, Daniel Jacobowitz
<drow@mvista.com> writes:
> On Wed, Aug 28, 2002 at 10:23:06AM -0700, David Carlton wrote:
>> In article <20020827031346.GA16591@nevyn.them.org>, Daniel Jacobowitz
>> <drow@mvista.com> writes:

>> > +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);
>> > +}
>> 
>> I'm pretty sure this is a memory leak.  How about replacing the last
>> if clause by
>> 
>> xfree(*old_name);
>> *old_name = method_name;
>> 
>> That should get rid of the memory leak and avoid a superfluous
>> strcmp.

> No can do.  Look at where TYPE_NAME is allocated; sometimes (often? 
> Not sure.) it is on the obstack.

Eek!  I hadn't followed all the code paths.  Unfortunate.

Having said that, update_method_name_from_physname() is called in
exactly one place, with the first argument equal to the location of
new_fnlist->fn_fieldlist.name, and at that point in the code, that
points to main_fn_name, which is always allocated using xmalloc().
It's only on other code paths that new_fnlist->fn_fieldlist.name gets
allocated on an obstack.

So I think my fix would be safe with the code as is, but future users
of the update_method_name_from_physname() would have to be careful.
So it seems that either my fix should be applied with a comment added
to the definition of update_method_name_from_physname() saying not to
call it unless it's safe to xfree() the first argument, or else it
should be left your way, but perhaps with a FIXME comment added.  I
have no idea which one of those would be better.

(Or, now that I think about it, maybe the fix is for main_fn_name to
be allocated on an obstack, and for update_method_name_from_physname()
also to use an obstack.  Hmm.)

David Carlton
carlton@math.stanford.edu


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: RFA: Correct field names for class methods
  2002-08-26 20:30 RFA: Correct field names for class methods Daniel Jacobowitz
  2002-08-28 10:26 ` David Carlton
@ 2002-08-29 21:07 ` Jim Blandy
  2002-08-30  0:14   ` Daniel Jacobowitz
  2002-09-09 16:32 ` Elena Zannoni
  2 siblings, 1 reply; 12+ messages in thread
From: Jim Blandy @ 2002-08-29 21:07 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: gdb-patches, ezannoni


I understand the method code very little, so I have only superficial
comments.  I'll try to do a more thorough reading next week, if Elena
doesn't beat me to it.

Daniel Jacobowitz <drow@mvista.com> writes:
> @@ -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;
>  	    }
>  	}
>      }

Not that it matters much, but why are you removing the QUIT from this
loop?

> +/* Find the last component of the demangled C++ name NAME.
> +
> +   This function return a pointer to the first colon before the
> +   last component, or NULL if the name had only one component.  */

Hmm, not every demangled name contains a closing paren.  Shouldn't this
comment clarify that it only works on demangled method names?

> @@ -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;
>  	    }
>  	}
>      }

QUIT is deleted here, too.

> @@ -3377,6 +3378,127 @@ read_member_functions (struct field_info
>  	}
>        else
>  	{
> +	  int has_stub = 0;
> +	  int has_nondestructor = 0, has_destructor = 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 some methods, we have a complete physname, so we
> +	     could fix this up now.  For stub methods we will do this
> +	     later, in check_stub_method_group.  For non-stub methods,
> +	     we have no clear way to know whether or not the physname
> +	     is correct; g++ 2.95.x only reliably emits full physnames
> +	     for operators which do not start with the method name
> +	     (constructors, destructors fall in this category; there
> +	     may be others?).  But for other methods it may or may not
> +	     emit a full physname depending on the platform (if
> +	     CPLUS_MARKER can be `$' or `.', it will use minimal debug
> +	     information, but not otherwise).
> +
> +	     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, because the only interesting
> +	     names are all operators.  Skip if any method in the group
> +	     is a stub, to prevent our fouling up the workings of
> +	     gdb_mangle_name.
> +
> +	     Another thing that we need to clean up here: GCC 2.95.x
> +	     puts constructors and destructors in the same group.  We
> +	     need to split this into two groups.  */
> +
> +	  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++;
> +
> +	      tmp_sublist = tmp_sublist->next;
> +	    }
> +
> +	  if (has_destructor && has_nondestructor)
> +	    {
> +	      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, who 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_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);
> +	    }
> +

Is there any way we could pull this out into a separate function or
functions?  read_member_functions is bad enough already.


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: RFA: Correct field names for class methods
  2002-08-29 21:07 ` Jim Blandy
@ 2002-08-30  0:14   ` Daniel Jacobowitz
  0 siblings, 0 replies; 12+ messages in thread
From: Daniel Jacobowitz @ 2002-08-30  0:14 UTC (permalink / raw)
  To: Jim Blandy; +Cc: gdb-patches, ezannoni

On Thu, Aug 29, 2002 at 10:48:05PM -0500, Jim Blandy wrote:
> 
> I understand the method code very little, so I have only superficial
> comments.  I'll try to do a more thorough reading next week, if Elena
> doesn't beat me to it.

Thanks.

> 
> Daniel Jacobowitz <drow@mvista.com> writes:
> > @@ -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;
> >  	    }
> >  	}
> >      }
> 
> Not that it matters much, but why are you removing the QUIT from this
> loop?

Exactly... because I moved the check_stub_method outside of the loop,
there is no longer any possible justification to QUIT; there.  It's a
loop of strcmp calls!  If you want, I could add the QUIT in
check_stub_method_group, but I don't think it's necessary.

> > +/* Find the last component of the demangled C++ name NAME.
> > +
> > +   This function return a pointer to the first colon before the
> > +   last component, or NULL if the name had only one component.  */
> 
> Hmm, not every demangled name contains a closing paren.  Shouldn't this
> comment clarify that it only works on demangled method names?

Yes, you're right.  It used to not require the closing paren, and then
I realized unpleasant things about the ways some local inner classes
are mangled.

> > @@ -3377,6 +3378,127 @@ read_member_functions (struct field_info
> >  	}
> >        else
> >  	{
> > +	  int has_stub = 0;
> > +	  int has_nondestructor = 0, has_destructor = 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 some methods, we have a complete physname, so we
> > +	     could fix this up now.  For stub methods we will do this
> > +	     later, in check_stub_method_group.  For non-stub methods,
> > +	     we have no clear way to know whether or not the physname
> > +	     is correct; g++ 2.95.x only reliably emits full physnames
> > +	     for operators which do not start with the method name
> > +	     (constructors, destructors fall in this category; there
> > +	     may be others?).  But for other methods it may or may not
> > +	     emit a full physname depending on the platform (if
> > +	     CPLUS_MARKER can be `$' or `.', it will use minimal debug
> > +	     information, but not otherwise).
> > +
> > +	     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, because the only interesting
> > +	     names are all operators.  Skip if any method in the group
> > +	     is a stub, to prevent our fouling up the workings of
> > +	     gdb_mangle_name.
> > +
> > +	     Another thing that we need to clean up here: GCC 2.95.x
> > +	     puts constructors and destructors in the same group.  We
> > +	     need to split this into two groups.  */
> > +
> > +	  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++;
> > +
> > +	      tmp_sublist = tmp_sublist->next;
> > +	    }
> > +
> > +	  if (has_destructor && has_nondestructor)
> > +	    {
> > +	      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, who 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_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);
> > +	    }
> > +
> 
> Is there any way we could pull this out into a separate function or
> functions?  read_member_functions is bad enough already.

Hmm... I'm not sure.  In particular, when splitting constructors from
destructors it tramples on the function state a bit: fip, nfn_fields,
total_length, length, and new_fnlist.  My usual criterion for breaking
out a function is whether its arguments would make any sense on their
own (outside of the calling function's control flow), and these wouldn't.

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: RFA: Correct field names for class methods
  2002-08-26 20:30 RFA: Correct field names for class methods Daniel Jacobowitz
  2002-08-28 10:26 ` David Carlton
  2002-08-29 21:07 ` Jim Blandy
@ 2002-09-09 16:32 ` Elena Zannoni
  2002-09-10  9:49   ` Daniel Jacobowitz
  2 siblings, 1 reply; 12+ messages in thread
From: Elena Zannoni @ 2002-09-09 16:32 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: gdb-patches, ezannoni

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?

 > 	(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?

 >  	      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.


 > +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?

 > +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);
 > +      }
 > +
 > +  /* We can handle only the v2 case here, because the only stabs with
 > +     incorrect field names in v3 are constructors and destructors, and
 > +     the only stub methods in v3 are static methods.  */
 > +  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 +3483,118 @@ build_gdbtypes (void)
 >  	       "__bfd_vma", (struct objfile *) NULL);
 >  }
 >  
 > +/* Find the last component of the demangled C++ name NAME.
 > +
 > +   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;
 > +}
 > +

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


 > +/* 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	27 Aug 2002 02:02:56 -0000
 > @@ -1124,11 +1124,17 @@ 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 void update_method_name_from_physname (char **old_name, char *physname);
 >  
 >  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	27 Aug 2002 02:02:56 -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	27 Aug 2002 02:02:57 -0000
 > @@ -44,6 +44,7 @@
 >  #include "demangle.h"
 >  #include "language.h"
 >  #include "doublest.h"
 > +#include "cp-abi.h"
 >  
 >  #include <ctype.h>
 >  
 > @@ -3377,6 +3378,127 @@ read_member_functions (struct field_info
 >  	}
 >        else
 >  	{
 > +	  int has_stub = 0;
 > +	  int has_nondestructor = 0, has_destructor = 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 some methods, we have a complete physname, so we
 > +	     could fix this up now.  For stub methods we will do this
 > +	     later, in check_stub_method_group.  For non-stub methods,
 > +	     we have no clear way to know whether or not the physname
 > +	     is correct; g++ 2.95.x only reliably emits full physnames
 > +	     for operators which do not start with the method name
 > +	     (constructors, destructors fall in this category; there
 > +	     may be others?).  But for other methods it may or may not
 > +	     emit a full physname depending on the platform (if
 > +	     CPLUS_MARKER can be `$' or `.', it will use minimal debug
 > +	     information, but not otherwise).
 > +
 > +	     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, because the only interesting
 > +	     names are all operators.  Skip if any method in the group
 > +	     is a stub, to prevent our fouling up the workings of
 > +	     gdb_mangle_name.
 > +
 > +	     Another thing that we need to clean up here: GCC 2.95.x
 > +	     puts constructors and destructors in the same group.  We
 > +	     need to split this into two groups.  */
 > +


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


 > +	  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.

 > +
 > +	      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?

 > +	    {
 > +	      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?


Elena

 > +	      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, who 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_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	27 Aug 2002 02:02:58 -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


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: RFA: Correct field names for class methods
  2002-09-09 16:32 ` Elena Zannoni
@ 2002-09-10  9:49   ` Daniel Jacobowitz
  2002-09-10 15:15     ` Elena Zannoni
  0 siblings, 1 reply; 12+ messages in thread
From: Daniel Jacobowitz @ 2002-09-10  9:49 UTC (permalink / raw)
  To: Elena Zannoni; +Cc: gdb-patches

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)
 \f
 /* 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


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: RFA: Correct field names for class methods
  2002-09-10  9:49   ` Daniel Jacobowitz
@ 2002-09-10 15:15     ` Elena Zannoni
  2002-09-10 15:20       ` Daniel Jacobowitz
  0 siblings, 1 reply; 12+ messages in thread
From: Elena Zannoni @ 2002-09-10 15:15 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: Elena Zannoni, gdb-patches

Daniel Jacobowitz writes:
 > 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.

OK.

 > 
 > >  >  	      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.
 > 

Yes! could you also pull the other new functions in stabsread.c?
They seem to be used there only.


 > >  > +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.

If you put it in stabsread.c.

 > 
 > >  > +/* 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).
 > 

ok


 > > 
 > > 
 > >  > +	  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?
 > 

Yes thanks.


 > >  > +
 > >  > +	      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.
 > 

Ahhhh. 


 > > 
 > >  > +	    {
 > >  > +	      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.
 > 

Approved, except for moving the functions to stabsread.c.

Elena


 > -- 
 > 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)
 >  \f
 >  /* 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


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: RFA: Correct field names for class methods
  2002-09-10 15:15     ` Elena Zannoni
@ 2002-09-10 15:20       ` Daniel Jacobowitz
  2002-09-13 11:30         ` Elena Zannoni
  0 siblings, 1 reply; 12+ messages in thread
From: Daniel Jacobowitz @ 2002-09-10 15:20 UTC (permalink / raw)
  To: Elena Zannoni; +Cc: gdb-patches

On Tue, Sep 10, 2002 at 06:13:41PM -0400, Elena Zannoni wrote:
> Approved, except for moving the functions to stabsread.c.
> 
> Elena

Well, that ulterior motive is showing again.

- I can't move method_name_from_physname unless I move the existing
  check_stub_method routine.  I could do this, and it might even be a
  good idea, since it's so patently stabs-only.

- I'm going to need class_name_from_physname in other parts of GDB; at
  least in the DWARF-2 reader.

I'd feel a little silly moving method_name_from_physname and leaving
class_name_from_physname.  What do you think?  I should probably
(separate patch) move check_stub_method and check_stub_method_group,
but the _from_physname functions seem like gdbtypes.c material to me.

> 
> 
>  > -- 
>  > 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)
>  >  \f
>  >  /* 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
> 

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: RFA: Correct field names for class methods
  2002-09-10 15:20       ` Daniel Jacobowitz
@ 2002-09-13 11:30         ` Elena Zannoni
  2002-09-13 19:11           ` Daniel Jacobowitz
  0 siblings, 1 reply; 12+ messages in thread
From: Elena Zannoni @ 2002-09-13 11:30 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: Elena Zannoni, gdb-patches

Daniel Jacobowitz writes:
 > On Tue, Sep 10, 2002 at 06:13:41PM -0400, Elena Zannoni wrote:
 > > Approved, except for moving the functions to stabsread.c.
 > > 
 > > Elena
 > 
 > Well, that ulterior motive is showing again.
 > 
 > - I can't move method_name_from_physname unless I move the existing
 >   check_stub_method routine.  I could do this, and it might even be a
 >   good idea, since it's so patently stabs-only.

OK I like the idea.

 > 
 > - I'm going to need class_name_from_physname in other parts of GDB; at
 >   least in the DWARF-2 reader.
 > 

Ah.

 > I'd feel a little silly moving method_name_from_physname and leaving
 > class_name_from_physname.  What do you think?  I should probably
 > (separate patch) move check_stub_method and check_stub_method_group,
 > but the _from_physname functions seem like gdbtypes.c material to me.
 > 

As you mentioned in a [private] e-mail maybe now the time has come to
start separating the c++ support into its own file. I think we could
move a few other things into such a file. I recall this being proposed
before, but I cannot do a successful search in the archives. All the
words I try to match are too common and the search only returns the
first N matches.

Elena


 > > 
 > > 
 > >  > -- 
 > >  > 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)
 > >  >  \f
 > >  >  /* 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
 > > 
 > 
 > -- 
 > Daniel Jacobowitz
 > MontaVista Software                         Debian GNU/Linux Developer


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: RFA: Correct field names for class methods
  2002-09-13 11:30         ` Elena Zannoni
@ 2002-09-13 19:11           ` Daniel Jacobowitz
  0 siblings, 0 replies; 12+ messages in thread
From: Daniel Jacobowitz @ 2002-09-13 19:11 UTC (permalink / raw)
  To: gdb-patches

On Fri, Sep 13, 2002 at 02:28:46PM -0400, Elena Zannoni wrote:
> Daniel Jacobowitz writes:
>  > On Tue, Sep 10, 2002 at 06:13:41PM -0400, Elena Zannoni wrote:
>  > > Approved, except for moving the functions to stabsread.c.
>  > > 
>  > > Elena
>  > 
>  > Well, that ulterior motive is showing again.
>  > 
>  > - I can't move method_name_from_physname unless I move the existing
>  >   check_stub_method routine.  I could do this, and it might even be a
>  >   good idea, since it's so patently stabs-only.
> 
> OK I like the idea.
> 
>  > 
>  > - I'm going to need class_name_from_physname in other parts of GDB; at
>  >   least in the DWARF-2 reader.
>  > 
> 
> Ah.
> 
>  > I'd feel a little silly moving method_name_from_physname and leaving
>  > class_name_from_physname.  What do you think?  I should probably
>  > (separate patch) move check_stub_method and check_stub_method_group,
>  > but the _from_physname functions seem like gdbtypes.c material to me.
>  > 
> 
> As you mentioned in a [private] e-mail maybe now the time has come to
> start separating the c++ support into its own file. I think we could
> move a few other things into such a file. I recall this being proposed
> before, but I cannot do a successful search in the archives. All the
> words I try to match are too common and the search only returns the
> first N matches.

OK.  I've checked the patch in as attached; the new functions go in
cp-support.c.  When I get a chance I'll move some associated gunk out
of gdbtypes.c; offhand this means check_stub_method{,_group}.

Onwards!  Method names were first; method printing from type
information is probably next; and then I'll tackle class names, and
we'll really start to get namespace support.  Then we can pick up the
DWARF-2 (DWARF-3) bits to handle it, which means the associated GCC
patches can finally go in.

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

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

	* gdbtypes.c (check_stub_method): Make static.
	(check_stub_method_group): New function.
	* gdbtypes.h: Update prototypes.
	* cp-support.c: New file.
	* cp-support.h: New file.

	* stabsread.c: Include "cp-abi.h" and "cp-support.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.
	(SFILES): Add cp-support.c.
	(COMMON_OBS): Add cp-support.o.
	(cp_support_h, cp-support.o): Add.

	* 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	14 Sep 2002 02:01:35 -0000
@@ -558,7 +558,7 @@ SFILES = ada-exp.y ada-lang.c ada-typepr
 	ui-file.h ui-file.c \
 	frame.c doublest.c \
 	builtin-regs.c std-regs.c \
-	gnu-v2-abi.c gnu-v3-abi.c hpacc-abi.c cp-abi.c
+	gnu-v2-abi.c gnu-v3-abi.c hpacc-abi.c cp-abi.c cp-support.c
 
 LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
@@ -626,6 +626,7 @@ command_h = command.h
 complaints_h = complaints.h
 completer_h = completer.h
 cp_abi_h = cp-abi.h
+cp_support_h = cp-support.h
 dcache_h = dcache.h
 defs_h = defs.h $(config_h) $(gdb_locale_h) $(gdb_signals_h) $(ansidecl_h) \
 	$(libiberty_h) $(progress_h) $(bfd_h) $(tui_h) $(ui_file_h) $(xm_h) \
@@ -842,7 +843,7 @@ COMMON_OBS = version.o blockframe.o brea
 	nlmread.o serial.o mdebugread.o top.o utils.o \
 	ui-file.o \
 	frame.o doublest.o \
-	gnu-v2-abi.o gnu-v3-abi.o hpacc-abi.o cp-abi.o
+	gnu-v2-abi.o gnu-v3-abi.o hpacc-abi.o cp-abi.o cp-support.o
 
 OBS = $(COMMON_OBS) $(ANNOTATE_OBS)
 
@@ -1588,6 +1589,7 @@ corelow.o: corelow.c $(defs_h) $(gdb_str
 	$(symtab_h) $(command_h) $(bfd_h) $(target_h) $(gdbcore_h) \
 	$(gdbthread_h) $(regcache_h) $(symfile_h)
 cp-abi.o: cp-abi.c $(defs_h) $(value_h) $(cp_abi_h) $(gdb_string_h)
+cp-support.o: cp-support.c $(defs_h) $(cp_support_h)
 cp-valprint.o: cp-valprint.c $(defs_h) $(gdb_obstack_h) $(symtab_h) \
 	$(gdbtypes_h) $(expression_h) $(value_h) $(command_h) $(gdbcmd_h) \
 	$(demangle_h) $(annotate_h) $(gdb_string_h) $(c_lang_h) $(target_h) \
@@ -2174,7 +2176,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) $(cp_support_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-support.c
===================================================================
RCS file: cp-support.c
diff -N cp-support.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ cp-support.c	14 Sep 2002 02:01:35 -0000
@@ -0,0 +1,141 @@
+/* Helper routines for C++ support in GDB.
+   Copyright 2002 Free Software Foundation, Inc.
+
+   Contributed by MontaVista Software.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 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.  */
+
+#include "defs.h"
+#include "cp-support.h"
+#include "gdb_string.h"
+#include "demangle.h"
+
+/* 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;
+}
Index: cp-support.h
===================================================================
RCS file: cp-support.h
diff -N cp-support.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ cp-support.h	14 Sep 2002 02:01:35 -0000
@@ -0,0 +1,25 @@
+/* Helper routines for C++ support in GDB.
+   Copyright 2002 Free Software Foundation, Inc.
+
+   Contributed by MontaVista Software.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 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.  */
+
+extern char *class_name_from_physname (const char *physname);
+
+extern char *method_name_from_physname (const char *physname);
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	14 Sep 2002 02:01:35 -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	14 Sep 2002 02:01:36 -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
@@ -3434,7 +3477,6 @@ build_gdbtypes (void)
 	       TYPE_FLAG_UNSIGNED,
 	       "__bfd_vma", (struct objfile *) NULL);
 }
-
 
 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	14 Sep 2002 02:01:36 -0000
@@ -1124,7 +1124,7 @@ 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 *);
 
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	14 Sep 2002 02:01:36 -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	14 Sep 2002 02:01:37 -0000
@@ -44,6 +44,8 @@
 #include "demangle.h"
 #include "language.h"
 #include "doublest.h"
+#include "cp-abi.h"
+#include "cp-support.h"
 
 #include <ctype.h>
 
@@ -3080,6 +3082,27 @@ rs6000_builtin_type (int typenum)
 \f
 /* 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 +3400,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.71
diff -u -p -r1.71 valops.c
--- valops.c	13 Sep 2002 00:38:48 -0000	1.71
+++ valops.c	14 Sep 2002 02:01:38 -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


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2002-09-14  2:11 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-08-26 20:30 RFA: Correct field names for class methods Daniel Jacobowitz
2002-08-28 10:26 ` David Carlton
2002-08-28 11:36   ` Daniel Jacobowitz
2002-08-28 11:50     ` David Carlton
2002-08-29 21:07 ` Jim Blandy
2002-08-30  0:14   ` Daniel Jacobowitz
2002-09-09 16:32 ` Elena Zannoni
2002-09-10  9:49   ` Daniel Jacobowitz
2002-09-10 15:15     ` Elena Zannoni
2002-09-10 15:20       ` Daniel Jacobowitz
2002-09-13 11:30         ` Elena Zannoni
2002-09-13 19:11           ` Daniel Jacobowitz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox