From d48cc9dd6fbc2e64af32b5ec1680e8255eeb4edd Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Thu, 12 Nov 2009 19:47:25 +0000 Subject: [PATCH] 2009-11-12 Daniel Jacobowitz Paul Brook * 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 | 19 +++++ gdb/c-typeprint.c | 13 +++- gdb/dwarf2read.c | 13 ++++ gdb/gdbtypes.c | 3 +- gdb/gdbtypes.h | 8 ++ gdb/gnu-v3-abi.c | 185 +++++++++++++++++++++++----------------------- gdb/varobj.c | 19 +++-- 7 files changed, 157 insertions(+), 103 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a2dbfaae42d..424383d308a 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,22 @@ +2009-11-12 Daniel Jacobowitz + Paul Brook + + * 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 Daniel Jacobowitz diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c index 807eec16781..a984e3ffcca 100644 --- a/gdb/c-typeprint.c +++ b/gdb/c-typeprint.c @@ -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 diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 381350fe287..2f6e522f3f0 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -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. */ diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 299d0c515a2..ac126cd7b13 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -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. */ diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index be6ed552363..451a94a7949 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -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 \ diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c index 0f9d44efc0d..7e4cb23028a 100644 --- a/gdb/gnu-v3-abi.c +++ b/gdb/gnu-v3-abi.c @@ -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) : ""); - - 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; diff --git a/gdb/varobj.c b/gdb/varobj.c index 8f22156e260..2e4cf43ca65 100644 --- a/gdb/varobj.c +++ b/gdb/varobj.c @@ -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; -- 2.30.2