2009-11-12 Daniel Jacobowitz <dan@codesourcery.com>
authorDaniel Jacobowitz <drow@false.org>
Thu, 12 Nov 2009 19:47:25 +0000 (19:47 +0000)
committerDaniel Jacobowitz <drow@false.org>
Thu, 12 Nov 2009 19:47:25 +0000 (19:47 +0000)
    Paul Brook  <paul@codesourcery.com>

* c-typeprint.c (c_type_print_base): Skip artificial fields.
Use get_vptr_fieldno to skip the vtable pointer.
* dwarf2read.c (dwarf2_add_field): Set FIELD_ARTIFICIAL on artificial
fields.
(dwarf2_add_member_fn): Complain about virtual member functions
without DW_AT_vtable_elem_location and force TYPE_CPLUS_DYNAMIC.
* gdbtypes.c (get_vptr_fieldno): Update comment.
* gdbtypes.h (struct cplus_struct_type): Add is_dynamic.
(TYPE_CPLUS_DYNAMIC): New macro.
* gnu-v3-abi.c (gnuv3_dynamic_class): New.
(gnuv3_get_vtable): Rewrite to use gnuv3_dynamic_class.  Move higher.
(gnuv3_rtti_type, gnuv3_get_virtual_fn, gnuv3_baseclass_offset): Use
gnuv3_get_vtable.
* varobj.c (cplus_class_num_children, cplus_describe_child): Skip
artificial fields.  Use get_vptr_fieldno to skip the vtable pointer.

gdb/ChangeLog
gdb/c-typeprint.c
gdb/dwarf2read.c
gdb/gdbtypes.c
gdb/gdbtypes.h
gdb/gnu-v3-abi.c
gdb/varobj.c

index a2dbfaae42d531643a686ab2bc58baeeb4b4abd0..424383d308a0136ac329934b9c993a41888aed0f 100644 (file)
@@ -1,3 +1,22 @@
+2009-11-12  Daniel Jacobowitz  <dan@codesourcery.com>
+           Paul Brook  <paul@codesourcery.com>
+
+       * c-typeprint.c (c_type_print_base): Skip artificial fields.
+       Use get_vptr_fieldno to skip the vtable pointer.
+       * dwarf2read.c (dwarf2_add_field): Set FIELD_ARTIFICIAL on artificial
+       fields.
+       (dwarf2_add_member_fn): Complain about virtual member functions
+       without DW_AT_vtable_elem_location and force TYPE_CPLUS_DYNAMIC.
+       * gdbtypes.c (get_vptr_fieldno): Update comment.
+       * gdbtypes.h (struct cplus_struct_type): Add is_dynamic.
+       (TYPE_CPLUS_DYNAMIC): New macro.
+       * gnu-v3-abi.c (gnuv3_dynamic_class): New.
+       (gnuv3_get_vtable): Rewrite to use gnuv3_dynamic_class.  Move higher.
+       (gnuv3_rtti_type, gnuv3_get_virtual_fn, gnuv3_baseclass_offset): Use
+       gnuv3_get_vtable.
+       * varobj.c (cplus_class_num_children, cplus_describe_child): Skip
+       artificial fields.  Use get_vptr_fieldno to skip the vtable pointer.
+
 2009-11-12  Paul Brook  <paul@codesourcery.com>
            Daniel Jacobowitz  <dan@codesourcery.com>
 
index 807eec16781d4eae9a2c1321284c4cd1354245c4..a984e3ffccadb806ccb62d4bff6f44805a3ebd22 100644 (file)
@@ -761,6 +761,9 @@ c_type_print_base (struct type *type, struct ui_file *stream, int show,
        }
       else if (show > 0 || TYPE_TAG_NAME (type) == NULL)
        {
+         struct type *basetype;
+         int vptr_fieldno;
+
          cp_type_print_derivation_info (stream, type);
 
          fprintf_filtered (stream, "{\n");
@@ -848,12 +851,16 @@ c_type_print_base (struct type *type, struct ui_file *stream, int show,
             do not print the field that it occupies.  */
 
          len = TYPE_NFIELDS (type);
+         vptr_fieldno = get_vptr_fieldno (type, &basetype);
          for (i = TYPE_N_BASECLASSES (type); i < len; i++)
            {
              QUIT;
-             /* Don't print out virtual function table.  */
-             if (strncmp (TYPE_FIELD_NAME (type, i), "_vptr", 5) == 0
-                 && is_cplus_marker ((TYPE_FIELD_NAME (type, i))[5]))
+
+             /* If we have a virtual table pointer, omit it.  Even if
+                virtual table pointers are not specifically marked in
+                the debug info, they should be artificial.  */
+             if ((type == basetype && i == vptr_fieldno)
+                 || TYPE_FIELD_ARTIFICIAL (type, i))
                continue;
 
              /* If this is a C++ class we can print the various C++ section
index 381350fe2879ef61c01c489783ed9d44cb7b4dc3..2f6e522f3f0e5f8ce8d73bb14bcae2bf3d4d8163 100644 (file)
@@ -4484,6 +4484,7 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die,
          pointer or virtual base class pointer) to private.  */
       if (dwarf2_attr (die, DW_AT_artificial, cu))
        {
+         FIELD_ARTIFICIAL (*fp) = 1;
          new_field->accessibility = DW_ACCESS_private;
          fip->non_public_fields = 1;
        }
@@ -4803,6 +4804,18 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die,
       else
        dwarf2_complex_location_expr_complaint ();
     }
+  else
+    {
+      attr = dwarf2_attr (die, DW_AT_virtuality, cu);
+      if (attr && DW_UNSND (attr))
+       {
+         /* GCC does this, as of 2008-08-25; PR debug/37237.  */
+         complaint (&symfile_complaints,
+                    _("Member function \"%s\" (offset %d) is virtual but the vtable offset is not specified"),
+                    fieldname, die->offset);
+         TYPE_CPLUS_DYNAMIC (type) = 1;
+       }
+    }
 }
 
 /* Create the vector of member function fields, and attach it to the type.  */
index 299d0c515a259c6bff147b7901b0f869a144149b..ac126cd7b13ba637bd898672ba50b414133bb0df 100644 (file)
@@ -1277,7 +1277,8 @@ lookup_struct_elt_type (struct type *type, char *name, int noerr)
    If not found, return -1 and ignore BASETYPEP.
    Callers should be aware that in some cases (for example,
    the type or one of its baseclasses is a stub type and we are
-   debugging a .o file), this function will not be able to find the
+   debugging a .o file, or the compiler uses DWARF-2 and is not GCC),
+   this function will not be able to find the
    virtual function table pointer, and vptr_fieldno will remain -1 and
    vptr_basetype will remain NULL or incomplete.  */
 
index be6ed55236387dd092c3f6c4fe798c0ad415bf96..451a94a79496f44560d580f9a6145c88c2aafe6d 100644 (file)
@@ -775,6 +775,13 @@ struct cplus_struct_type
        int line;
       }
      *localtype_ptr;
+
+    /* One if this struct is a dynamic class, as defined by the
+       Itanium C++ ABI: if it requires a virtual table pointer,
+       because it or any of its base classes have one or more virtual
+       member functions or virtual base classes.  Minus one if not
+       dynamic.  Zero if not yet computed.  */
+    int is_dynamic : 2;
   };
 
 /* Struct used in computing virtual base list */
@@ -861,6 +868,7 @@ extern void allocate_cplus_struct_type (struct type *);
 #define TYPE_BASECLASS_BITPOS(thistype,index) TYPE_FIELD_BITPOS(thistype,index)
 #define BASETYPE_VIA_PUBLIC(thistype, index) \
   ((!TYPE_FIELD_PRIVATE(thistype, index)) && (!TYPE_FIELD_PROTECTED(thistype, index)))
+#define TYPE_CPLUS_DYNAMIC(thistype) TYPE_CPLUS_SPECIFIC (thistype)->is_dynamic
 
 #define BASETYPE_VIA_VIRTUAL(thistype, index) \
   (TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits == NULL ? 0 \
index 0f9d44efc0def3e54e3856fedca1617706ab846b..7e4cb23028a0f1c732380b0641ffe8dc860d52f9 100644 (file)
@@ -190,23 +190,96 @@ vtable_address_point_offset (struct gdbarch *gdbarch)
 }
 
 
+/* Determine whether structure TYPE is a dynamic class.  Cache the
+   result.  */
+
+static int
+gnuv3_dynamic_class (struct type *type)
+{
+  int fieldnum, fieldelem;
+
+  if (TYPE_CPLUS_DYNAMIC (type))
+    return TYPE_CPLUS_DYNAMIC (type) == 1;
+
+  ALLOCATE_CPLUS_STRUCT_TYPE (type);
+
+  for (fieldnum = 0; fieldnum < TYPE_N_BASECLASSES (type); fieldnum++)
+    if (BASETYPE_VIA_VIRTUAL (type, fieldnum)
+       || gnuv3_dynamic_class (TYPE_FIELD_TYPE (type, fieldnum)))
+      {
+       TYPE_CPLUS_DYNAMIC (type) = 1;
+       return 1;
+      }
+
+  for (fieldnum = 0; fieldnum < TYPE_NFN_FIELDS (type); fieldnum++)
+    for (fieldelem = 0; fieldelem < TYPE_FN_FIELDLIST_LENGTH (type, fieldnum);
+        fieldelem++)
+      {
+       struct fn_field *f = TYPE_FN_FIELDLIST1 (type, fieldnum);
+
+       if (TYPE_FN_FIELD_VIRTUAL_P (f, fieldelem))
+         {
+           TYPE_CPLUS_DYNAMIC (type) = 1;
+           return 1;
+         }
+      }
+
+  TYPE_CPLUS_DYNAMIC (type) = -1;
+  return 0;
+}
+
+/* Find the vtable for a value of CONTAINER_TYPE located at
+   CONTAINER_ADDR.  Return a value of the correct vtable type for this
+   architecture, or NULL if CONTAINER does not have a vtable.  */
+
+static struct value *
+gnuv3_get_vtable (struct gdbarch *gdbarch,
+                 struct type *container_type, CORE_ADDR container_addr)
+{
+  struct type *vtable_type = gdbarch_data (gdbarch,
+                                          vtable_type_gdbarch_data);
+  struct type *vtable_pointer_type;
+  struct value *vtable_pointer;
+  CORE_ADDR vtable_address;
+
+  /* If this type does not have a virtual table, don't read the first
+     field.  */
+  if (!gnuv3_dynamic_class (check_typedef (container_type)))
+    return NULL;
+
+  /* We do not consult the debug information to find the virtual table.
+     The ABI specifies that it is always at offset zero in any class,
+     and debug information may not represent it.
+
+     We avoid using value_contents on principle, because the object might
+     be large.  */
+
+  /* Find the type "pointer to virtual table".  */
+  vtable_pointer_type = lookup_pointer_type (vtable_type);
+
+  /* Load it from the start of the class.  */
+  vtable_pointer = value_at (vtable_pointer_type, container_addr);
+  vtable_address = value_as_address (vtable_pointer);
+
+  /* Correct it to point at the start of the virtual table, rather
+     than the address point.  */
+  return value_at_lazy (vtable_type,
+                       vtable_address - vtable_address_point_offset (gdbarch));
+}
+
+
 static struct type *
 gnuv3_rtti_type (struct value *value,
                  int *full_p, int *top_p, int *using_enc_p)
 {
   struct gdbarch *gdbarch;
-  struct type *vtable_type;
   struct type *values_type = check_typedef (value_type (value));
-  CORE_ADDR vtable_address;
   struct value *vtable;
   struct minimal_symbol *vtable_symbol;
   const char *vtable_symbol_name;
   const char *class_name;
   struct type *run_time_type;
-  struct type *base_type;
   LONGEST offset_to_top;
-  struct type *values_type_vptr_basetype;
-  int values_type_vptr_fieldno;
 
   /* We only have RTTI for class objects.  */
   if (TYPE_CODE (values_type) != TYPE_CODE_CLASS)
@@ -214,33 +287,15 @@ gnuv3_rtti_type (struct value *value,
 
   /* Determine architecture.  */
   gdbarch = get_type_arch (values_type);
-  vtable_type = gdbarch_data (gdbarch, vtable_type_gdbarch_data);
-
-  /* If we can't find the virtual table pointer for values_type, we
-     can't find the RTTI.  */
-  values_type_vptr_fieldno = get_vptr_fieldno (values_type,
-                                              &values_type_vptr_basetype);
-  if (values_type_vptr_fieldno == -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.  */
-  base_type = check_typedef (values_type_vptr_basetype);
-  if (values_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, values_type_vptr_fieldno));
-  vtable
-    = value_at_lazy (vtable_type,
-                    vtable_address - vtable_address_point_offset (gdbarch));
-  
+  vtable = gnuv3_get_vtable (gdbarch, value_type (value),
+                            value_as_address (value_addr (value)));
+  if (vtable == NULL)
+    return NULL;
+
   /* Find the linker symbol for this vtable.  */
   vtable_symbol
     = lookup_minimal_symbol_by_pc (value_address (vtable)
@@ -282,45 +337,9 @@ gnuv3_rtti_type (struct value *value,
                    >= TYPE_LENGTH (run_time_type)));
   if (top_p)
     *top_p = - offset_to_top;
-
   return run_time_type;
 }
 
-/* Find the vtable for CONTAINER and return a value of the correct
-   vtable type for this architecture.  */
-
-static struct value *
-gnuv3_get_vtable (struct gdbarch *gdbarch, struct value *container)
-{
-  struct type *vtable_type = gdbarch_data (gdbarch, vtable_type_gdbarch_data);
-  struct type *vtable_pointer_type;
-  struct value *vtable_pointer;
-  CORE_ADDR vtable_pointer_address, vtable_address;
-
-  /* We do not consult the debug information to find the virtual table.
-     The ABI specifies that it is always at offset zero in any class,
-     and debug information may not represent it.  We won't issue an
-     error if there's a class with virtual functions but no virtual table
-     pointer, but something's already gone seriously wrong if that
-     happens.
-
-     We avoid using value_contents on principle, because the object might
-     be large.  */
-
-  /* Find the type "pointer to virtual table".  */
-  vtable_pointer_type = lookup_pointer_type (vtable_type);
-
-  /* Load it from the start of the class.  */
-  vtable_pointer_address = value_as_address (value_addr (container));
-  vtable_pointer = value_at (vtable_pointer_type, vtable_pointer_address);
-  vtable_address = value_as_address (vtable_pointer);
-
-  /* Correct it to point at the start of the virtual table, rather
-     than the address point.  */
-  return value_at_lazy (vtable_type,
-                       vtable_address - vtable_address_point_offset (gdbarch));
-}
-
 /* Return a function pointer for CONTAINER's VTABLE_INDEX'th virtual
    function, of type FNTYPE.  */
 
@@ -328,8 +347,12 @@ static struct value *
 gnuv3_get_virtual_fn (struct gdbarch *gdbarch, struct value *container,
                      struct type *fntype, int vtable_index)
 {
-  struct value *vtable = gnuv3_get_vtable (gdbarch, container);
-  struct value *vfn;
+  struct value *vtable, *vfn;
+
+  /* Every class with virtual functions must have a vtable.  */
+  vtable = gnuv3_get_vtable (gdbarch, value_type (container),
+                            value_as_address (value_addr (container)));
+  gdb_assert (vtable != NULL);
 
   /* Fetch the appropriate function pointer from the vtable.  */
   vfn = value_subscript (value_field (vtable, vtable_field_virtual_functions),
@@ -389,18 +412,13 @@ gnuv3_baseclass_offset (struct type *type, int index, const bfd_byte *valaddr,
                        CORE_ADDR address)
 {
   struct gdbarch *gdbarch;
-  struct type *vtable_type;
   struct type *ptr_type;
   struct value *vtable;
-  struct type *vbasetype;
   struct value *vbase_array;
-  CORE_ADDR vtable_address;
   long int cur_base_offset, base_offset;
-  int vbasetype_vptr_fieldno;
 
   /* Determine architecture.  */
   gdbarch = get_type_arch (type);
-  vtable_type = gdbarch_data (gdbarch, vtable_type_gdbarch_data);
   ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
 
   /* If it isn't a virtual base, this is easy.  The offset is in the
@@ -422,29 +440,8 @@ gnuv3_baseclass_offset (struct type *type, int index, const bfd_byte *valaddr,
     error (_("Misaligned vbase offset."));
   cur_base_offset = cur_base_offset / ((int) TYPE_LENGTH (ptr_type));
 
-  /* We're now looking for the cur_base_offset'th entry (negative index)
-     in the vcall_and_vbase_offsets array.  We used to cast the object to
-     its TYPE_VPTR_BASETYPE, and reference the vtable as TYPE_VPTR_FIELDNO;
-     however, that cast can not be done without calling baseclass_offset again
-     if the TYPE_VPTR_BASETYPE is a virtual base class, as described in the
-     v3 C++ ABI Section 2.4.I.2.b.  Fortunately the ABI guarantees that the
-     vtable pointer will be located at the beginning of the object, so we can
-     bypass the casting.  Verify that the TYPE_VPTR_FIELDNO is in fact at the
-     start of whichever baseclass it resides in, as a sanity measure - iff
-     we have debugging information for that baseclass.  */
-
-  vbasetype = check_typedef (TYPE_VPTR_BASETYPE (type));
-  vbasetype_vptr_fieldno = get_vptr_fieldno (vbasetype, NULL);
-
-  if (vbasetype_vptr_fieldno >= 0
-      && TYPE_FIELD_BITPOS (vbasetype, vbasetype_vptr_fieldno) != 0)
-    error (_("Illegal vptr offset in class %s"),
-          TYPE_NAME (vbasetype) ? TYPE_NAME (vbasetype) : "<unknown>");
-
-  vtable_address = value_as_address (value_at_lazy (ptr_type, address));
-  vtable
-    = value_at_lazy (vtable_type,
-                    vtable_address - vtable_address_point_offset (gdbarch));
+  vtable = gnuv3_get_vtable (gdbarch, type, address);
+  gdb_assert (vtable != NULL);
   vbase_array = value_field (vtable, vtable_field_vcall_and_vbase_offsets);
   base_offset = value_as_long (value_subscript (vbase_array, cur_base_offset));
   return base_offset;
index 8f22156e2600761e465f232aded9d740b87efa56..2e4cf43ca65daf15543c009754d191b11a2a73c9 100644 (file)
@@ -3103,16 +3103,21 @@ cplus_number_of_children (struct varobj *var)
 static void
 cplus_class_num_children (struct type *type, int children[3])
 {
-  int i;
+  int i, vptr_fieldno;
+  struct type *basetype = NULL;
 
   children[v_public] = 0;
   children[v_private] = 0;
   children[v_protected] = 0;
 
+  vptr_fieldno = get_vptr_fieldno (type, &basetype);
   for (i = TYPE_N_BASECLASSES (type); i < TYPE_NFIELDS (type); i++)
     {
-      /* If we have a virtual table pointer, omit it. */
-      if (TYPE_VPTR_BASETYPE (type) == type && TYPE_VPTR_FIELDNO (type) == i)
+      /* If we have a virtual table pointer, omit it.  Even if virtual
+        table pointers are not specifically marked in the debug info,
+        they should be artificial.  */
+      if ((type == basetype && i == vptr_fieldno)
+         || TYPE_FIELD_ARTIFICIAL (type, i))
        continue;
 
       if (TYPE_FIELD_PROTECTED (type, i))
@@ -3199,6 +3204,10 @@ cplus_describe_child (struct varobj *parent, int index,
             find the indexed field. */
          int type_index = TYPE_N_BASECLASSES (type);
          enum accessibility acc = public_field;
+         int vptr_fieldno;
+         struct type *basetype = NULL;
+
+         vptr_fieldno = get_vptr_fieldno (type, &basetype);
          if (strcmp (parent->name, "private") == 0)
            acc = private_field;
          else if (strcmp (parent->name, "protected") == 0)
@@ -3206,8 +3215,8 @@ cplus_describe_child (struct varobj *parent, int index,
 
          while (index >= 0)
            {
-             if (TYPE_VPTR_BASETYPE (type) == type
-                 && type_index == TYPE_VPTR_FIELDNO (type))
+             if ((type == basetype && type_index == vptr_fieldno)
+                 || TYPE_FIELD_ARTIFICIAL (type, type_index))
                ; /* ignore vptr */
              else if (match_accessibility (type, type_index, acc))
                    --index;