* gnu-v3-abi.c (gnuv3_rtti_type): Guard that vtable_symbol_name
[deliverable/binutils-gdb.git] / gdb / gnu-v3-abi.c
index 015bead1b8090625769b4fb22760b6b58f9727aa..a4c79605000cd8bf3a5fd50759ace436af913960 100644 (file)
@@ -23,6 +23,7 @@
 #include "value.h"
 #include "cp-abi.h"
 #include "demangle.h"
+#include "gdb_assert.h"
 
 static struct cp_abi_ops gnu_v3_abi_ops;
 
@@ -156,8 +157,7 @@ build_gdb_vtable_type (struct gdbarch *arch)
   field++;
 
   /* We assumed in the allocation above that there were four fields.  */
-  if (field != field_list + 4)
-    abort ();
+  gdb_assert (field == (field_list + 4));
 
   t = init_type (TYPE_CODE_STRUCT, offset, 0, 0, 0);
   TYPE_NFIELDS (t) = field - field_list;
@@ -194,6 +194,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,10 +207,20 @@ 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_pointer (value_field (value, TYPE_VPTR_FIELDNO (value_type)));
+    = value_as_address (value_field (value, TYPE_VPTR_FIELDNO (value_type)));
   vtable = value_at_lazy (vtable_type,
                           vtable_address - vtable_address_point_offset (),
                           VALUE_BFD_SECTION (value));
@@ -228,7 +239,8 @@ 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))
+  if (vtable_symbol_name == NULL
+      || strncmp (vtable_symbol_name, "vtable for ", 11))
     error ("can't find linker symbol for virtual table for `%s' value",
            TYPE_NAME (value_type));
   class_name = vtable_symbol_name + 11;
@@ -260,8 +272,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;
 }
@@ -303,15 +313,17 @@ 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?  */
+  if (TYPE_VPTR_BASETYPE (vfn_base) != vfn_base)
+    value = value_cast (TYPE_VPTR_BASETYPE (vfn_base), value);
   vtable_address
-    = value_as_pointer (value_field (value, TYPE_VPTR_FIELDNO (vfn_base)));
+    = 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));
@@ -328,6 +340,66 @@ gnuv3_virtual_fn_field (struct value **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 (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 +415,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.025963 seconds and 4 git commands to generate.