From: pfieland@citron.sw.stratus.com (Peggy Fieland)
Subject: (none)
Organization: GNUs Not Usenet
Distribution: gnu
Date: Thu, 13 Aug 1992 20:15:46 GMT

On a stratus i860, using gdb-4.6 and cfront, gdb does not  account for
the differences between g++ and cfront methods of implementing virtual
function tables.  Here is a program that illustrates some of the
problems that arise:

#include <stream.h>

// Example of virtual functions, class inheritance and overloading!
// By Farooq Butt

extern "C" 
{ 
   char *strcpy(...); 
}



enum fruit { apple, orange, banana };              // Herbivore foods 
enum meat  { rawsteak, bones, groundbeef };        // Carnivore foods


class ZooAnimal {
   public: 
   
   ZooAnimal(){ cout << "creating a ZooAnimal \n"; strcpy (mytype,"ZooAnimal");}
   float zooanimalhood; 

   virtual void draw()     { cout << "Generic Zoo Animal\n"; }
   virtual void feed(fruit){ cout << "Can't feed a generic Zoo Animal\n";}
   virtual void feed(meat) { cout << "Can't feed a generic Zoo Animal\n";}

   private:
   char mytype[255]; 
   }; 


class Bear : public ZooAnimal {

   public:

   Bear (char *whoami = "bear"){strcpy(mytype,whoami);}

   void draw();
   void feed(fruit);
   void feed(meat);

   private:
   char mytype[255]; 
      
}; 


class Lion : public ZooAnimal{

   public:

   Lion (char *whoami = "lion"){strcpy(mytype,whoami);}

   void draw();
   void feed(fruit);
   void feed(meat);

   private:
   char mytype[255]; 
}; 

class Buffalo : public  ZooAnimal {

   public:

   Buffalo (char *whoami = "buffalo"){strcpy(mytype,whoami);}

   void draw();
   void feed(fruit);
   void feed(meat);

   private:
   char mytype[255]; 
}; 



// The ZooList is the list object while the ZooItem is the list item 
// object.  It is VERY important to differentiate between the two because
// a list is a functionally different thing from its components.


class ZooList;         // Forward declaration


class ListItem{

   friend class ZooList;     // i.e. Let the ZooList object get at privates
 
   public:
   ListItem(ZooAnimal *v){val = v; next =0;}

   private:
   ZooAnimal *val;
   ListItem *next; 
}; 

class ZooList{

   public: 
   ZooList(){thelist=0;}         // constructor 

   void insert(ZooAnimal*);       // interface 
   void traverse(); 

   private:
   ListItem *thelist;
}; 


void ZooList::insert(ZooAnimal* v)
      {
         ListItem *pt = new ListItem(v);

         pt->next = thelist;
         thelist = pt;

      }

void ZooList::traverse()
{
   if (thelist == 0)
      cout << "empty list\n";

   ListItem *pt = thelist;

   while (pt){
      pt->val->draw();

      pt->val->feed(apple);
      pt->val->feed(rawsteak);

      pt=pt->next;
   }
}



   
void Bear::draw()
{
   cout << "Grrrrrrraaawr I am a bear\n"; 
}

void Bear::feed(meat)
{
   cout << "YUM YUM, bears love meat!\n"; 
}

void Bear::feed(fruit)
{
   cout << "ECCCCHHH Bears can't eat fruit!\n"; 
}



void Lion::draw()
{
   cout << "Roooooaaaaar I am the king of the forest\n"; 
}

void Lion::feed(meat)
{
   cout << "YUM YUM, lions love meat!\n"; 
}

void Lion::feed(fruit)
{
   cout << "ECCCCHHH Lions can't eat fruit!\n"; 
}

void Buffalo::draw()
{
   cout << "Mooooooo I am the woolly plains-buffalo\n"; 
}

void Buffalo::feed(meat)
{
   cout << "YUK! How could you feed meat to a buffalo!\n";
}

void Buffalo::feed(fruit)
{
   cout << "YUM, got any more fruit there ? We buffalos love it!\n"; 
}

static ZooList alist;


main()
{

   Lion a1; 
   Bear a2; 
   Buffalo a3; 
   ZooAnimal *animal; 

   animal = new(Bear); 


   a1.draw(); 
   a2.draw();
   a3.draw();

   cout << "\n"; 

   alist.insert(&a1);
   alist.insert(&a2);
   alist.insert(&a3);

   alist.traverse(); 
}
   
Here is a sample debugging session that illustrates some of the
problems:


maestro-tests% pwd
/home2/maestro/pfieland/tests
maestro-tests% cp zoo.c /net/citron/home/citron/pfieland/gdb-4.6/yyy
maestro-tests% /net/citron/home/citron/pfieland/gdb-4.6/gdb-4.6/gdb/gdbx zoo
GDB is free software and you are welcome to distribute copies of it
 under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.6, Copyright 1992 Free Software Foundation, Inc...
(gdb) b main
Breakpoint 1 at 0x1ebc: file zoo.c, line 193.
(gdb) run
Starting program: /home2/maestro/pfieland/tests/zoo

Breakpoint 1, main () at zoo.c:193
193        Lion a1;
Current Language:  auto; currently c++
Type checking:     auto; currently off
Range checking:    auto; currently off
(gdb) n
194        Bear a2;
(gdb)
195        Buffalo a3;
(gdb)
198        animal = new(Bear);
(gdb)
201        a1.draw();
(gdb)
202        a2.draw();
(gdb) call a1.draw()
Argument to arithmetic operation not a number.
(gdb) print animal
$1 = (struct ZooAnimal *) 0xc920
(gdb) set print object on
(gdb) print animal
$2 = (suspicious *) 0xc920
(gdb) print *animal
Attempt to take contents of a non-pointer value.
(gdb)


Here is a fix. Note that it also includes an enhancement of mine to
print the DERIVED VALUE of an object when "print object" is on.

*** /home/tools/gnu/gdb-4.6/gdb/symtab.h	Mon Jul  6 13:11:13 1992
--- gdb-4.6/gdb/symtab.h	Tue Aug  4 11:31:31 1992
***************
*** 539,544 ****
--- 540,549 ----
  
  #define VTBL_PREFIX_P(NAME) ((NAME)[3] == CPLUS_MARKER	\
  			     && !strncmp ((NAME), "_vt", 3))
+ #define CF_OPNAME_PREFIX_P(NAME) ((NAME)[0] == '_' && (NAME)[1] == '_')
+ #define CF_VTBL_PREFIX_P(NAME) (!strncmp((NAME), "__vtbl__", CF_VTBL_PREFIX_LEN))
+ #define CF_VTBL_PREFIX_LEN  8
+ 
  
  /* Functions that work on the objects described above */
  

*** /home/tools/gnu/gdb-4.6/gdb/printcmd.c	Mon Jul  6 13:11:00 1992
--- gdb-4.6/gdb/printcmd.c	Thu Jul 30 11:34:57 1992
***************
***************
*** 769,774 ****
--- 770,791 ----
  	      type = VALUE_TYPE (val);
  	    }
  	}
+       /* Non-standard behavior -- print the value that a pointer points to according to
+          it's actual (derived) type.  
+        Added by Peggy Fieland Margaret_Fieland@vos.stratus.com */
+       else if (objectprint 
+                && (TYPE_CODE(type) == TYPE_CODE_STRUCT || TYPE_CODE(type) == TYPE_CODE_UNION))
+          {
+             value v;
+ 
+             v = value_from_vtable_info (val, type);
+             if (v != 0)
+                {
+                   val = v;
+                   type = VALUE_TYPE (val);
+                }
+          }
+       
      }
    else
      val = access_value_history (0);
*** /home/tools/gnu/gdb-4.6/gdb/values.c	Tue Jul 14 03:34:32 1992
--- gdb-4.6/gdb/values.c	Thu Aug 13 13:35:38 1992
***************
*** 32,38 ****
  /* Local function prototypes. */
  
  static value
! value_headof PARAMS ((value, struct type *, struct type *));
  
  static void
  show_values PARAMS ((char *, int));
--- 32,38 ----
  /* Local function prototypes. */
  
  static value
! value_headof PARAMS ((value, struct type *, struct type *, int is_struct));
  
  static void
  show_values PARAMS ((char *, int));
***************
*** 76,82 ****
  
    check_stub_type (type);
  
!   val = (value) xmalloc (sizeof (struct value) + TYPE_LENGTH (type));
    VALUE_NEXT (val) = all_values;
    all_values = val;
    VALUE_TYPE (val) = type;
--- 76,89 ----
  
    check_stub_type (type);
  
! /* guard to prevent coredumping on dereference of a null type (caused when, say,
!    doing "ptype var.xx" where xx is not in struct var. Peggy Fieland. */
!   if (type != NULL)
!      val = (value) xmalloc (sizeof (struct value) + TYPE_LENGTH (type));
!   else
!      /* pick a reasonable size  -- could this be + 0?? */
!      val = (value) xmalloc (sizeof (struct value) + sizeof(long)); 
! 
    VALUE_NEXT (val) = all_values;
    all_values = val;
    VALUE_TYPE (val) = type;
***************
*** 966,974 ****
    if (TYPE_VPTR_FIELDNO (context) < 0)
      fill_in_vptr_fieldno (context);
  
!   /* 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 (context)));
  
    /* Index into the virtual function table.  This is hard-coded because
       looking up a field is not cheap, and it may be important to save
--- 973,988 ----
    if (TYPE_VPTR_FIELDNO (context) < 0)
      fill_in_vptr_fieldno (context);
  
!   if (current_demangling_style == cfront_demangling)
!      /* For cfront, the virtual function table field is a pointer to a structure,
!         NOT, a pointer to an array of structures ! The structure has the form
!         { short d; short i; _vptp f; }
!      */
!      vtbl = value_field (arg1, TYPE_VPTR_FIELDNO (context));
!   else
!      /* 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 (context)));
  
    /* Index into the virtual function table.  This is hard-coded because
       looking up a field is not cheap, and it may be important to save
***************
*** 1001,1009 ****
     FIXME-tiemann: should work with dossier entries as well.  */
  
  static value
! value_headof (arg, btype, dtype)
       value arg;
       struct type *btype, *dtype;
  {
    /* First collect the vtables we must look at for this object.  */
    /* FIXME-tiemann: right now, just look at top-most vtable.  */
--- 1015,1024 ----
     FIXME-tiemann: should work with dossier entries as well.  */
  
  static value
! value_headof (arg, btype, dtype, is_struct)
       value arg;
       struct type *btype, *dtype;
+      int is_struct;
  {
    /* First collect the vtables we must look at for this object.  */
    /* FIXME-tiemann: right now, just look at top-most vtable.  */
***************
*** 1021,1032 ****
      vtbl = value_cast (lookup_pointer_type (btype), arg);
    else
      vtbl = arg;
!   vtbl = value_ind (value_field (value_ind (vtbl), TYPE_VPTR_FIELDNO (btype)));
  
    /* Check that VTBL looks like it points to a virtual function table.  */
    msymbol = lookup_minimal_symbol_by_pc (VALUE_ADDRESS (vtbl));
    if (msymbol == NULL
!       || !VTBL_PREFIX_P (demangled_name = msymbol -> name))
      {
        /* If we expected to find a vtable, but did not, let the user
  	 know that we aren't happy, but don't throw an error.
--- 1036,1051 ----
      vtbl = value_cast (lookup_pointer_type (btype), arg);
    else
      vtbl = arg;
!   if (is_struct)
!      vtbl = value_ind (value_field (vtbl, TYPE_VPTR_FIELDNO (btype)));
!   else
!      vtbl = value_ind (value_field (value_ind (vtbl), TYPE_VPTR_FIELDNO (btype)));
  
    /* Check that VTBL looks like it points to a virtual function table.  */
    msymbol = lookup_minimal_symbol_by_pc (VALUE_ADDRESS (vtbl));
    if (msymbol == NULL
!       || (!VTBL_PREFIX_P (demangled_name = msymbol -> name)
!                && ! CF_VTBL_PREFIX_P(demangled_name)))
      {
        /* If we expected to find a vtable, but did not, let the user
  	 know that we aren't happy, but don't throw an error.
***************
*** 1039,1045 ****
      }
  
    /* Now search through the virtual function table.  */
!   entry = value_ind (vtbl);
    nelems = longest_to_int (value_as_long (value_field (entry, 2)));
    for (i = 1; i <= nelems; i++)
      {
--- 1058,1069 ----
      }
  
    /* Now search through the virtual function table.  */
!   if (current_demangling_style == cfront_demangling)
!      /* Note (as before) that this difference is due to cfront's implementing vtbls differently
!         from g++ */
!      entry = vtbl;
!   else
!      entry = value_ind (vtbl);
    nelems = longest_to_int (value_as_long (value_field (entry, 2)));
    for (i = 1; i <= nelems; i++)
      {
***************
*** 1062,1068 ****
         * But we leave it in for future use, when we will hopefully
         * have optimizes the vtable to use thunks instead of offsets. */
        /* Use the name of vtable itself to extract a base type. */
!       demangled_name += 4;  /* Skip _vt$ prefix. */
      }
    else
      {
--- 1086,1104 ----
         * But we leave it in for future use, when we will hopefully
         * have optimizes the vtable to use thunks instead of offsets. */
        /* Use the name of vtable itself to extract a base type. */
!        int count;
! 
!        if (current_demangling_style == cfront_demangling)
!           {
!              demangled_name += CF_VTBL_PREFIX_LEN;  /* Skip _vtbl__  prefix. */
!              /* call this function to get the count (and move the pointer past the count )*/
!              get_count (&demangled_name, &count);
!              /* necessary because name may contain stuff after the class*/
!              demangled_name[count]  = '\0';
!           }
!        else
!           demangled_name += 4;  /* Skip _vt$ prefix. */
! 
      }
    else
      {
***************
*** 1080,1086 ****
        arg = value_add (value_cast (builtin_type_int, arg),
  		       value_field (best_entry, 0));
      }
!   VALUE_TYPE (arg) = lookup_pointer_type (SYMBOL_TYPE (sym));
    return arg;
  }
  
--- 1116,1125 ----
        arg = value_add (value_cast (builtin_type_int, arg),
  		       value_field (best_entry, 0));
      }
!   if (is_struct)
!      VALUE_TYPE (arg) = SYMBOL_TYPE (sym);
!   else
!      VALUE_TYPE (arg) = lookup_pointer_type (SYMBOL_TYPE (sym));
    return arg;
  }
  
***************
*** 1100,1106 ****
    if (TYPE_VPTR_FIELDNO (type) < 0 || VALUE_REPEATED (arg))
      return 0;
  
!   return value_headof (arg, 0, type);
  }
  
  /* Compute the address of the baseclass which is
--- 1139,1150 ----
    if (TYPE_VPTR_FIELDNO (type) < 0 || VALUE_REPEATED (arg))
      return 0;
  
! /* altered by MLF so as to be able to print the derived value of objects ,, ie print *obj */
!   if ((TYPE_CODE (VALUE_TYPE(arg)) == TYPE_CODE_STRUCT)
!       || (TYPE_CODE (VALUE_TYPE(arg)) == TYPE_CODE_UNION))
!      return (value_headof (arg, 0, type, 1));
!   else
!      return value_headof (arg, 0, type, 0);
  }
  
  /* Compute the address of the baseclass which is
*** /home/tools/gnu/gdb-4.6/gdb/valprint.c	Tue Jul 14 03:34:32 1992
--- gdb-4.6/gdb/valprint.c	Mon Aug 10 18:06:43 1992
***************
*** 436,441 ****
--- 448,455 ----
  
  /* Return truth value for assertion that TYPE is of the type
     "pointer to virtual function".  */
+ /* code altered by Peggy Fieland (Margaret_Fieland@vos.stratus.com)
+    to account for cfront conventions. */
  static int
  is_vtbl_ptr_type(type)
       struct type *type;
***************
*** 443,454 ****
    char *typename = type_name_no_tag (type);
    static const char vtbl_ptr_name[] =
      { CPLUS_MARKER,'v','t','b','l','_','p','t','r','_','t','y','p','e', 0 };
  
!   return (typename != NULL && !strcmp(typename, vtbl_ptr_name));
  }
  
  /* Return truth value for the assertion that TYPE is of the type
     "pointer to virtual function table".  */
  static int
  is_vtbl_member(type)
       struct type *type;
--- 457,480 ----
    char *typename = type_name_no_tag (type);
    static const char vtbl_ptr_name[] =
      { CPLUS_MARKER,'v','t','b','l','_','p','t','r','_','t','y','p','e', 0 };
+   static const char cf_vtbl_ptr_name[] = 
+     "__mptr";
  
! 
!   if (typename != NULL)
!      {
!      if (!strcmp(typename, vtbl_ptr_name))
!         return (1);
!      if (!strcmp(typename, cf_vtbl_ptr_name))
!         return (1);
!   }
!   return (0);
  }
  
  /* Return truth value for the assertion that TYPE is of the type
     "pointer to virtual function table".  */
+ /* code altered by Peggy Fieland (Margaret_Fieland@vos.stratus.com)
+    to account for cfront conventions. */
  static int
  is_vtbl_member(type)
       struct type *type;
***************
*** 458,467 ****
    else
      return 0;
  
!   if (TYPE_CODE (type) == TYPE_CODE_ARRAY
!       && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_STRUCT)
!     /* Virtual functions tables are full of pointers to virtual functions.  */
!     return is_vtbl_ptr_type (TYPE_TARGET_TYPE (type));
    return 0;
  }
  
--- 484,506 ----
    else
      return 0;
  
!   if (current_demangling_style == cfront_demangling)
!      {
!         if ((TYPE_CODE (type) == TYPE_CODE_ARRAY
!              && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_STRUCT))
!            /* Virtual functions tables are full of pointers to virtual functions.  */
!            return is_vtbl_ptr_type (TYPE_TARGET_TYPE (type));
!         else if (TYPE_CODE(type) == TYPE_CODE_STRUCT)
!            return is_vtbl_ptr_type (type);
!      }
!   else
!      {
!         if ((TYPE_CODE (type) == TYPE_CODE_ARRAY
!              && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_STRUCT))
!            /* Virtual functions tables are full of pointers to virtual functions.  */
!            return is_vtbl_ptr_type (TYPE_TARGET_TYPE (type));
!      }
! 
    return 0;
  }
  
***************
*** 677,683 ****
    register unsigned int i;
    unsigned len = TYPE_NFIELDS (domain);
    /* @@ Make VAL into bit offset */
!   LONGEST val = unpack_long (builtin_type_int, valaddr) << 3;
    for (i = TYPE_N_BASECLASSES (domain); i < len; i++)
      {
        int bitpos = TYPE_FIELD_BITPOS (domain, i);
--- 716,730 ----
    register unsigned int i;
    unsigned len = TYPE_NFIELDS (domain);
    /* @@ Make VAL into bit offset */
!   LONGEST val;
! 
!   /* Code altered by Peggy Fieland (Margaret_Fieland@vos.stratus.com) to account
!      for Cfront's use of 1-based offsets ... */
!   if (current_demangling_style == cfront_demangling)
!     val = (unpack_long (builtin_type_int, valaddr) - 1) << 3;
!   else
!     val = unpack_long (builtin_type_int, valaddr) << 3;
! 
    for (i = TYPE_N_BASECLASSES (domain); i < len; i++)
      {
        int bitpos = TYPE_FIELD_BITPOS (domain, i);

Newsgroups: gnu.gdb.bug