diff options
author | Daniel Jacobowitz <drow@false.org> | 2009-11-12 19:47:25 +0000 |
---|---|---|
committer | Daniel Jacobowitz <drow@false.org> | 2009-11-12 19:47:25 +0000 |
commit | d48cc9dd6fbc2e64af32b5ec1680e8255eeb4edd (patch) | |
tree | 006d18471c2868b4bdd8f2152a666064b820b568 /gdb/gnu-v3-abi.c | |
parent | 87728fa060cd21bf91473bf56b0d931b96efde3b (diff) | |
download | gdb-d48cc9dd6fbc2e64af32b5ec1680e8255eeb4edd.zip gdb-d48cc9dd6fbc2e64af32b5ec1680e8255eeb4edd.tar.gz gdb-d48cc9dd6fbc2e64af32b5ec1680e8255eeb4edd.tar.bz2 |
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.
Diffstat (limited to 'gdb/gnu-v3-abi.c')
-rw-r--r-- | gdb/gnu-v3-abi.c | 185 |
1 files changed, 91 insertions, 94 deletions
diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c index 0f9d44e..7e4cb23 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) : "<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; |