* 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().
This commit is contained in:
Daniel Jacobowitz
2007-01-03 18:05:45 +00:00
parent 9d6063994f
commit 0d5de0100f
42 changed files with 1192 additions and 810 deletions

View File

@@ -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,77 +277,92 @@ 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_get_vtable (struct value *container)
{
struct type *vtable_type = gdbarch_data (current_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 ());
}
/* Return a function pointer for CONTAINER's VTABLE_INDEX'th virtual
function, of type FNTYPE. */
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, vtable_index));
/* 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);
/* 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 *type, int offset)
struct type *vfn_base, int offset)
{
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 *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."));
/* 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. */
/* 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 = value_cast (vfn_base, value);
*value_p = value_cast (vfn_base, *value_p);
/* 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 ());
/* 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)));
/* Cast the function pointer to the appropriate type. */
vfn = value_cast (lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j)),
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));
return vfn;
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
@@ -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 */