* gdbarch.sh (gdbarch_data): Add gdbarch parameter.
[deliverable/binutils-gdb.git] / gdb / gnu-v3-abi.c
index bffdca56b95a759d769fe4a1123b0428ece259ab..e86af89d55727a56cceee944d61cf7956fb02698 100644 (file)
@@ -1,6 +1,7 @@
 /* Abstraction of GNU v3 abi.
    Contributed by Jim Blandy <jimb@redhat.com>
-   Copyright 2001 Free Software Foundation, Inc.
+
+   Copyright 2001, 2002 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -174,7 +175,8 @@ build_gdb_vtable_type (struct gdbarch *arch)
 static int
 vtable_address_point_offset ()
 {
-  struct type *vtable_type = gdbarch_data (vtable_type_gdbarch_data);
+  struct type *vtable_type = gdbarch_data (current_gdbarch,
+                                          vtable_type_gdbarch_data);
 
   return (TYPE_FIELD_BITPOS (vtable_type, vtable_field_virtual_functions)
           / TARGET_CHAR_BIT);
@@ -185,7 +187,8 @@ static struct type *
 gnuv3_rtti_type (struct value *value,
                  int *full_p, int *top_p, int *using_enc_p)
 {
-  struct type *vtable_type = gdbarch_data (vtable_type_gdbarch_data);
+  struct type *vtable_type = gdbarch_data (current_gdbarch,
+                                          vtable_type_gdbarch_data);
   struct type *value_type = check_typedef (VALUE_TYPE (value));
   CORE_ADDR vtable_address;
   struct value *vtable;
@@ -194,6 +197,7 @@ gnuv3_rtti_type (struct value *value,
   const char *class_name;
   struct symbol *class_symbol;
   struct type *run_time_type;
+  struct type *base_type;
   LONGEST offset_to_top;
 
   /* We only have RTTI for class objects.  */
@@ -206,8 +210,18 @@ gnuv3_rtti_type (struct value *value,
   if (TYPE_VPTR_FIELDNO (value_type) == -1)
     return NULL;
 
+  if (using_enc_p)
+    *using_enc_p = 0;
+
   /* Fetch VALUE's virtual table pointer, and tweak it to point at
-     an instance of our imaginary gdb_gnu_v3_abi_vtable structure.   */
+     an instance of our imaginary gdb_gnu_v3_abi_vtable structure.  */
+  base_type = check_typedef (TYPE_VPTR_BASETYPE (value_type));
+  if (value_type != base_type)
+    {
+      value = value_cast (base_type, value);
+      if (using_enc_p)
+       *using_enc_p = 1;
+    }
   vtable_address
     = value_as_address (value_field (value, TYPE_VPTR_FIELDNO (value_type)));
   vtable = value_at_lazy (vtable_type,
@@ -228,23 +242,35 @@ gnuv3_rtti_type (struct value *value,
      type_info object itself to get the class name.  But this way
      should work just as well, and doesn't read target memory.  */
   vtable_symbol_name = SYMBOL_DEMANGLED_NAME (vtable_symbol);
-  if (strncmp (vtable_symbol_name, "vtable for ", 11))
-    error ("can't find linker symbol for virtual table for `%s' value",
-           TYPE_NAME (value_type));
+  if (vtable_symbol_name == NULL
+      || strncmp (vtable_symbol_name, "vtable for ", 11))
+    {
+      warning ("can't find linker symbol for virtual table for `%s' value",
+              TYPE_NAME (value_type));
+      if (vtable_symbol_name)
+       warning ("  found `%s' instead", vtable_symbol_name);
+      return NULL;
+    }
   class_name = vtable_symbol_name + 11;
 
   /* Try to look up the class name as a type name.  */
   class_symbol = lookup_symbol (class_name, 0, STRUCT_NAMESPACE, 0, 0);
   if (! class_symbol)
-    error ("can't find class named `%s', as given by C++ RTTI", class_name);
+    {
+      warning ("can't find class named `%s', as given by C++ RTTI", class_name);
+      return NULL;
+    }
 
   /* Make sure the type symbol is sane.  (An earlier version of this
      code would find constructor functions, who have the same name as
      the class.)  */
   if (SYMBOL_CLASS (class_symbol) != LOC_TYPEDEF
       || TYPE_CODE (SYMBOL_TYPE (class_symbol)) != TYPE_CODE_CLASS)
-    error ("C++ RTTI gives a class name of `%s', but that isn't a type name",
-           class_name);
+    {
+      warning ("C++ RTTI gives a class name of `%s', but that isn't a type name",
+              class_name);
+      return NULL;
+    }
 
   /* This is the object's run-time type!  */
   run_time_type = SYMBOL_TYPE (class_symbol);
@@ -260,8 +286,6 @@ gnuv3_rtti_type (struct value *value,
                    >= TYPE_LENGTH (run_time_type)));
   if (top_p)
     *top_p = - offset_to_top;
-  if (using_enc_p)
-    *using_enc_p = 0;
 
   return run_time_type;
 }
@@ -272,7 +296,8 @@ gnuv3_virtual_fn_field (struct value **value_p,
                         struct fn_field *f, int j,
                        struct type *type, int offset)
 {
-  struct type *vtable_type = gdbarch_data (vtable_type_gdbarch_data);
+  struct type *vtable_type = gdbarch_data (current_gdbarch,
+                                          vtable_type_gdbarch_data);
   struct value *value = *value_p;
   struct type *value_type = check_typedef (VALUE_TYPE (value));
   struct type *vfn_base;
@@ -303,15 +328,19 @@ gnuv3_virtual_fn_field (struct value **value_p,
      function, cast our value to that baseclass.  This takes care of
      any necessary `this' adjustments.  */
   if (vfn_base != value_type)
-    /* It would be nicer to simply cast the value to the appropriate
-       base class (and I think that is supposed to be legal), but
-       value_cast only does the right magic when casting pointers.  */
-    value = value_ind (value_cast (vfn_base, value_addr (value)));
+    value = value_cast (vfn_base, value);
 
   /* Now value is an object of the appropriate base type.  Fetch its
      virtual table.  */
+  /* It might be possible to do this cast at the same time as the above.
+     Does multiple inheritance affect this?
+     Can this even trigger, or is TYPE_VPTR_BASETYPE idempotent?
+  */
+  if (TYPE_VPTR_BASETYPE (vfn_base) != vfn_base)
+    value = value_cast (TYPE_VPTR_BASETYPE (vfn_base), value);
   vtable_address
     = value_as_address (value_field (value, TYPE_VPTR_FIELDNO (vfn_base)));
+
   vtable = value_at_lazy (vtable_type,
                           vtable_address - vtable_address_point_offset (),
                           VALUE_BFD_SECTION (value));
@@ -325,9 +354,74 @@ gnuv3_virtual_fn_field (struct value **value_p,
   vfn = value_cast (lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j)),
                     vfn);
 
+  /* Is (type)value always numerically the same as (vfn_base)value?
+     If so we can spare this cast and use one of the ones above.  */
+  *value_p = value_addr (value_cast (type, *value_p));
+
   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 (current_gdbarch,
+                                          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)
@@ -343,6 +437,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;
 }
 
 
This page took 0.025146 seconds and 4 git commands to generate.