Article View: gnu.gdb.bug
Article #376(none)
From: Peggy Fieland
Date: Thu, 13 Aug 1992 20:15
Date: Thu, 13 Aug 1992 20:15
639 lines
18657 bytes
18657 bytes
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);
Technical Details
Message-ID:
<9208132015.AA15970@citron.sw.stratus.com>Path:
arc1-ca.pugleaf.net!sparky!uunet!cis.ohio-state.edu!citron.sw.stratus.com!pfielandShow Full Headers
Complete Article Headers
Newsgroups: gnu.gdb.bug Path: arc1-ca.pugleaf.net!sparky!uunet!cis.ohio-state.edu!citron.sw.stratus.com!pfieland From: pfieland@citron.sw.stratus.com (Peggy Fieland) Subject: (none) Message-ID: <9208132015.AA15970@citron.sw.stratus.com> Sender: gnulists@ai.mit.edu Organization: GNUs Not Usenet Distribution: gnu Date: Thu, 13 Aug 1992 20:15:46 GMT Approved: bug-gdb@prep.ai.mit.edu Lines: 640