]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
DWARF and C++ ABI constructor/destructor enhancements.
authorKeith Seitz <keiths@redhat.com>
Tue, 21 Feb 2017 21:32:53 +0000 (13:32 -0800)
committerKeith Seitz <keiths@redhat.com>
Tue, 21 Feb 2017 21:32:53 +0000 (13:32 -0800)
This patch primarily adds support for recording constructor and destructor
kinds for the relevant types.

gdb/ChangeLog

gdb/cp-abi.h
gdb/dwarf2read.c
gdb/gdbtypes.h
gdb/gnu-v2-abi.c
gdb/gnu-v3-abi.c

index 6b82eacd01e6b9429035ee574d1688da8267721e..968f92cbaa0c23b0ff377cecb24285a16aa2ca82 100644 (file)
@@ -39,15 +39,24 @@ struct frame_info;
    non-zero.  */
 enum ctor_kinds {
 
+  /* Unrecognized or not a constructor.  */
+  not_ctor = 0,
+
   /* Initialize a complete object, including virtual bases, using
      memory provided by caller.  */
-  complete_object_ctor = 1,
+  complete_object_ctor,
 
   /* Initialize a base object of some larger object.  */
   base_object_ctor,
 
   /* An allocating complete-object constructor.  */
-  complete_object_allocating_ctor
+  complete_object_allocating_ctor,
+
+  /* GCC's "unified" constructor.  */
+  unified_ctor,
+
+  /* Deprecated?  */
+  object_ctor_group
 };
 
 /* Return non-zero iff NAME is the mangled name of a constructor.
@@ -60,9 +69,12 @@ extern enum ctor_kinds is_constructor_name (const char *name);
    non-zero.  */
 enum dtor_kinds {
 
+  /* Unrecognized or not a destructor.  */
+  not_dtor = 0,
+
   /* A destructor which finalizes the entire object, and then calls
      `delete' on its storage.  */
-  deleting_dtor = 1,
+  deleting_dtor,
 
   /* A destructor which finalizes the entire object, but does not call
      `delete'.  */
@@ -70,7 +82,13 @@ enum dtor_kinds {
 
   /* A destructor which finalizes a subobject of some larger
      object.  */
-  base_object_dtor
+  base_object_dtor,
+
+  /* GCC's "unified" destructor.  */
+  unified_dtor,
+
+  /* Deprecated?  */
+  object_dtor_group
 };
   
 /* Return non-zero iff NAME is the mangled name of a destructor.
index 2e2c58d0dbfec80b0c47754364fa65d2848d27df..b697b3f17efa5ea722be979961fb1ea7ec085af0 100644 (file)
@@ -13096,6 +13096,15 @@ dwarf2_is_constructor (struct die_info *die, struct dwarf2_cu *cu)
   const char *type_name;
   int len;
 
+  /* If there is a linkage name, use it to determine if this DIE represents
+     a constructor.  */
+  const char *linkage_name = dw2_linkage_name (die, cu);
+
+  if (linkage_name != NULL)
+    return is_constructor_name (linkage_name) != not_ctor;
+
+  /* Many older versions of GCC do not output DW_AT_linkage_name for
+     constructors.  In that case, fallback to a heuristic test.  */
   if (die->parent == NULL)
     return 0;
 
@@ -13114,6 +13123,32 @@ dwarf2_is_constructor (struct die_info *die, struct dwarf2_cu *cu)
          && (type_name[len] == '\0' || type_name[len] == '<'));
 }
 
+/* Return true if this member function is a destructor, false
+   otherwise.  */
+
+static int
+dwarf2_is_destructor (struct die_info *die, struct dwarf2_cu *cu)
+{
+  /* If there is a linkage name, use it to determine if this DIE represents
+     a destructor.  */
+  const char *linkage_name = dw2_linkage_name (die, cu);
+
+  if (linkage_name != NULL)
+    return is_destructor_name (linkage_name) != not_dtor;
+
+  if (die->parent == NULL)
+    return 0;
+
+  if (die->parent->tag != DW_TAG_structure_type
+      && die->parent->tag != DW_TAG_union_type
+      && die->parent->tag != DW_TAG_class_type)
+    return 0;
+
+  const char *fieldname = dwarf2_name (die, cu);
+
+  return (fieldname != NULL && *fieldname == '~');
+}
+
 /* Create a new fn_field which may represent an alias to an existing
    field (if a constructor or destructor).  TYPE_DIE and TYPE_CU
    may be NULL, in which case they default to NAME_DIE and NAME_CU,
@@ -13211,6 +13246,30 @@ new_fn_field (struct die_info *name_die, struct dwarf2_cu *name_cu,
     fnfield.is_artificial = 1;
 
   fnfield.is_constructor = dwarf2_is_constructor (name_die, type_cu);
+  if (fnfield.is_constructor)
+    {
+      const char *linkage_name = dw2_linkage_name (name_die, name_cu);
+
+      if (linkage_name != NULL)
+       {
+         fnfield.cdtor_type.ctor_kind = is_constructor_name (linkage_name);
+         gdb_assert (fnfield.cdtor_type.ctor_kind != not_ctor);
+       }
+    }
+  else
+    {
+      fnfield.is_destructor = dwarf2_is_destructor (name_die, name_cu);
+      if (fnfield.is_destructor)
+       {
+         const char *linkage_name = dw2_linkage_name (name_die, name_cu);
+
+         if (linkage_name != NULL)
+           {
+             fnfield.cdtor_type.dtor_kind = is_destructor_name (linkage_name);
+             gdb_assert (fnfield.cdtor_type.dtor_kind != not_dtor);
+           }
+       }
+    }
 
   /* Get index in virtual function table if it is a virtual member
      function.  For older versions of GCC, this is an offset in the
index b8910dcb0475cafdb4affa8575676a97094fe0cf..12e3841ca99756fef7145b8a02bc92e72998db4c 100644 (file)
@@ -45,6 +45,7 @@
  */
 
 #include "hashtab.h"
+#include "cp-abi.h"
 
 /* Forward declarations for prototypes.  */
 struct field;
@@ -833,6 +834,18 @@ struct fn_field
 
   struct type *fcontext;
 
+  /* If this method is a constructor or destructor, this field will describe
+     what kind of constructor or destructor it is.  */
+
+  union
+  {
+    /* The type of this constructor if IS_CONSTRUCTOR.  */
+    enum ctor_kinds ctor_kind;
+
+    /* The type of this destructor if IS_DESTRUCTOR.  */
+    enum dtor_kinds dtor_kind;
+  } cdtor_type;
+
   /* Attributes.  */
 
   unsigned int is_const:1;
@@ -856,9 +869,18 @@ struct fn_field
 
   unsigned int is_constructor : 1;
 
+  /* * True if this function is a destructor, false otherwise.  */
+
+  unsigned int is_destructor : 1;
+
+  /* * True if this function is aliased to an existing fn_field,
+     false otherwise.  These functions should be skipped during symbol
+     lookups or type printing.  */
+  unsigned int is_duplicate : 1;
+
   /* * Unused.  */
 
-  unsigned int dummy:3;
+  unsigned int dummy:1;
 
   /* * Index into that baseclass's virtual function table, minus 2;
      else if static: VOFFSET_STATIC; else: 0.  */
@@ -1427,6 +1449,7 @@ extern void set_type_vptr_basetype (struct type *, struct type *);
 #define TYPE_FN_FIELD_ABSTRACT(thisfn, n) ((thisfn)[n].is_abstract)
 #define TYPE_FN_FIELD_STUB(thisfn, n) ((thisfn)[n].is_stub)
 #define TYPE_FN_FIELD_CONSTRUCTOR(thisfn, n) ((thisfn)[n].is_constructor)
+#define TYPE_FN_FIELD_DESTRUCTOR(thisfn, n) ((thisfn)[n].is_destructor)
 #define TYPE_FN_FIELD_FCONTEXT(thisfn, n) ((thisfn)[n].fcontext)
 #define TYPE_FN_FIELD_VOFFSET(thisfn, n) ((thisfn)[n].voffset-2)
 #define TYPE_FN_FIELD_VIRTUAL_P(thisfn, n) ((thisfn)[n].voffset > 1)
index 0af684f4546546b80d163891607bc393b5f7bef0..dd6820b0afa84cdc5901362a29975f0acd64285f 100644 (file)
@@ -40,7 +40,7 @@ gnuv2_is_destructor_name (const char *name)
       || startswith (name, "__dt__"))
     return complete_object_dtor;
   else
-    return (enum dtor_kinds) 0;
+    return not_dtor;
 }
 
 static enum ctor_kinds
@@ -51,7 +51,7 @@ gnuv2_is_constructor_name (const char *name)
       || startswith (name, "__ct__"))
     return complete_object_ctor;
   else
-    return (enum ctor_kinds) 0;
+    return not_ctor;
 }
 
 static int
index 6c7f35bcbd8788570a04108cca381d27a65e95c1..e39d3162bf5f3c87497ea980a0974598cb552b1b 100644 (file)
@@ -1342,6 +1342,81 @@ gnuv3_pass_by_reference (struct type *type)
   return 0;
 }
 
+/* Wrapper for libiberty's is_gnu_v3_mangled_ctor function which
+   maps libiberty's values onto our own set of return values.  */
+
+static enum ctor_kinds
+gnuv3_is_constructor_name (const char *mangled_name)
+{
+  enum gnu_v3_ctor_kinds libiberty_kind;
+  enum ctor_kinds kind;
+
+  libiberty_kind = is_gnu_v3_mangled_ctor (mangled_name);
+
+  switch (libiberty_kind)
+    {
+    case 0:
+      kind = not_ctor;
+      break;
+    case gnu_v3_complete_object_ctor:
+      kind = complete_object_ctor;
+      break;
+    case gnu_v3_base_object_ctor:
+      kind = base_object_ctor;
+      break;
+    case gnu_v3_complete_object_allocating_ctor:
+      kind = complete_object_allocating_ctor;
+      break;
+    case gnu_v3_unified_ctor:
+      kind = unified_ctor;
+      break;
+    case gnu_v3_object_ctor_group:
+      kind = object_ctor_group;
+      break;
+    default:
+      gdb_assert_not_reached ("unhandled libiberty constructor kind");
+    }
+
+  return kind;
+}
+
+/* Wrapper for libiberty's is_gnu_v3_mangled_dtor function which
+   maps libiberty's values onto our own set of return values.  */
+
+static enum dtor_kinds
+gnuv3_is_destructor_name (const char *mangled_name)
+{
+  enum gnu_v3_dtor_kinds libiberty_kind;
+  enum dtor_kinds kind;
+
+  libiberty_kind = is_gnu_v3_mangled_dtor (mangled_name);
+  switch (libiberty_kind)
+  {
+  case 0:
+    kind = not_dtor;
+    break;
+  case gnu_v3_deleting_dtor:
+    kind = deleting_dtor;
+    break;
+  case gnu_v3_complete_object_dtor:
+    kind = complete_object_dtor;
+    break;
+  case gnu_v3_base_object_dtor:
+    kind = base_object_dtor;
+    break;
+  case gnu_v3_unified_dtor:
+    kind = unified_dtor;
+    break;
+  case gnu_v3_object_dtor_group:
+    kind = object_dtor_group;
+    break;
+  default:
+    gdb_assert_not_reached ("unhandled libiberty destructor kind");
+  }
+
+  return kind;
+}
+
 static void
 init_gnuv3_ops (void)
 {
@@ -1353,10 +1428,8 @@ init_gnuv3_ops (void)
   gnu_v3_abi_ops.shortname = "gnu-v3";
   gnu_v3_abi_ops.longname = "GNU G++ Version 3 ABI";
   gnu_v3_abi_ops.doc = "G++ Version 3 ABI";
-  gnu_v3_abi_ops.is_destructor_name =
-    (enum dtor_kinds (*) (const char *))is_gnu_v3_mangled_dtor;
-  gnu_v3_abi_ops.is_constructor_name =
-    (enum ctor_kinds (*) (const char *))is_gnu_v3_mangled_ctor;
+  gnu_v3_abi_ops.is_destructor_name = gnuv3_is_destructor_name;
+  gnu_v3_abi_ops.is_constructor_name = gnuv3_is_constructor_name;
   gnu_v3_abi_ops.is_vtable_name = gnuv3_is_vtable_name;
   gnu_v3_abi_ops.is_operator_name = gnuv3_is_operator_name;
   gnu_v3_abi_ops.rtti_type = gnuv3_rtti_type;