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


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

[rfa/c++] Fix "virtual baseclass botch"


Here's the last big patch in my queue.  This is the fix to the virtual
baseclass botch problems (or at least most of them).  I add baseclass_offset
to the C++ ABI structure, and supply a new version for v3.  The old
baseclass_offset is moved (unchanged except for name) into gnu-v2-abi.c. 
hpacc-abi.c currently references that same function, which is not quite
right, but preserves the current state of affairs (see the FIXME).

Tested on i386-linux; gcc 2.95.4 and 3.0-branch; stabs+ and dwarf-2.  No
changes on 2.95.4 except for a couple of:
-PASS: gdb.threads/pthreads.exp: continue to bkpt at common_routine in thread 2
-PASS: gdb.threads/pthreads.exp: backtrace from thread 2 bkpt in common_routine
+FAIL: gdb.threads/pthreads.exp: continue to bkpt at common_routine in thread 2

and vice versa; this test is apparently quite unstable.

In v3/stabs:
-# of expected passes           7947
-# of unexpected failures       62
-# of unexpected successes      34
-# of expected failures         192
+# of expected passes           7981
+# of unexpected failures       57
+# of unexpected successes      35
+# of expected failures         191


In v3/dwarf we're not quite as well off:
-# of expected passes           7964
-# of unexpected failures       135
+# of expected passes           7978
+# of unexpected failures       152
 # of unexpected successes      29
 # of expected failures         106
 # of untested testcases                7

Still an improvement, but I have another problem to track down in there.  I
think I know where it is.

OK to commit?


-- 
Daniel Jacobowitz                           Carnegie Mellon University
MontaVista Software                         Debian GNU/Linux Developer

2001-12-08  Daniel Jacobowitz  <drow@mvista.com>

	* cp-abi.c: Fix whitespace.
	(baseclass_offset): New wrapper function.
	* cp-abi.h (baseclass_offset): Add prototype.
	(struct cp_abi_ops): Add baseclass_offset pointer.

	* valops.c (vb_match): Move to...
	* gnu-v2-abi.c (vb_match): here.
	* valops.c (baseclass_offset): Move to...
	* gnu-v2-abi.c (gnuv2_baseclass_offset): here, and rename.

	* gnu-v3-abi.c (gnuv3_baseclass_offset): New function.

	* gnu-v2-abi.c (init_gnuv2_ops): Initialize baseclass_offset.
	* gnu-v3-abi.c (init_gnuv3_ops): Likewise.
	* hpacc-abi.c (init_hpacc_ops): Likewise.

Index: cp-abi.c
===================================================================
RCS file: /cvs/src/src/gdb/cp-abi.c,v
retrieving revision 1.2
diff -u -p -r1.2 cp-abi.c
--- cp-abi.c	2001/10/21 01:06:25	1.2
+++ cp-abi.c	2001/12/08 19:40:55
@@ -60,6 +60,15 @@ is_operator_name (const char *name)
   return (*current_cp_abi.is_operator_name) (name);
 }
 
+int
+baseclass_offset (struct type *type, int index, char *valaddr,
+		  CORE_ADDR address)
+{
+  if (current_cp_abi.baseclass_offset == NULL)
+    error ("ABI doesn't define required function baseclass_offset");
+  return (*current_cp_abi.baseclass_offset) (type, index, valaddr, address);
+}
+
 struct value *
 value_virtual_fn_field (struct value **arg1p, struct fn_field * f, int j,
 			struct type * type, int offset)
@@ -68,6 +77,7 @@ value_virtual_fn_field (struct value **a
     return NULL;
   return (*current_cp_abi.virtual_fn_field) (arg1p, f, j, type, offset);
 }
+
 struct type *
 value_rtti_type (struct value *v, int *full, int *top, int *using_enc)
 {
Index: cp-abi.h
===================================================================
RCS file: /cvs/src/src/gdb/cp-abi.h,v
retrieving revision 1.3
diff -u -p -r1.3 cp-abi.h
--- cp-abi.h	2001/10/21 01:06:25	1.3
+++ cp-abi.h	2001/12/08 19:40:55
@@ -132,7 +132,17 @@ extern struct value *value_virtual_fn_fi
 extern struct type *value_rtti_type (struct value *value,
                                      int *full, int *top, int *using_enc);
 
+/* Compute the offset of the baseclass which is
+   the INDEXth baseclass of class TYPE,
+   for value at VALADDR (in host) at ADDRESS (in target).
+   The result is the offset of the baseclass value relative
+   to (the address of)(ARG) + OFFSET.
 
+   -1 is returned on error. */
+
+extern int baseclass_offset (struct type *type, int index, char *valaddr,
+			     CORE_ADDR address);
+                  
 struct cp_abi_ops
 {
   const char *shortname;
@@ -148,6 +158,8 @@ struct cp_abi_ops
 				     int j, struct type * type, int offset);
   struct type *(*rtti_type) (struct value *v, int *full, int *top,
 			     int *using_enc);
+  int (*baseclass_offset) (struct type *type, int index, char *valaddr,
+			   CORE_ADDR address);
 };
 
 
Index: gnu-v2-abi.c
===================================================================
RCS file: /cvs/src/src/gdb/gnu-v2-abi.c,v
retrieving revision 1.5
diff -u -p -r1.5 gnu-v2-abi.c
--- gnu-v2-abi.c	2001/10/21 01:06:25	1.5
+++ gnu-v2-abi.c	2001/12/08 19:40:56
@@ -34,6 +34,8 @@
 struct cp_abi_ops gnu_v2_abi_ops;
 
 static int vb_match (struct type *, int, struct type *);
+int gnuv2_baseclass_offset (struct type *type, int index, char *valaddr,
+			    CORE_ADDR address);
 
 static enum dtor_kinds
 gnuv2_is_destructor_name (const char *name)
@@ -308,7 +310,101 @@ gnuv2_value_rtti_type (struct value *v, 
   return rtti_type;
 }
 
+/* Return true if the INDEXth field of TYPE is a virtual baseclass
+   pointer which is for the base class whose type is BASECLASS.  */
 
+static int
+vb_match (struct type *type, int index, struct type *basetype)
+{
+  struct type *fieldtype;
+  char *name = TYPE_FIELD_NAME (type, index);
+  char *field_class_name = NULL;
+
+  if (*name != '_')
+    return 0;
+  /* gcc 2.4 uses _vb$.  */
+  if (name[1] == 'v' && name[2] == 'b' && is_cplus_marker (name[3]))
+    field_class_name = name + 4;
+  /* gcc 2.5 will use __vb_.  */
+  if (name[1] == '_' && name[2] == 'v' && name[3] == 'b' && name[4] == '_')
+    field_class_name = name + 5;
+
+  if (field_class_name == NULL)
+    /* This field is not a virtual base class pointer.  */
+    return 0;
+
+  /* It's a virtual baseclass pointer, now we just need to find out whether
+     it is for this baseclass.  */
+  fieldtype = TYPE_FIELD_TYPE (type, index);
+  if (fieldtype == NULL
+      || TYPE_CODE (fieldtype) != TYPE_CODE_PTR)
+    /* "Can't happen".  */
+    return 0;
+
+  /* What we check for is that either the types are equal (needed for
+     nameless types) or have the same name.  This is ugly, and a more
+     elegant solution should be devised (which would probably just push
+     the ugliness into symbol reading unless we change the stabs format).  */
+  if (TYPE_TARGET_TYPE (fieldtype) == basetype)
+    return 1;
+
+  if (TYPE_NAME (basetype) != NULL
+      && TYPE_NAME (TYPE_TARGET_TYPE (fieldtype)) != NULL
+      && STREQ (TYPE_NAME (basetype),
+		TYPE_NAME (TYPE_TARGET_TYPE (fieldtype))))
+    return 1;
+  return 0;
+}
+
+/* Compute the offset of the baseclass which is
+   the INDEXth baseclass of class TYPE,
+   for value at VALADDR (in host) at ADDRESS (in target).
+   The result is the offset of the baseclass value relative
+   to (the address of)(ARG) + OFFSET.
+
+   -1 is returned on error. */
+
+int
+gnuv2_baseclass_offset (struct type *type, int index, char *valaddr,
+		  CORE_ADDR address)
+{
+  struct type *basetype = TYPE_BASECLASS (type, index);
+
+  if (BASETYPE_VIA_VIRTUAL (type, index))
+    {
+      /* Must hunt for the pointer to this virtual baseclass.  */
+      register int i, len = TYPE_NFIELDS (type);
+      register int n_baseclasses = TYPE_N_BASECLASSES (type);
+
+      /* First look for the virtual baseclass pointer
+         in the fields.  */
+      for (i = n_baseclasses; i < len; i++)
+	{
+	  if (vb_match (type, i, basetype))
+	    {
+	      CORE_ADDR addr
+	      = unpack_pointer (TYPE_FIELD_TYPE (type, i),
+				valaddr + (TYPE_FIELD_BITPOS (type, i) / 8));
+
+	      return addr - (LONGEST) address;
+	    }
+	}
+      /* Not in the fields, so try looking through the baseclasses.  */
+      for (i = index + 1; i < n_baseclasses; i++)
+	{
+	  int boffset =
+	  baseclass_offset (type, i, valaddr, address);
+	  if (boffset)
+	    return boffset;
+	}
+      /* Not found.  */
+      return -1;
+    }
+
+  /* Baseclass is easily computed.  */
+  return TYPE_BASECLASS_BITPOS (type, index) / 8;
+}
+
 static void
 init_gnuv2_ops (void)
 {
@@ -321,6 +417,7 @@ init_gnuv2_ops (void)
   gnu_v2_abi_ops.is_operator_name = gnuv2_is_operator_name;
   gnu_v2_abi_ops.virtual_fn_field = gnuv2_virtual_fn_field;
   gnu_v2_abi_ops.rtti_type = gnuv2_value_rtti_type;
+  gnu_v2_abi_ops.baseclass_offset = gnuv2_baseclass_offset;
 }
 
 void
Index: gnu-v3-abi.c
===================================================================
RCS file: /cvs/src/src/gdb/gnu-v3-abi.c,v
retrieving revision 1.5
diff -u -p -r1.5 gnu-v3-abi.c
--- gnu-v3-abi.c	2001/11/30 17:47:51	1.5
+++ gnu-v3-abi.c	2001/12/08 19:40:56
@@ -339,6 +339,66 @@ gnuv3_virtual_fn_field (struct value **v
   return vfn;
 }
 
+/* Compute the offset of the baseclass which is
+   the INDEXth baseclass of class TYPE,
+   for value at VALADDR (in host) at ADDRESS (in target).
+   The result is the offset of the baseclass value relative
+   to (the address of)(ARG) + OFFSET.
+
+   -1 is returned on error. */
+int
+gnuv3_baseclass_offset (struct type *type, int index, char *valaddr,
+			CORE_ADDR address)
+{
+  struct type *vtable_type = gdbarch_data (vtable_type_gdbarch_data);
+  struct type *basetype = TYPE_BASECLASS (type, index);
+  struct value *full_object, *vbase_object, *orig_object;
+  struct value *vtable, *orig_typeinfo, *orig_base_info;
+  struct type *orig_type, *vbasetype;
+  struct value *offset_val, *vbase_array;
+  CORE_ADDR vtable_address;
+  long int cur_base_offset, base_offset;
+  int to_top;
+  int baseclasses, i;
+
+  /* If it isn't a virtual base, this is easy.  The offset is in the
+     type definition.  */
+  if (!BASETYPE_VIA_VIRTUAL (type, index))
+    return TYPE_BASECLASS_BITPOS (type, index) / 8;
+
+  /* To access a virtual base, we need to use the vbase offset stored in
+     our vtable.  Recent GCC versions provide this information.  If it isn't
+     available, we could get what we needed from RTTI, or from drawing the
+     complete inheritance graph based on the debug info.  Neither is
+     worthwhile.  */
+  cur_base_offset = TYPE_BASECLASS_BITPOS (type, index) / 8;
+  if (cur_base_offset >= - vtable_address_point_offset ())
+    error ("Expected a negative vbase offset (old compiler?)");
+
+  cur_base_offset = cur_base_offset + vtable_address_point_offset ();
+  if ((- cur_base_offset) % TYPE_LENGTH (builtin_type_void_data_ptr) != 0)
+    error ("Misaligned vbase offset.");
+  cur_base_offset = cur_base_offset
+    / ((int) TYPE_LENGTH (builtin_type_void_data_ptr));
+
+  /* We're now looking for the cur_base_offset'th entry (negative index)
+     in the vcall_and_vbase_offsets array.  */
+
+  orig_object = value_at_lazy (type, address, NULL);
+  vbasetype = TYPE_VPTR_BASETYPE (VALUE_TYPE (orig_object));
+  vbase_object = value_cast (vbasetype, orig_object);
+
+  vtable_address
+    = value_as_address (value_field (vbase_object,
+				     TYPE_VPTR_FIELDNO (vbasetype)));
+  vtable = value_at_lazy (vtable_type,
+                          vtable_address - vtable_address_point_offset (),
+                          NULL);
+  offset_val = value_from_longest(builtin_type_int, cur_base_offset);
+  vbase_array = value_field (vtable, vtable_field_vcall_and_vbase_offsets);
+  base_offset = value_as_long (value_subscript (vbase_array, offset_val));
+  return base_offset;
+}
 
 static void
 init_gnuv3_ops (void)
@@ -354,6 +420,7 @@ init_gnuv3_ops (void)
   gnu_v3_abi_ops.is_operator_name = gnuv3_is_operator_name;
   gnu_v3_abi_ops.rtti_type = gnuv3_rtti_type;
   gnu_v3_abi_ops.virtual_fn_field = gnuv3_virtual_fn_field;
+  gnu_v3_abi_ops.baseclass_offset = gnuv3_baseclass_offset;
 }
 
 
Index: hpacc-abi.c
===================================================================
RCS file: /cvs/src/src/gdb/hpacc-abi.c,v
retrieving revision 1.2
diff -u -p -r1.2 hpacc-abi.c
--- hpacc-abi.c	2001/10/21 01:06:25	1.2
+++ hpacc-abi.c	2001/12/08 19:40:56
@@ -287,6 +287,8 @@ hpacc_value_rtti_type (struct value *v, 
   return rtti_type;
 }
 
+extern int gnuv2_baseclass_offset (struct type *type, int index,
+				   char *valaddr, CORE_ADDR address);
 
 static void
 init_hpacc_ops (void)
@@ -300,6 +302,11 @@ init_hpacc_ops (void)
   hpacc_abi_ops.is_operator_name = hpacc_is_operator_name;
   hpacc_abi_ops.virtual_fn_field = hpacc_virtual_fn_field;
   hpacc_abi_ops.rtti_type = hpacc_value_rtti_type;
+  /* It seems that this function is specific to GNU G++ < 3.0.
+     However, it is called for data members even in the HP
+     case (although not for member functions).
+     FIXME: Is that correct?  */
+  hpacc_abi_ops.baseclass_offset = gnuv2_baseclass_offset;
 }
 
 
Index: value.h
===================================================================
RCS file: /cvs/src/src/gdb/value.h,v
retrieving revision 1.22
diff -u -p -r1.22 value.h
--- value.h	2001/10/16 01:58:07	1.22
+++ value.h	2001/12/08 19:40:57
@@ -541,8 +541,6 @@ extern void clear_internalvars (void);
 
 extern value_ptr value_copy (value_ptr);
 
-extern int baseclass_offset (struct type *, int, char *, CORE_ADDR);
-
 /* From valops.c */
 
 extern value_ptr varying_to_slice (value_ptr);
Index: values.c
===================================================================
RCS file: /cvs/src/src/gdb/values.c,v
retrieving revision 1.29
diff -u -p -r1.29 values.c
--- values.c	2001/11/30 17:47:51	1.29
+++ values.c	2001/12/08 19:40:57
@@ -1077,101 +1077,6 @@ value_from_vtable_info (value_ptr arg, s
 
   return value_headof (arg, 0, type);
 }
-
-/* Return true if the INDEXth field of TYPE is a virtual baseclass
-   pointer which is for the base class whose type is BASECLASS.  */
-
-static int
-vb_match (struct type *type, int index, struct type *basetype)
-{
-  struct type *fieldtype;
-  char *name = TYPE_FIELD_NAME (type, index);
-  char *field_class_name = NULL;
-
-  if (*name != '_')
-    return 0;
-  /* gcc 2.4 uses _vb$.  */
-  if (name[1] == 'v' && name[2] == 'b' && is_cplus_marker (name[3]))
-    field_class_name = name + 4;
-  /* gcc 2.5 will use __vb_.  */
-  if (name[1] == '_' && name[2] == 'v' && name[3] == 'b' && name[4] == '_')
-    field_class_name = name + 5;
-
-  if (field_class_name == NULL)
-    /* This field is not a virtual base class pointer.  */
-    return 0;
-
-  /* It's a virtual baseclass pointer, now we just need to find out whether
-     it is for this baseclass.  */
-  fieldtype = TYPE_FIELD_TYPE (type, index);
-  if (fieldtype == NULL
-      || TYPE_CODE (fieldtype) != TYPE_CODE_PTR)
-    /* "Can't happen".  */
-    return 0;
-
-  /* What we check for is that either the types are equal (needed for
-     nameless types) or have the same name.  This is ugly, and a more
-     elegant solution should be devised (which would probably just push
-     the ugliness into symbol reading unless we change the stabs format).  */
-  if (TYPE_TARGET_TYPE (fieldtype) == basetype)
-    return 1;
-
-  if (TYPE_NAME (basetype) != NULL
-      && TYPE_NAME (TYPE_TARGET_TYPE (fieldtype)) != NULL
-      && STREQ (TYPE_NAME (basetype),
-		TYPE_NAME (TYPE_TARGET_TYPE (fieldtype))))
-    return 1;
-  return 0;
-}
-
-/* Compute the offset of the baseclass which is
-   the INDEXth baseclass of class TYPE,
-   for value at VALADDR (in host) at ADDRESS (in target).
-   The result is the offset of the baseclass value relative
-   to (the address of)(ARG) + OFFSET.
-
-   -1 is returned on error. */
-
-int
-baseclass_offset (struct type *type, int index, char *valaddr,
-		  CORE_ADDR address)
-{
-  struct type *basetype = TYPE_BASECLASS (type, index);
-
-  if (BASETYPE_VIA_VIRTUAL (type, index))
-    {
-      /* Must hunt for the pointer to this virtual baseclass.  */
-      register int i, len = TYPE_NFIELDS (type);
-      register int n_baseclasses = TYPE_N_BASECLASSES (type);
-
-      /* First look for the virtual baseclass pointer
-         in the fields.  */
-      for (i = n_baseclasses; i < len; i++)
-	{
-	  if (vb_match (type, i, basetype))
-	    {
-	      CORE_ADDR addr
-	      = unpack_pointer (TYPE_FIELD_TYPE (type, i),
-				valaddr + (TYPE_FIELD_BITPOS (type, i) / 8));
-
-	      return addr - (LONGEST) address;
-	    }
-	}
-      /* Not in the fields, so try looking through the baseclasses.  */
-      for (i = index + 1; i < n_baseclasses; i++)
-	{
-	  int boffset =
-	  baseclass_offset (type, i, valaddr, address);
-	  if (boffset)
-	    return boffset;
-	}
-      /* Not found.  */
-      return -1;
-    }
-
-  /* Baseclass is easily computed.  */
-  return TYPE_BASECLASS_BITPOS (type, index) / 8;
-}
 
 /* Unpack a field FIELDNO of the specified TYPE, from the anonymous object at
    VALADDR.


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