From: Keith Seitz Date: Tue, 21 Feb 2017 21:32:53 +0000 (-0800) Subject: DWARF and C++ ABI constructor/destructor enhancements. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e691088032a961339af3e8977a7d8b68a29e568f;p=thirdparty%2Fbinutils-gdb.git DWARF and C++ ABI constructor/destructor enhancements. This patch primarily adds support for recording constructor and destructor kinds for the relevant types. gdb/ChangeLog --- diff --git a/gdb/cp-abi.h b/gdb/cp-abi.h index 6b82eacd01e..968f92cbaa0 100644 --- a/gdb/cp-abi.h +++ b/gdb/cp-abi.h @@ -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. diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 2e2c58d0dbf..b697b3f17ef 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -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 diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index b8910dcb047..12e3841ca99 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -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) diff --git a/gdb/gnu-v2-abi.c b/gdb/gnu-v2-abi.c index 0af684f4546..dd6820b0afa 100644 --- a/gdb/gnu-v2-abi.c +++ b/gdb/gnu-v2-abi.c @@ -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 diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c index 6c7f35bcbd8..e39d3162bf5 100644 --- a/gdb/gnu-v3-abi.c +++ b/gdb/gnu-v3-abi.c @@ -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;