[gnu.gdb.bug] GDB 3.1+

mdt@YAHI.STANFORD.EDU (Michael Tiemann) (03/12/89)

Some people have noticed that GDB 3.1 does not quite replace GDB+
2.8.1 when it comes to debugging GNU C++ code.  This is more my fault
than Randy's.  The following diffs should go a long way toward
remedying the problem.  You will also need a small patch for dbxout.c
for GNU C++ 1.34.0, which is enclosed at the bottom.

Michael

yahi% diff -c2 dbxread.c~ dbxread.c
*** dbxread.c~	Mon Jan 30 08:59:56 1989
--- dbxread.c	Sat Mar 11 17:59:56 1989
***************
*** 3786,3789 ****
--- 3786,3794 ----
    int read_possible_virtual_info = 0;
  
+   if (TYPE_CODE (type) == TYPE_CODE_UNDEF)
+     {
+       TYPE_MAIN_VARIANT (type) = type;
+     }
+ 
    TYPE_CODE (type) = TYPE_CODE_STRUCT;
  
***************
*** 4010,4013 ****
--- 4015,4021 ----
  
  	      new_sublist->fn_field.type = read_type (pp);
+ 	      smash_to_method_type (new_sublist->fn_field.type,
+ 				    TYPE_DOMAIN_TYPE (new_sublist->fn_field.type),
+ 				    TYPE_TARGET_TYPE (new_sublist->fn_field.type));
  	      new_sublist->fn_field.args = read_args (pp, ':');
  	      p = *pp;
yahi% diff -c2 values.c~ values.c
*** values.c~	Tue Jan 31 09:55:59 1989
--- values.c	Sat Mar 11 18:14:26 1989
***************
*** 659,669 ****
        = fill_in_vptr_fieldno (type);
  
!   /* Pretend that this array is just an array of pointers to integers.
!      This will have to change for multiple inheritance.  */
!   vtbl = value_copy (value_field (arg1, TYPE_VPTR_FIELDNO (type)));
!   VALUE_TYPE (vtbl) = lookup_pointer_type (builtin_type_int);
  
    /* Index into the virtual function table.  */
!   vfn = value_subscript (vtbl, vi);
  
    /* Reinstantiate the function pointer with the correct type.  */
--- 659,669 ----
        = fill_in_vptr_fieldno (type);
  
!   /* The virtual function table is now an array of structures
!      which have the form { int16 offset, delta; void* pfn; }.  */
!   vtbl = value_ind (value_field (arg1, TYPE_VPTR_FIELDNO (type)));
  
    /* Index into the virtual function table.  */
!   vfn = value_struct_elt (value_subscript (vtbl, vi), 0, "pfn",
! 			  "internal error in virtual function lookup");
  
    /* Reinstantiate the function pointer with the correct type.  */
yahi% diff -c2 symseg.h~ symseg.h
*** symseg.h~	Mon Jan 23 12:42:18 1989
--- symseg.h	Sat Mar 11 17:44:56 1989
***************
*** 122,125 ****
--- 122,126 ----
    /* C++ */
    TYPE_CODE_MEMBER,		/* Member type */
+   TYPE_CODE_METHOD,		/* Method type */
    TYPE_CODE_REF,		/* C++ Reference types */
  };
***************
*** 147,151 ****
    /* For a pointer type, describes the type of object pointed to.
       For an array type, describes the type of the elements.
!      For a function type, describes the type of the value.
       For a range type, describes the type of the full range.
       Unused otherwise.  */
--- 148,152 ----
    /* For a pointer type, describes the type of object pointed to.
       For an array type, describes the type of the elements.
!      For a function or method type, describes the type of the value.
       For a range type, describes the type of the full range.
       Unused otherwise.  */
***************
*** 240,244 ****
  	  char *name;
  #endif
! 	  /* The type of the argument */
  	  struct type *type;
  	  /* The argument list */
--- 241,245 ----
  	  char *name;
  #endif
! 	  /* The return value of the method */
  	  struct type *type;
  	  /* The argument list */
yahi% diff -c2 symtab.c~ symtab.c
*** symtab.c~	Tue Jan 17 11:29:19 1989
--- symtab.c	Sat Mar 11 17:47:40 1989
***************
*** 362,365 ****
--- 362,419 ----
  }
  
+ struct type *
+ lookup_method_type (type, domain)
+      struct type *type, *domain;
+ {
+   register struct type *mtype = TYPE_MAIN_VARIANT (type);
+   struct type *main_type;
+ 
+   main_type = mtype;
+   while (mtype)
+     {
+       if (TYPE_DOMAIN_TYPE (mtype) == domain)
+ 	return mtype;
+       mtype = TYPE_NEXT_VARIANT (mtype);
+     }
+ 
+   /* This is the first time anyone wanted this member type.  */
+   if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+     mtype  = (struct type *) xmalloc (sizeof (struct type));
+   else
+     mtype  = (struct type *) obstack_alloc (symbol_obstack,
+ 					    sizeof (struct type));
+ 
+   bzero (mtype, sizeof (struct type));
+   if (main_type == 0)
+     main_type = mtype;
+   else
+     {
+       TYPE_NEXT_VARIANT (mtype) = TYPE_NEXT_VARIANT (main_type);
+       TYPE_NEXT_VARIANT (main_type) = mtype;
+     }
+   TYPE_MAIN_VARIANT (mtype) = main_type;
+   TYPE_TARGET_TYPE (mtype) = type;
+   TYPE_DOMAIN_TYPE (mtype) = domain;
+   /* New type is permanent if type pointed to is permanent.  */
+   if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+     TYPE_FLAGS (mtype) |= TYPE_FLAG_PERM;
+ 
+   /* In practice, this is never used.  */
+   TYPE_LENGTH (mtype) = 1;
+   TYPE_CODE (mtype) = TYPE_CODE_MEMBER;
+ 
+ #if 0
+   /* Now splice in the new member pointer type.  */
+   if (main_type)
+     {
+       /* This type was not "smashed".  */
+       TYPE_CHAIN (mtype) = TYPE_CHAIN (main_type);
+       TYPE_CHAIN (main_type) = mtype;
+     }
+ #endif
+ 
+   return mtype;
+ }
+ 
  /* Given a type TYPE, return a type which has offset OFFSET,
     via_virtual VIA_VIRTUAL, and via_public VIA_PUBLIC.
***************
*** 491,494 ****
--- 545,565 ----
  
    TYPE_MAIN_VARIANT (type) = lookup_member_type (domain, to_type);
+ }
+ 
+ /* Smash TYPE to be a type of method of DOMAIN with type TO_TYPE.  */
+ 
+ void
+ smash_to_method_type (type, domain, to_type)
+      struct type *type, *domain, *to_type;
+ {
+   bzero (type, sizeof (struct type));
+   TYPE_TARGET_TYPE (type) = to_type;
+   TYPE_DOMAIN_TYPE (type) = domain;
+ 
+   /* In practice, this is never needed.  */
+   TYPE_LENGTH (type) = 1;
+   TYPE_CODE (type) = TYPE_CODE_METHOD;
+ 
+   TYPE_MAIN_VARIANT (type) = lookup_method_type (domain, to_type);
  }
  
yahi% diff -c2 valops.c~ valops.c
*** valops.c~	Thu Jan 19 15:09:14 1989
--- valops.c	Fri Mar 10 22:03:47 1989
***************
*** 525,536 ****
      /* If it's a member function, just look at the function
         part of it.  */
-     if (code == TYPE_CODE_MEMBER)
-       {
- 	ftype = TYPE_TARGET_TYPE (ftype);
- 	code = TYPE_CODE (ftype);
-       }
- 
      /* Determine address to call.  */
!     if (code == TYPE_CODE_FUNC)
        {
  	funaddr = VALUE_ADDRESS (function);
--- 525,530 ----
      /* If it's a member function, just look at the function
         part of it.  */
      /* Determine address to call.  */
!     if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD)
        {
  	funaddr = VALUE_ADDRESS (function);
***************
*** 540,545 ****
        {
  	funaddr = value_as_long (function);
! 	if (TYPE_CODE (TYPE_TARGET_TYPE (ftype))
! 	    == TYPE_CODE_FUNC)
  	  value_type = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (ftype));
  	else
--- 534,539 ----
        {
  	funaddr = value_as_long (function);
! 	if (TYPE_CODE (TYPE_TARGET_TYPE (ftype)) == TYPE_CODE_FUNC
! 	    || TYPE_CODE (TYPE_TARGET_TYPE (ftype)) == TYPE_CODE_METHOD)
  	  value_type = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (ftype));
  	else
yahi% diff -c2 valprint.c~ valprint.c
*** valprint.c~	Wed Jan 11 10:51:31 1989
--- valprint.c	Fri Mar 10 22:41:35 1989
***************
*** 186,190 ****
  	  break;
  	}
!       if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_MEMBER)
  	{
  	  struct type *domain = TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type));
--- 186,190 ----
  	  break;
  	}
!       if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD)
  	{
  	  struct type *domain = TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type));
***************
*** 195,297 ****
  
  	  val = unpack_long (builtin_type_int, valaddr);
! 	  if (TYPE_CODE (target) == TYPE_CODE_FUNC)
  	    {
! 	      if (val < 128)
  		{
! 		  len = TYPE_NFN_FIELDS (domain);
! 		  for (i = 0; i < len; i++)
! 		    {
! 		      f = TYPE_FN_FIELDLIST1 (domain, i);
! 		      len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
  
! 		      for (j = 0; j < len2; j++)
! 			{
! 			  QUIT;
! 			  if (TYPE_FN_FIELD_VOFFSET (f, j) == val)
! 			    {
! 			      kind = "virtual";
! 			      goto common;
! 			    }
! 			}
! 		    }
! 		}
! 	      else
! 		{
! 		  struct symbol *sym = find_pc_function ((CORE_ADDR) val);
! 		  if (sym == 0)
! 		    error ("invalid pointer to member function");
! 		  len = TYPE_NFN_FIELDS (domain);
! 		  for (i = 0; i < len; i++)
  		    {
! 		      f = TYPE_FN_FIELDLIST1 (domain, i);
! 		      len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
! 
! 		      for (j = 0; j < len2; j++)
  			{
! 			  QUIT;
! 			  if (!strcmp (SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j)))
! 			    goto common;
  			}
  		    }
  		}
- 	    common:
- 	      if (i < len)
- 		{
- 		  fputc ('&', stream);
- 		  type_print_varspec_prefix (TYPE_FN_FIELD_TYPE (f, j), stream, 0, 0);
- 		  fprintf (stream, kind);
- 		  if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_'
- 		      && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == '$')
- 		    type_print_method_args
- 		      (TYPE_FN_FIELD_ARGS (f, j) + 1, "~",
- 		       TYPE_FN_FIELDLIST_NAME (domain, i), stream);
- 		  else
- 		    type_print_method_args
- 		      (TYPE_FN_FIELD_ARGS (f, j), "",
- 		       TYPE_FN_FIELDLIST_NAME (domain, i), stream);
- 		  break;
- 		}
  	    }
  	  else
  	    {
! 	      /* VAL is a byte offset into the structure type DOMAIN.
! 		 Find the name of the field for that offset and
! 		 print it.  */
! 	      int extra = 0;
! 	      int bits = 0;
! 	      len = TYPE_NFIELDS (domain);
! 	      val <<= 3;	/* @@ Make VAL into bit offset */
  	      for (i = 0; i < len; i++)
  		{
! 		  int bitpos = TYPE_FIELD_BITPOS (domain, i);
! 		  QUIT;
! 		  if (val == bitpos)
! 		    break;
! 		  if (val < bitpos && i > 0)
  		    {
! 		      int ptrsize = (TYPE_LENGTH (builtin_type_char) * TYPE_LENGTH (target));
! 		      /* Somehow pointing into a field.  */
! 		      i -= 1;
! 		      extra = (val - TYPE_FIELD_BITPOS (domain, i));
! 		      if (extra & 0x3)
! 			bits = 1;
! 		      else
! 			extra >>= 3;
! 		      break;
  		    }
  		}
! 	      if (i < len)
  		{
! 		  fputc ('&', stream);
! 		  type_print_base (domain, stream, 0, 0);
! 		  fprintf (stream, "::");
! 		  fprintf (stream, "%s", TYPE_FIELD_NAME (domain, i));
! 		  if (extra)
! 		    fprintf (stream, " + %d bytes", extra);
! 		  if (bits)
! 		    fprintf (stream, " (offset in bits)");
  		  break;
  		}
  	    }
  	  fputc ('(', stream);
  	  type_print (type, "", stream, -1);
--- 195,303 ----
  
  	  val = unpack_long (builtin_type_int, valaddr);
! 	  if (val < 128)
  	    {
! 	      len = TYPE_NFN_FIELDS (domain);
! 	      for (i = 0; i < len; i++)
  		{
! 		  f = TYPE_FN_FIELDLIST1 (domain, i);
! 		  len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
  
! 		  for (j = 0; j < len2; j++)
  		    {
! 		      QUIT;
! 		      if (TYPE_FN_FIELD_VOFFSET (f, j) == val)
  			{
! 			  kind = "virtual";
! 			  goto common;
  			}
  		    }
  		}
  	    }
  	  else
  	    {
! 	      struct symbol *sym = find_pc_function ((CORE_ADDR) val);
! 	      if (sym == 0)
! 		error ("invalid pointer to member function");
! 	      len = TYPE_NFN_FIELDS (domain);
  	      for (i = 0; i < len; i++)
  		{
! 		  f = TYPE_FN_FIELDLIST1 (domain, i);
! 		  len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
! 
! 		  for (j = 0; j < len2; j++)
  		    {
! 		      QUIT;
! 		      if (!strcmp (SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j)))
! 			goto common;
  		    }
  		}
! 	    }
! 	common:
! 	  if (i < len)
! 	    {
! 	      fputc ('&', stream);
! 	      type_print_varspec_prefix (TYPE_FN_FIELD_TYPE (f, j), stream, 0, 0);
! 	      fprintf (stream, kind);
! 	      if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_'
! 		  && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == '$')
! 		type_print_method_args
! 		  (TYPE_FN_FIELD_ARGS (f, j) + 1, "~",
! 		   TYPE_FN_FIELDLIST_NAME (domain, i), stream);
! 	      else
! 		type_print_method_args
! 		  (TYPE_FN_FIELD_ARGS (f, j), "",
! 		   TYPE_FN_FIELDLIST_NAME (domain, i), stream);
! 	      break;
! 	    }
! 	  fputc ('(', stream);
! 	  type_print (type, "", stream, -1);
! 	  fprintf (stream, ") %d", val >> 3);
! 	}
!       else if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_MEMBER)
! 	{
! 	  struct type *domain = TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type));
! 	  struct type *target = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (type));
! 	  struct fn_field *f;
! 	  int j, len2;
! 	  char *kind = "";
! 
! 	  /* VAL is a byte offset into the structure type DOMAIN.
! 	     Find the name of the field for that offset and
! 	     print it.  */
! 	  int extra = 0;
! 	  int bits = 0;
! 	  len = TYPE_NFIELDS (domain);
! 	  val <<= 3;		/* @@ Make VAL into bit offset */
! 	  for (i = 0; i < len; i++)
! 	    {
! 	      int bitpos = TYPE_FIELD_BITPOS (domain, i);
! 	      QUIT;
! 	      if (val == bitpos)
! 		break;
! 	      if (val < bitpos && i > 0)
  		{
! 		  int ptrsize = (TYPE_LENGTH (builtin_type_char) * TYPE_LENGTH (target));
! 		  /* Somehow pointing into a field.  */
! 		  i -= 1;
! 		  extra = (val - TYPE_FIELD_BITPOS (domain, i));
! 		  if (extra & 0x3)
! 		    bits = 1;
! 		  else
! 		    extra >>= 3;
  		  break;
  		}
  	    }
+ 	  if (i < len)
+ 	    {
+ 	      fputc ('&', stream);
+ 	      type_print_base (domain, stream, 0, 0);
+ 	      fprintf (stream, "::");
+ 	      fprintf (stream, "%s", TYPE_FIELD_NAME (domain, i));
+ 	      if (extra)
+ 		fprintf (stream, " + %d bytes", extra);
+ 	      if (bits)
+ 		fprintf (stream, " (offset in bits)");
+ 	      break;
+ 	    }
  	  fputc ('(', stream);
  	  type_print (type, "", stream, -1);
***************
*** 573,576 ****
--- 579,583 ----
         &&
         (code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC
+ 	|| code == TYPE_CODE_METHOD
  	|| code == TYPE_CODE_ARRAY
  	|| code == TYPE_CODE_MEMBER
***************
*** 702,705 ****
--- 709,721 ----
        break;
  
+     case TYPE_CODE_METHOD:
+       type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0,
+ 				 passed_a_ptr);
+       fputc (' ', stream);
+       type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0,
+ 		       passed_a_ptr);
+       fprintf (stream, "::");
+       break;
+ 
      case TYPE_CODE_REF:
        type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1);
***************
*** 758,761 ****
--- 774,783 ----
        break;
  
+     case TYPE_CODE_METHOD:
+       if (passed_a_ptr)
+ 	fputc (')', stream);
+       type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0);
+       break;
+ 
      case TYPE_CODE_PTR:
      case TYPE_CODE_REF:
***************
*** 819,822 ****
--- 841,845 ----
      case TYPE_CODE_REF:
      case TYPE_CODE_FUNC:
+     case TYPE_CODE_METHOD:
        type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
        break;
***************
*** 887,891 ****
  		  if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
  		    fprintf (stream, "virtual ");
! 		  type_print (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j))), "", stream, 0);
  		  if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_'
  		      && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == '$')
--- 910,914 ----
  		  if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
  		    fprintf (stream, "virtual ");
! 		  type_print (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)), "", stream, 0);
  		  if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_'
  		      && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == '$')
yahi% gdb a.out
GDB 3.1, Copyright (C) 1988 Free Software Foundation, Inc.
There is ABSOLUTELY NO WARRANTY for GDB; type "info warranty" for details.
GDB is free software and you are welcome to distribute copies of it
 under certain conditions; type "info copying" to see the conditions.
Reading symbol data from /home/sioux/mdt/dist-gdb/a.out...done.
Function fatal not defined.
Type "help" for a list of commands.
(gdb) pty a
struct a  {
    int x;
    int y;

    int f ();
    int f (int, int);

}
(gdb) pty b
struct b : public a  {
    int z;
    int w;

    int f ();
    int f (int, int);

}
(gdb) b main
Breakpoint 1 at 0x21a8: file test.c, line 30.
(gdb) r
Starting program: /home/sioux/mdt/dist-gdb/a.out 

Bpt 1, main () (test.c line 33)
33	  x.f (5, 6);
(gdb) p x
$1 = {x = 0, y = 0}
(gdb) p x.f (-1, -2)
$2 = -134218336
(gdb) p x.f()
calling f for a(-1,-2)
$3 = -134218336
(gdb) b a::f
[0] cancel
[1] all
[2] file:test.c; line number:10
[3] file:test.c; line number:6
> 1
Breakpoint 2 at 0x2138: file test.c, line 10.
Breakpoint 3 at 0x2178: file test.c, line 6.
Multiple breakpoints were set.
Use the "delete" command to delete unwanted breakpoints.
(gdb) c
Continuing.

Bpt 2, f_PSa_SI_SI ($this=(struct a *) 0xf7fffda0, i=5, j=6) (test.c line 10)
10	      x = i;
(gdb) p x
$4 = -1
(gdb) i ad this
No symbol "this" in current context.
(gdb) p ad $this
No symbol "ad" in current context.
(gdb) i ad $this
Symbol "$this" is a local variable at frame offset 68.
(gdb) i ad x
Symbol "x" is a field of the local class variable `this'
(gdb) set x = 10
(gdb) p *$this
Attempt to take contents of a non-pointer value.
(gdb) p $this
$5 = void
(gdb) p x
$6 = 10
(gdb) quit
The program is running.  Quit anyway? (y or n) y
yahi% 

As you can see, GDB 3.1 now behaves more like a C++ debugger.

yahi% diff -c2 dbxout.c~ dbxout.c
*** dbxout.c~	Mon Feb 27 17:43:02 1989
--- dbxout.c	Sat Mar 11 17:24:26 1989
***************
*** 523,527 ****
  		  t = tem; /* Get to the FUNCTION_DECL */
  		  dbxout_type (TREE_TYPE (t), 0); /* METHOD_TYPE */
- 		  dbxout_args (TYPE_ARG_TYPES (TREE_TYPE (t)));
  		  fprintf (asmfile, ":%s;%c%c",
  			   IDENTIFIER_POINTER (DECL_NAME (t)),
--- 523,526 ----
***************
*** 575,579 ****
  		  t = tem; /* Get to the FUNCTION_DECL */
  		  dbxout_type (TREE_TYPE (t), 0); /* METHOD_TYPE */
- 		  dbxout_args (TYPE_ARG_TYPES (TREE_TYPE (t)));
  		  fprintf (asmfile, ":%s;%c%c",
  			   IDENTIFIER_POINTER (DECL_NAME (t)),
--- 574,577 ----
***************
*** 695,698 ****
--- 693,697 ----
  	  CHARS (1);
  	  dbxout_type (TREE_TYPE (type), 0);
+ 	  dbxout_args (TYPE_ARG_TYPES (type));
  	}
        else
***************
*** 786,791 ****
  	break;
        FORCE_TEXT;
        fprintf (asmfile, ".stabs \"%s:%c",
! 	       IDENTIFIER_POINTER (DECL_ORIGINAL_NAME (decl)),
  	       TREE_PUBLIC (decl) ? 'F' : 'f');
  
--- 785,792 ----
  	break;
        FORCE_TEXT;
+       /* For GDB 3.1, it may be better to use DECL_NAME (instead of DECL_ORIGINAL_NAME
+ 	 in this case.  */
        fprintf (asmfile, ".stabs \"%s:%c",
! 	       IDENTIFIER_POINTER (DECL_NAME (decl)),
  	       TREE_PUBLIC (decl) ? 'F' : 'f');
  
yahi% 

Michael