diff options
author | Daniel Jacobowitz <drow@false.org> | 2007-01-03 18:05:45 +0000 |
---|---|---|
committer | Daniel Jacobowitz <drow@false.org> | 2007-01-03 18:05:45 +0000 |
commit | 0d5de0100fd9c669790851af4f9f50704a24b453 (patch) | |
tree | f24fc195c586568deff26d6561c24cd65f1fd186 /gdb/gnu-v3-abi.c | |
parent | 9d6063994fbb0f0ec4fb8005f18bc84768592368 (diff) | |
download | gdb-0d5de0100fd9c669790851af4f9f50704a24b453.zip gdb-0d5de0100fd9c669790851af4f9f50704a24b453.tar.gz gdb-0d5de0100fd9c669790851af4f9f50704a24b453.tar.bz2 |
* NEWS: Mention pointer to member improvements.
* Makefile.in (gnu-v3-abi.o): Delete special rule.
(eval.o, gnu-v3-abi.o, ia64-tdep.o): Update.
* ada-valprint.c (ada_print_scalar): Update for new type codes.
* c-typeprint.c (c_print_type): Update for new type codes.
(c_type_print_varspec_prefix, c_type_print_varspec_suffix)
(c_type_print_base): Likewise.
(c_type_print_args): Rewrite.
* c-valprint.c (c_val_print): Update for new type codes. Remove
support for references to members. Treat methods like functions.
* cp-abi.c (cplus_print_method_ptr, cplus_method_ptr_size)
(cplus_make_method_ptr, cplus_method_ptr_to_value): New.
* cp-abi.h (cplus_print_method_ptr, cplus_method_ptr_size)
(cplus_make_method_ptr, cplus_method_ptr_to_value): New prototypes.
(struct cp_abi_ops): Add corresponding members.
* cp-valprint.c (cp_print_class_method): Delete.
(cp_find_class_member): New function.
(cp_print_class_member): Use it. Simplify support for bogus
member pointers.
* dwarf2read.c (quirk_gcc_member_function_pointer): Use
lookup_methodptr_type.
(read_tag_ptr_to_member_type): Likewise, and lookup_memberptr_type.
* eval.c (evaluate_subexp_standard): Implement EVAL_SKIP for
OP_SCOPE. Update call to value_aggregate_elt. Rewrite member
pointer support.
(evaluate_subexp_for_address): Handle OP_SCOPE explicitly. Handle
references returned by user defined operators.
* f-typeprint.c (f_print_type, f_type_print_varspec_prefix)
(f_type_print_varspec_suffix): Remove support for member pointers.
* gdbtypes.c (lookup_memberptr_type): Renamed from lookup_member_type
and adjusted.
(smash_to_memberptr_type): Likewise, from smash_to_member_type.
(lookup_methodptr_type): New.
(rank_one_type): Adjust for TYPE_CODE_MEMBERPTR.
(recursive_dump_type): Update for new types.
* gdbtypes.h (enum type_code): Replace TYPE_CODE_MEMBER with
TYPE_CODE_MEMBERPTR and TYPE_CODE_METHODPTR.
(lookup_memberptr_type, lookup_methodptr_type)
(smash_to_memberptr_type): New prototypes.
(smash_to_method_type): Formatting fix.
(lookup_member_type, smash_to_member_type): Delete prototypes.
* gnu-v3-abi.c (gnuv3_get_vtable, gnuv3_get_virtual_fn): New.
Do not rely on debug information for the vptr or the method's
enclosing type. Handle function descriptors for IA64.
(gnuv3_virtual_fn_field): Rewrite using the new functions.
(gnuv3_find_method_in, gnuv3_print_method_ptr)
(gnuv3_method_ptr_size, gnuv3_make_method_ptr)
(gnuv3_method_ptr_to_value): New.
(init_gnuv3_ops): Set new members of gnu_v3_abi_ops.
* hpread.c (hpread_type_lookup): Update for new types.
* infcall.c (value_arg_coerce): Likewise.
* m2-typeprint.c (m2_print_type): Remove explicit support
for member pointers.
* m2-valprint.c (m2_val_print): Likewise.
* p-typeprint.c (pascal_type_print_varspec_prefix)
(pascal_type_print_varspec_suffix, pascal_type_print_base): Likewise.
* p-valprint.c (pascal_val_print): Likewise.
(pascal_object_print_class_method, pascal_object_print_class_member):
Delete.
* p-lang.h (pascal_object_print_class_method)
(pascal_object_print_class_member): Delete prototypes.
* stabsread.c (read_type): Update for new types.
* typeprint.c (print_type_scalar): Likewise.
* valops.c (value_struct_elt_for_reference, value_namespace_elt)
(value_maybe_namespace_elt, value_aggregate_elt): Add want_address
argument. Construct a pointer to member if the address of a
function or data member is requested.
(value_cast_pointers): Don't modify the input value.
(value_cast): Adjust pointer to member handling for new types.
Allow null pointer to member constants. Don't modify the input
value.
(value_ind): Remove pointer to member check. Handle function
descriptors for function pointers.
(value_struct_elt, value_find_oload_method_list, check_field):
Remove pointer to member checks.
* value.c (unpack_long): Allow pointers to data members.
(value_from_longest): Allow member pointers.
* value.h (value_aggregate_elt): Add want_address.
* varobj.c (c_variable_editable): Remove check for members.
* gdbarch.sh: Add vtable_function_descriptors and vbit_in_delta.
* ia64-tdep.c (ia64_convert_from_func_ptr_addr): Handle descriptors
in virtual tables.
(ia64_gdbarch_init): Call set_gdbarch_vtable_function_descriptors.
* c-lang.h (cp_print_class_method): Delete prototype.
* arm-tdep.c (arm_gdbarch_init): Call set_gdbarch_vbit_in_delta.
* mips-tdep.c (mips_gdbarch_init): Likewise.
* gdbarch.c, gdbarch.h: Regenerated.
* gdb.cp/classes.exp (test_pointers_to_class_members): Update expected
output. Test the types of members and member pointers.
* gdb.cp/inherit.exp (test_print_mi_member_types): Remove KFAILs for
gdb/2092.
* gdb.cp/member-ptr.exp: Search for a comment instead of a
statement. Enable for GCC. Update expected output for some tests
and add new tests. Remove obsolete GCC KFAILs. Allow GCC's class
layout.
* gdb.cp/member-ptr.cc (Padding, Padding::vspacer, Base, Base::get_x)
(Base::vget_base, Left, Left::vget, Right, Right::vget, Diamond)
(Diamond::vget_base): New.
(main): Add new tests.
* gdb.cp/printmethod.exp: Update expected output for member functions.
* gdb.cp/virtfunc.exp (test_virtual_calls): Add a KFAIL for
print pEe->D::vg().
Diffstat (limited to 'gdb/gnu-v3-abi.c')
-rw-r--r-- | gdb/gnu-v3-abi.c | 377 |
1 files changed, 319 insertions, 58 deletions
diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c index 383b475..c3a3913 100644 --- a/gdb/gnu-v3-abi.c +++ b/gdb/gnu-v3-abi.c @@ -1,7 +1,8 @@ /* Abstraction of GNU v3 abi. Contributed by Jim Blandy <jimb@redhat.com> - Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2003, 2005, 2006 + Free Software Foundation, Inc. This file is part of GDB. @@ -25,6 +26,8 @@ #include "cp-abi.h" #include "cp-support.h" #include "demangle.h" +#include "valprint.h" + #include "gdb_assert.h" #include "gdb_string.h" @@ -274,79 +277,94 @@ gnuv3_rtti_type (struct value *value, 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_virtual_fn_field (struct value **value_p, - struct fn_field *f, int j, - struct type *type, int offset) +gnuv3_get_vtable (struct value *container) { struct type *vtable_type = gdbarch_data (current_gdbarch, vtable_type_gdbarch_data); - struct value *value = *value_p; - struct type *values_type = check_typedef (value_type (value)); - struct type *vfn_base; - CORE_ADDR vtable_address; - struct value *vtable; - struct value *vfn; + 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 ()); +} - /* Some simple sanity checks. */ - if (TYPE_CODE (values_type) != TYPE_CODE_CLASS) - error (_("Only classes can have virtual functions.")); +/* Return a function pointer for CONTAINER's VTABLE_INDEX'th virtual + function, of type FNTYPE. */ - /* Find the base class that defines this virtual function. */ - vfn_base = TYPE_FN_FIELD_FCONTEXT (f, j); - if (! vfn_base) - /* In programs compiled with G++ version 1, the debug info doesn't - say which base class defined the virtual function. We'll guess - it's the same base class that has our vtable; this is wrong for - multiple inheritance, but it's better than nothing. */ - vfn_base = TYPE_VPTR_BASETYPE (type); - - /* This type may have been defined before its virtual function table - was. If so, fill in the virtual function table entry for the - type now. */ - if (TYPE_VPTR_FIELDNO (vfn_base) < 0) - fill_in_vptr_fieldno (vfn_base); - if (TYPE_VPTR_FIELDNO (vfn_base) < 0) - error (_("Could not find virtual table pointer for class \"%s\"."), - TYPE_TAG_NAME (vfn_base) ? TYPE_TAG_NAME (vfn_base) : "<unknown>"); - - /* Now that we know which base class is defining our virtual - function, cast our value to that baseclass. This takes care of - any necessary `this' adjustments. */ - if (vfn_base != values_type) - value = value_cast (vfn_base, value); - - /* Now value is an object of the appropriate base type. Fetch its - virtual table. */ - /* It might be possible to do this cast at the same time as the above. - Does multiple inheritance affect this? - Can this even trigger, or is TYPE_VPTR_BASETYPE idempotent? - */ - if (TYPE_VPTR_BASETYPE (vfn_base) != vfn_base) - value = value_cast (TYPE_VPTR_BASETYPE (vfn_base), value); - vtable_address - = value_as_address (value_field (value, TYPE_VPTR_FIELDNO (vfn_base))); - - vtable = value_at_lazy (vtable_type, - vtable_address - vtable_address_point_offset ()); +static struct value * +gnuv3_get_virtual_fn (struct value *container, struct type *fntype, + int vtable_index) +{ + struct value *vtable = gnuv3_get_vtable (container); + struct value *vfn; /* Fetch the appropriate function pointer from the vtable. */ vfn = value_subscript (value_field (vtable, vtable_field_virtual_functions), - value_from_longest (builtin_type_int, - TYPE_FN_FIELD_VOFFSET (f, j))); + value_from_longest (builtin_type_int, vtable_index)); - /* Cast the function pointer to the appropriate type. */ - vfn = value_cast (lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j)), - vfn); + /* If this architecture uses function descriptors directly in the vtable, + then the address of the vtable entry is actually a "function pointer" + (i.e. points to the descriptor). We don't need to scale the index + by the size of a function descriptor; GCC does that before outputing + debug information. */ + if (gdbarch_vtable_function_descriptors (current_gdbarch)) + vfn = value_addr (vfn); - /* Is (type)value always numerically the same as (vfn_base)value? - If so we can spare this cast and use one of the ones above. */ - *value_p = value_addr (value_cast (type, *value_p)); + /* Cast the function pointer to the appropriate type. */ + vfn = value_cast (lookup_pointer_type (fntype), vfn); return vfn; } +/* GNU v3 implementation of value_virtual_fn_field. See cp-abi.h + for a description of the arguments. */ + +static struct value * +gnuv3_virtual_fn_field (struct value **value_p, + struct fn_field *f, int j, + struct type *vfn_base, int offset) +{ + struct type *values_type = check_typedef (value_type (*value_p)); + + /* Some simple sanity checks. */ + if (TYPE_CODE (values_type) != TYPE_CODE_CLASS) + error (_("Only classes can have virtual functions.")); + + /* Cast our value to the base class which defines this virtual + function. This takes care of any necessary `this' + adjustments. */ + if (vfn_base != values_type) + *value_p = value_cast (vfn_base, *value_p); + + return gnuv3_get_virtual_fn (*value_p, TYPE_FN_FIELD_TYPE (f, j), + TYPE_FN_FIELD_VOFFSET (f, j)); +} + /* Compute the offset of the baseclass which is the INDEXth baseclass of class TYPE, for value at VALADDR (in host) at ADDRESS (in target). @@ -416,6 +434,245 @@ gnuv3_baseclass_offset (struct type *type, int index, const bfd_byte *valaddr, return base_offset; } +/* Locate a virtual method in DOMAIN or its non-virtual base classes + which has virtual table index VOFFSET. The method has an associated + "this" adjustment of ADJUSTMENT bytes. */ + +const char * +gnuv3_find_method_in (struct type *domain, CORE_ADDR voffset, + LONGEST adjustment) +{ + int i; + const char *physname; + + /* Search this class first. */ + physname = NULL; + if (adjustment == 0) + { + int len; + + len = TYPE_NFN_FIELDS (domain); + for (i = 0; i < len; i++) + { + int len2, j; + struct fn_field *f; + + f = TYPE_FN_FIELDLIST1 (domain, i); + len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i); + + check_stub_method_group (domain, i); + for (j = 0; j < len2; j++) + if (TYPE_FN_FIELD_VOFFSET (f, j) == voffset) + return TYPE_FN_FIELD_PHYSNAME (f, j); + } + } + + /* Next search non-virtual bases. If it's in a virtual base, + we're out of luck. */ + for (i = 0; i < TYPE_N_BASECLASSES (domain); i++) + { + int pos; + struct type *basetype; + + if (BASETYPE_VIA_VIRTUAL (domain, i)) + continue; + + pos = TYPE_BASECLASS_BITPOS (domain, i) / 8; + basetype = TYPE_FIELD_TYPE (domain, i); + /* Recurse with a modified adjustment. We don't need to adjust + voffset. */ + if (adjustment >= pos && adjustment < pos + TYPE_LENGTH (basetype)) + return gnuv3_find_method_in (basetype, voffset, adjustment - pos); + } + + return NULL; +} + +/* GNU v3 implementation of cplus_print_method_ptr. */ + +static void +gnuv3_print_method_ptr (const gdb_byte *contents, + struct type *type, + struct ui_file *stream) +{ + CORE_ADDR ptr_value; + LONGEST adjustment; + struct type *domain; + int vbit; + + domain = TYPE_DOMAIN_TYPE (type); + + /* Extract the pointer to member. */ + ptr_value = extract_typed_address (contents, builtin_type_void_func_ptr); + contents += TYPE_LENGTH (builtin_type_void_func_ptr); + adjustment = extract_signed_integer (contents, + TYPE_LENGTH (builtin_type_long)); + + if (!gdbarch_vbit_in_delta (current_gdbarch)) + { + vbit = ptr_value & 1; + ptr_value = ptr_value ^ vbit; + } + else + { + vbit = adjustment & 1; + adjustment = adjustment >> 1; + } + + /* Check for NULL. */ + if (ptr_value == 0 && vbit == 0) + { + fprintf_filtered (stream, "NULL"); + return; + } + + /* Search for a virtual method. */ + if (vbit) + { + CORE_ADDR voffset; + const char *physname; + + /* It's a virtual table offset, maybe in this class. Search + for a field with the correct vtable offset. First convert it + to an index, as used in TYPE_FN_FIELD_VOFFSET. */ + voffset = ptr_value / TYPE_LENGTH (builtin_type_long); + + physname = gnuv3_find_method_in (domain, voffset, adjustment); + + /* If we found a method, print that. We don't bother to disambiguate + possible paths to the method based on the adjustment. */ + if (physname) + { + char *demangled_name = cplus_demangle (physname, + DMGL_ANSI | DMGL_PARAMS); + if (demangled_name != NULL) + { + fprintf_filtered (stream, "&virtual "); + fputs_filtered (demangled_name, stream); + xfree (demangled_name); + return; + } + } + } + + /* We didn't find it; print the raw data. */ + if (vbit) + { + fprintf_filtered (stream, "&virtual table offset "); + print_longest (stream, 'd', 1, ptr_value); + } + else + print_address_demangle (ptr_value, stream, demangle); + + if (adjustment) + { + fprintf_filtered (stream, ", this adjustment "); + print_longest (stream, 'd', 1, adjustment); + } +} + +/* GNU v3 implementation of cplus_method_ptr_size. */ + +static int +gnuv3_method_ptr_size (void) +{ + return 2 * TYPE_LENGTH (builtin_type_void_data_ptr); +} + +/* GNU v3 implementation of cplus_make_method_ptr. */ + +static void +gnuv3_make_method_ptr (gdb_byte *contents, CORE_ADDR value, int is_virtual) +{ + int size = TYPE_LENGTH (builtin_type_void_data_ptr); + + /* FIXME drow/2006-12-24: The adjustment of "this" is currently + always zero, since the method pointer is of the correct type. + But if the method pointer came from a base class, this is + incorrect - it should be the offset to the base. The best + fix might be to create the pointer to member pointing at the + base class and cast it to the derived class, but that requires + support for adjusting pointers to members when casting them - + not currently supported by GDB. */ + + if (!gdbarch_vbit_in_delta (current_gdbarch)) + { + store_unsigned_integer (contents, size, value | is_virtual); + store_unsigned_integer (contents + size, size, 0); + } + else + { + store_unsigned_integer (contents, size, value); + store_unsigned_integer (contents + size, size, is_virtual); + } +} + +/* GNU v3 implementation of cplus_method_ptr_to_value. */ + +static struct value * +gnuv3_method_ptr_to_value (struct value **this_p, struct value *method_ptr) +{ + const gdb_byte *contents = value_contents (method_ptr); + CORE_ADDR ptr_value; + struct type *final_type, *method_type; + LONGEST adjustment; + struct value *adjval; + int vbit; + + final_type = TYPE_DOMAIN_TYPE (check_typedef (value_type (method_ptr))); + final_type = lookup_pointer_type (final_type); + + method_type = TYPE_TARGET_TYPE (check_typedef (value_type (method_ptr))); + + ptr_value = extract_typed_address (contents, builtin_type_void_func_ptr); + contents += TYPE_LENGTH (builtin_type_void_func_ptr); + adjustment = extract_signed_integer (contents, + TYPE_LENGTH (builtin_type_long)); + + if (!gdbarch_vbit_in_delta (current_gdbarch)) + { + vbit = ptr_value & 1; + ptr_value = ptr_value ^ vbit; + } + else + { + vbit = adjustment & 1; + adjustment = adjustment >> 1; + } + + /* First convert THIS to match the containing type of the pointer to + member. This cast may adjust the value of THIS. */ + *this_p = value_cast (final_type, *this_p); + + /* Then apply whatever adjustment is necessary. This creates a somewhat + strange pointer: it claims to have type FINAL_TYPE, but in fact it + might not be a valid FINAL_TYPE. For instance, it might be a + base class of FINAL_TYPE. And if it's not the primary base class, + then printing it out as a FINAL_TYPE object would produce some pretty + garbage. + + But we don't really know the type of the first argument in + METHOD_TYPE either, which is why this happens. We can't + dereference this later as a FINAL_TYPE, but once we arrive in the + called method we'll have debugging information for the type of + "this" - and that'll match the value we produce here. + + You can provoke this case by casting a Base::* to a Derived::*, for + instance. */ + *this_p = value_cast (builtin_type_void_data_ptr, *this_p); + adjval = value_from_longest (builtin_type_long, adjustment); + *this_p = value_add (*this_p, adjval); + *this_p = value_cast (final_type, *this_p); + + if (vbit) + { + LONGEST voffset = ptr_value / TYPE_LENGTH (builtin_type_long); + return gnuv3_get_virtual_fn (value_ind (*this_p), method_type, voffset); + } + else + return value_from_pointer (lookup_pointer_type (method_type), ptr_value); +} + static void init_gnuv3_ops (void) { @@ -433,6 +690,10 @@ init_gnuv3_ops (void) gnu_v3_abi_ops.rtti_type = gnuv3_rtti_type; gnu_v3_abi_ops.virtual_fn_field = gnuv3_virtual_fn_field; gnu_v3_abi_ops.baseclass_offset = gnuv3_baseclass_offset; + gnu_v3_abi_ops.print_method_ptr = gnuv3_print_method_ptr; + gnu_v3_abi_ops.method_ptr_size = gnuv3_method_ptr_size; + gnu_v3_abi_ops.make_method_ptr = gnuv3_make_method_ptr; + gnu_v3_abi_ops.method_ptr_to_value = gnuv3_method_ptr_to_value; } extern initialize_file_ftype _initialize_gnu_v3_abi; /* -Wmissing-prototypes */ |