* 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().
+2007-01-03 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * 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.
+
2007-01-01 Mark Kettenis <kettenis@gnu.org>
* rs6000-tdep.c (rs6000_use_struct_convention)
$(CC) -c $(INTERNAL_CFLAGS) $(TARGET_SYSTEM_ROOT_DEFINE) \
-DBINDIR=\"$(bindir)\" $(srcdir)/main.c
-# FIXME: cagney/2004-09-16: "gnu-v3-abi.c", with a GCC 3.4 compiler,
-# gets a "assignment from incompatible pointer type" warning. The
-# return types - "enum gnu_v3_dtor_kinds" vs "enum ctor_kinds" -
-# conflict.
-gnu-v3-abi.o: $(srcdir)/gnu-v3-abi.c
- $(CC) -c $(INTERNAL_WARN_CFLAGS) $(srcdir)/gnu-v3-abi.c
-
# FIXME: cagney/2003-08-10: "monitor.c" gets -Wformat-nonliteral
# errors. It turns out that that is the least of monitor.c's
# problems. The function print_vsprintf appears to be using
eval.o: eval.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \
$(value_h) $(expression_h) $(target_h) $(frame_h) $(language_h) \
$(f_lang_h) $(cp_abi_h) $(infcall_h) $(objc_lang_h) $(block_h) \
- $(parser_defs_h) $(cp_support_h)
+ $(parser_defs_h) $(cp_support_h) $(gdb_assert_h)
event-loop.o: event-loop.c $(defs_h) $(event_loop_h) $(event_top_h) \
$(gdb_string_h) $(exceptions_h) $(gdb_assert_h) $(gdb_select_h)
event-top.o: event-top.c $(defs_h) $(top_h) $(inferior_h) $(target_h) \
$(gdbtypes_h) $(value_h) $(demangle_h) $(cp_abi_h) $(cp_support_h) \
$(gnu_v2_abi_h)
gnu-v3-abi.o: gnu-v3-abi.c $(defs_h) $(value_h) $(cp_abi_h) $(cp_support_h) \
- $(demangle_h) $(gdb_assert_h) $(gdb_string_h)
+ $(demangle_h) $(valprint_h) $(gdb_assert_h) $(gdb_string_h)
go32-nat.o: go32-nat.c $(defs_h) $(inferior_h) $(gdb_wait_h) $(gdbcore_h) \
$(command_h) $(gdbcmd_h) $(floatformat_h) $(buildsym_h) \
$(i387_tdep_h) $(i386_tdep_h) $(value_h) $(regcache_h) \
$(frame_h) $(frame_base_h) $(frame_unwind_h) $(doublest_h) \
$(value_h) $(gdb_assert_h) $(objfiles_h) $(elf_common_h) \
$(elf_bfd_h) $(dis_asm_h) $(infcall_h) $(osabi_h) $(ia64_tdep_h) \
- $(elf_ia64_h) $(libunwind_frame_h) $(libunwind_ia64_h)
+ $(elf_ia64_h) $(libunwind_frame_h) $(libunwind_ia64_h) \
+ $(cp_abi_h)
infcall.o: infcall.c $(defs_h) $(breakpoint_h) $(target_h) $(regcache_h) \
$(inferior_h) $(gdb_assert_h) $(block_h) $(gdbcore_h) $(language_h) \
$(objfiles_h) $(gdbcmd_h) $(command_h) $(gdb_string_h) $(infcall_h) \
* GDB for MIPS targets now autodetects whether a remote target provides
32-bit or 64-bit register values.
+* Support for C++ member pointers has been improved.
+
* New commands
set mem inaccessible-by-default
case TYPE_CODE_SET:
case TYPE_CODE_STRING:
case TYPE_CODE_ERROR:
- case TYPE_CODE_MEMBER:
+ case TYPE_CODE_MEMBERPTR:
+ case TYPE_CODE_METHODPTR:
case TYPE_CODE_METHOD:
case TYPE_CODE_REF:
warning (_("internal error: unhandled type in ada_print_scalar"));
set_gdbarch_coff_make_msymbol_special (gdbarch,
arm_coff_make_msymbol_special);
+ /* Virtual tables. */
+ set_gdbarch_vbit_in_delta (gdbarch, 1);
+
/* Hook in the ABI-specific overrides, if they have been registered. */
gdbarch_init_osabi (info, gdbarch);
/* C language support definitions for GDB, the GNU debugger.
- Copyright (C) 1992, 1994, 1995, 1996, 1997, 1998, 2000, 2002, 2005 Free
- Software Foundation, Inc.
+ Copyright (C) 1992, 1994, 1995, 1996, 1997, 1998, 2000, 2002, 2005, 2006
+ Free Software Foundation, Inc.
This file is part of GDB.
extern void cp_print_class_member (const gdb_byte *, struct type *,
struct ui_file *, char *);
-extern void cp_print_class_method (const gdb_byte *, struct type *,
- struct ui_file *);
-
extern void cp_print_value_fields (struct type *, struct type *,
const gdb_byte *, int, CORE_ADDR,
struct ui_file *, int,
/* Support for printing C and C++ types for GDB, the GNU debugger.
Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
- 1999, 2000, 2001, 2002, 2003
+ 1999, 2000, 2001, 2002, 2003, 2006
Free Software Foundation, Inc.
This file is part of GDB.
(code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC
|| code == TYPE_CODE_METHOD
|| code == TYPE_CODE_ARRAY
- || code == TYPE_CODE_MEMBER
+ || code == TYPE_CODE_MEMBERPTR
+ || code == TYPE_CODE_METHODPTR
|| code == TYPE_CODE_REF)))
fputs_filtered (" ", stream);
need_post_space = (varstring != NULL && strcmp (varstring, "") != 0);
c_type_print_modifier (type, stream, 1, need_post_space);
break;
- case TYPE_CODE_MEMBER:
- if (passed_a_ptr)
- fprintf_filtered (stream, "(");
+ case TYPE_CODE_MEMBERPTR:
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, show, 0, 0);
- fprintf_filtered (stream, " ");
name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
if (name)
fputs_filtered (name, stream);
else
c_type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, passed_a_ptr);
- fprintf_filtered (stream, "::");
+ fprintf_filtered (stream, "::*");
break;
- case TYPE_CODE_METHOD:
- if (passed_a_ptr)
- fprintf_filtered (stream, "(");
+ case TYPE_CODE_METHODPTR:
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, show, 0, 0);
- if (passed_a_ptr)
- {
- fprintf_filtered (stream, " ");
- c_type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, passed_a_ptr);
- fprintf_filtered (stream, "::");
- }
+ fprintf_filtered (stream, "(");
+ name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
+ if (name)
+ fputs_filtered (name, stream);
+ else
+ c_type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, passed_a_ptr);
+ fprintf_filtered (stream, "::*");
break;
case TYPE_CODE_REF:
c_type_print_modifier (type, stream, 1, need_post_space);
break;
+ case TYPE_CODE_METHOD:
case TYPE_CODE_FUNC:
c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, show, 0, 0);
if (passed_a_ptr)
}
-
+/* Print out the arguments of TYPE, which should have TYPE_CODE_METHOD
+ or TYPE_CODE_FUNC, to STREAM. Artificial arguments, such as "this"
+ in non-static methods, are displayed. */
static void
c_type_print_args (struct type *type, struct ui_file *stream)
{
- int i;
+ int i, len;
struct field *args;
+ int printed_any = 0;
fprintf_filtered (stream, "(");
args = TYPE_FIELDS (type);
- if (args != NULL)
- {
- int i;
-
- /* FIXME drow/2002-05-31: Always skips the first argument,
- should we be checking for static members? */
+ len = TYPE_NFIELDS (type);
- for (i = 1; i < TYPE_NFIELDS (type); i++)
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
+ {
+ if (printed_any)
{
- c_print_type (args[i].type, "", stream, -1, 0);
- if (i != TYPE_NFIELDS (type))
- {
- fprintf_filtered (stream, ",");
- wrap_here (" ");
- }
+ fprintf_filtered (stream, ", ");
+ wrap_here (" ");
}
- if (TYPE_VARARGS (type))
- fprintf_filtered (stream, "...");
- else if (i == 1
- && (current_language->la_language == language_cplus))
- fprintf_filtered (stream, "void");
+
+ c_print_type (TYPE_FIELD_TYPE (type, i), "", stream, -1, 0);
+ printed_any = 1;
}
- else if (current_language->la_language == language_cplus)
+
+ if (printed_any && TYPE_VARARGS (type))
{
- fprintf_filtered (stream, "void");
+ /* Print out a trailing ellipsis for varargs functions. Ignore
+ TYPE_VARARGS if the function has no named arguments; that
+ represents unprototyped (K&R style) C functions. */
+ if (printed_any && TYPE_VARARGS (type))
+ {
+ fprintf_filtered (stream, ", ");
+ wrap_here (" ");
+ fprintf_filtered (stream, "...");
+ }
}
+ else if (!printed_any
+ && (TYPE_PROTOTYPED (type)
+ || current_language->la_language == language_cplus))
+ fprintf_filtered (stream, "void");
fprintf_filtered (stream, ")");
}
0, 0);
break;
- case TYPE_CODE_MEMBER:
- if (passed_a_ptr)
- fprintf_filtered (stream, ")");
+ case TYPE_CODE_MEMBERPTR:
c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, show,
0, 0);
break;
- case TYPE_CODE_METHOD:
- if (passed_a_ptr)
- fprintf_filtered (stream, ")");
+ case TYPE_CODE_METHODPTR:
+ fprintf_filtered (stream, ")");
c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, show,
0, 0);
- if (passed_a_ptr)
- {
- c_type_print_args (type, stream);
- }
break;
case TYPE_CODE_PTR:
1, 0);
break;
+ case TYPE_CODE_METHOD:
case TYPE_CODE_FUNC:
if (passed_a_ptr)
fprintf_filtered (stream, ")");
if (!demangled_args)
- {
- int i, len = TYPE_NFIELDS (type);
- fprintf_filtered (stream, "(");
- if (len == 0
- && (TYPE_PROTOTYPED (type)
- || current_language->la_language == language_cplus))
- {
- fprintf_filtered (stream, "void");
- }
- else
- for (i = 0; i < len; i++)
- {
- if (i > 0)
- {
- fputs_filtered (", ", stream);
- wrap_here (" ");
- }
- c_print_type (TYPE_FIELD_TYPE (type, i), "", stream, -1, 0);
- }
- fprintf_filtered (stream, ")");
- }
+ c_type_print_args (type, stream);
c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, show,
passed_a_ptr, 0);
break;
case TYPE_CODE_TYPEDEF:
case TYPE_CODE_ARRAY:
case TYPE_CODE_PTR:
- case TYPE_CODE_MEMBER:
+ case TYPE_CODE_MEMBERPTR:
case TYPE_CODE_REF:
case TYPE_CODE_FUNC:
case TYPE_CODE_METHOD:
+ case TYPE_CODE_METHODPTR:
c_type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
break;
addr = address;
goto print_unpacked_pointer;
+ case TYPE_CODE_MEMBERPTR:
+ if (format)
+ {
+ print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
+ break;
+ }
+ cp_print_class_member (valaddr + embedded_offset,
+ TYPE_DOMAIN_TYPE (type),
+ stream, "&");
+ break;
+
+ case TYPE_CODE_METHODPTR:
+ cplus_print_method_ptr (valaddr + embedded_offset, type, stream);
+ break;
+
case TYPE_CODE_PTR:
if (format && format != 's')
{
break;
}
elttype = check_typedef (TYPE_TARGET_TYPE (type));
- if (TYPE_CODE (elttype) == TYPE_CODE_METHOD)
- {
- cp_print_class_method (valaddr + embedded_offset, type, stream);
- }
- else if (TYPE_CODE (elttype) == TYPE_CODE_MEMBER)
- {
- cp_print_class_member (valaddr + embedded_offset,
- TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)),
- stream, "&");
- }
- else
{
addr = unpack_pointer (type, valaddr + embedded_offset);
print_unpacked_pointer:
}
break;
- case TYPE_CODE_MEMBER:
- error (_("not implemented: member type in c_val_print"));
- break;
-
case TYPE_CODE_REF:
elttype = check_typedef (TYPE_TARGET_TYPE (type));
- if (TYPE_CODE (elttype) == TYPE_CODE_MEMBER)
- {
- cp_print_class_member (valaddr + embedded_offset,
- TYPE_DOMAIN_TYPE (elttype),
- stream, "");
- break;
- }
if (addressprint)
{
CORE_ADDR addr
break;
case TYPE_CODE_FUNC:
+ case TYPE_CODE_METHOD:
if (format)
{
print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
}
break;
- case TYPE_CODE_METHOD:
- {
- struct value *v = value_at (type, address);
- cp_print_class_method (value_contents (value_addr (v)),
- lookup_pointer_type (type), stream);
- break;
- }
-
case TYPE_CODE_VOID:
fprintf_filtered (stream, "void");
break;
/* Generic code for supporting multiple C++ ABI's
- 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.
return (*current_cp_abi.rtti_type) (v, full, top, using_enc);
}
+void
+cplus_print_method_ptr (const gdb_byte *contents, struct type *type,
+ struct ui_file *stream)
+{
+ if (current_cp_abi.print_method_ptr == NULL)
+ error (_("GDB does not support pointers to methods on this target"));
+ (*current_cp_abi.print_method_ptr) (contents, type, stream);
+}
+
+int
+cplus_method_ptr_size (void)
+{
+ if (current_cp_abi.method_ptr_size == NULL)
+ error (_("GDB does not support pointers to methods on this target"));
+ return (*current_cp_abi.method_ptr_size) ();
+}
+
+void
+cplus_make_method_ptr (gdb_byte *contents, CORE_ADDR value, int is_virtual)
+{
+ if (current_cp_abi.make_method_ptr == NULL)
+ error (_("GDB does not support pointers to methods on this target"));
+ (*current_cp_abi.make_method_ptr) (contents, value, is_virtual);
+}
+
+struct value *
+cplus_method_ptr_to_value (struct value **this_p, struct value *method_ptr)
+{
+ if (current_cp_abi.method_ptr_to_value == NULL)
+ error (_("GDB does not support pointers to methods on this target"));
+ return (*current_cp_abi.method_ptr_to_value) (this_p, method_ptr);
+}
+
/* Set the current C++ ABI to SHORT_NAME. */
static int
Contributed by Daniel Berlin <dberlin@redhat.com>
- Copyright (C) 2001, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2001, 2005, 2006 Free Software Foundation, Inc.
This file is part of GDB.
struct fn_field;
struct type;
struct value;
+struct ui_file;
/* The functions here that attempt to determine what sort of thing a
mangled name refers to may well be revised in the future. It would
extern int baseclass_offset (struct type *type, int index,
const bfd_byte *valaddr, CORE_ADDR address);
+/* Describe the target of a pointer to method. CONTENTS is the byte
+ pattern representing the pointer to method. TYPE is the pointer to
+ method type. STREAM is the stream to print it to. */
+void cplus_print_method_ptr (const gdb_byte *contents, struct type *type,
+ struct ui_file *stream);
+
+/* Return the size of a pointer to member function for the current
+ architecture. */
+int cplus_method_ptr_size (void);
+
+/* Return the method which should be called by applying METHOD_PTR
+ to *THIS_P, and adjust *THIS_P if necessary. */
+struct value *cplus_method_ptr_to_value (struct value **this_p,
+ struct value *method_ptr);
+
+/* Create the byte pattern in CONTENTS representing a pointer to
+ member function at ADDRESS (if IS_VIRTUAL is 0) or with virtual
+ table offset ADDRESS (if IS_VIRTUAL is 1). This is the opposite
+ of cplus_method_ptr_to_value. */
+void cplus_make_method_ptr (gdb_byte *CONTENTS, CORE_ADDR address,
+ int is_virtual);
+
struct cp_abi_ops
{
const char *shortname;
int *using_enc);
int (*baseclass_offset) (struct type *type, int index,
const bfd_byte *valaddr, CORE_ADDR address);
+ void (*print_method_ptr) (const gdb_byte *contents, struct type *type,
+ struct ui_file *stream);
+ int (*method_ptr_size) (void);
+ void (*make_method_ptr) (gdb_byte *, CORE_ADDR, int);
+ struct value * (*method_ptr_to_value) (struct value **, struct value *);
};
/* Support for printing C++ values for GDB, the GNU debugger.
Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
- 1997, 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+ 1997, 2000, 2001, 2002, 2003, 2005, 2006
+ Free Software Foundation, Inc.
This file is part of GDB.
enum val_prettyprint);
-void
-cp_print_class_method (const gdb_byte *valaddr,
- struct type *type,
- struct ui_file *stream)
-{
- struct type *domain;
- struct fn_field *f = NULL;
- int j = 0;
- int len2;
- int offset;
- char *kind = "";
- CORE_ADDR addr;
- struct symbol *sym;
- unsigned len;
- unsigned int i;
- struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type));
-
- domain = TYPE_DOMAIN_TYPE (target_type);
- if (domain == (struct type *) NULL)
- {
- fprintf_filtered (stream, "<unknown>");
- return;
- }
- addr = unpack_pointer (type, valaddr);
- if (METHOD_PTR_IS_VIRTUAL (addr))
- {
- offset = METHOD_PTR_TO_VOFFSET (addr);
- len = TYPE_NFN_FIELDS (domain);
- for (i = 0; i < len; i++)
- {
- 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) == offset)
- {
- kind = "virtual ";
- goto common;
- }
- }
- }
- }
- else
- {
- sym = find_pc_function (addr);
- if (sym == 0)
- {
- /* 1997-08-01 Currently unsupported with HP aCC */
- if (deprecated_hp_som_som_object_present)
- {
- fputs_filtered ("?? <not supported with HP aCC>", stream);
- return;
- }
- error (_("invalid pointer to member function"));
- }
- len = TYPE_NFN_FIELDS (domain);
- for (i = 0; i < len; i++)
- {
- 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 (strcmp (DEPRECATED_SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j))
- == 0)
- goto common;
- }
- }
- }
- common:
- if (i < len)
- {
- char *demangled_name;
-
- fprintf_filtered (stream, "&");
- fputs_filtered (kind, stream);
- demangled_name = cplus_demangle (TYPE_FN_FIELD_PHYSNAME (f, j),
- DMGL_ANSI | DMGL_PARAMS);
- if (demangled_name == NULL)
- fprintf_filtered (stream, "<badly mangled name %s>",
- TYPE_FN_FIELD_PHYSNAME (f, j));
- else
- {
- fputs_filtered (demangled_name, stream);
- xfree (demangled_name);
- }
- }
- else
- {
- fprintf_filtered (stream, "(");
- type_print (type, "", stream, -1);
- fprintf_filtered (stream, ") %d", (int) addr >> 3);
- }
-}
-
/* GCC versions after 2.4.5 use this. */
const char vtbl_ptr_name[] = "__vtbl_ptr_type";
stream, format, 0, recurse, pretty);
}
+
+/* Find the field in *DOMAIN, or its non-virtual base classes, with bit offset
+ OFFSET. Set *DOMAIN to the containing type and *FIELDNO to the containing
+ field number. If OFFSET is not exactly at the start of some field, set
+ *DOMAIN to NULL. */
+
+void
+cp_find_class_member (struct type **domain_p, int *fieldno,
+ LONGEST offset)
+{
+ struct type *domain;
+ unsigned int i;
+ unsigned len;
+
+ *domain_p = check_typedef (*domain_p);
+ domain = *domain_p;
+ len = TYPE_NFIELDS (domain);
+
+ for (i = TYPE_N_BASECLASSES (domain); i < len; i++)
+ {
+ LONGEST bitpos = TYPE_FIELD_BITPOS (domain, i);
+
+ QUIT;
+ if (offset == bitpos)
+ {
+ *fieldno = i;
+ return;
+ }
+ }
+
+ for (i = 0; i < TYPE_N_BASECLASSES (domain); i++)
+ {
+ LONGEST bitpos = TYPE_FIELD_BITPOS (domain, i);
+ LONGEST bitsize = 8 * TYPE_LENGTH (TYPE_FIELD_TYPE (domain, i));
+
+ if (offset >= bitpos && offset < bitpos + bitsize)
+ {
+ *domain_p = TYPE_FIELD_TYPE (domain, i);
+ cp_find_class_member (domain_p, fieldno, offset - bitpos);
+ return;
+ }
+ }
+
+ *domain_p = NULL;
+}
+
void
cp_print_class_member (const gdb_byte *valaddr, struct type *domain,
struct ui_file *stream, char *prefix)
{
-
/* VAL is a byte offset into the structure type DOMAIN.
Find the name of the field for that offset and
print it. */
- int extra = 0;
- int bits = 0;
- unsigned int i;
- unsigned len = TYPE_NFIELDS (domain);
+ unsigned int fieldno;
- /* @@ Make VAL into bit offset */
+ LONGEST val = unpack_long (builtin_type_long, valaddr);
- /* Note: HP aCC generates offsets that are the real byte offsets added
- to a constant bias 0x20000000 (1 << 29). This constant bias gets
- shifted out in the code below -- joyous happenstance! */
+ /* Pointers to data members are usually byte offsets into an object.
+ Because a data member can have offset zero, and a NULL pointer to
+ member must be distinct from any valid non-NULL pointer to
+ member, either the value is biased or the NULL value has a
+ special representation; both are permitted by ISO C++. HP aCC
+ used a bias of 0x20000000; HP cfront used a bias of 1; g++ 3.x
+ and other compilers which use the Itanium ABI use -1 as the NULL
+ value. GDB only supports that last form; to add support for
+ another form, make this into a cp-abi hook. */
- /* Note: HP cfront uses a constant bias of 1; if we support this
- compiler ever, we will have to adjust the computation below */
-
- LONGEST val = unpack_long (builtin_type_int, valaddr) << 3;
- for (i = TYPE_N_BASECLASSES (domain); i < len; i++)
+ if (val == -1)
{
- int bitpos = TYPE_FIELD_BITPOS (domain, i);
- QUIT;
- if (val == bitpos)
- break;
- if (val < bitpos && i != 0)
- {
- /* Somehow pointing into a field. */
- i -= 1;
- extra = (val - TYPE_FIELD_BITPOS (domain, i));
- if (extra & 0x7)
- bits = 1;
- else
- extra >>= 3;
- break;
- }
+ fprintf_filtered (stream, "NULL");
+ return;
}
- if (i < len)
+
+ cp_find_class_member (&domain, &fieldno, val << 3);
+
+ if (domain != NULL)
{
char *name;
fputs_filtered (prefix, stream);
else
c_type_print_base (domain, stream, 0, 0);
fprintf_filtered (stream, "::");
- fputs_filtered (TYPE_FIELD_NAME (domain, i), stream);
- if (extra)
- fprintf_filtered (stream, " + %d bytes", extra);
- if (bits)
- fprintf_filtered (stream, " (offset in bits)");
+ fputs_filtered (TYPE_FIELD_NAME (domain, fieldno), stream);
}
else
- fprintf_filtered (stream, "%ld", (long) (val >> 3));
+ fprintf_filtered (stream, "%ld", (long) val);
}
TYPE_NFN_FIELDS_TOTAL (type) = total_length;
}
-
/* Returns non-zero if NAME is the name of a vtable member in CU's
language, zero otherwise. */
static int
smash_to_method_type (type, domain_type, TYPE_TARGET_TYPE (pfn_type),
TYPE_FIELDS (pfn_type), TYPE_NFIELDS (pfn_type),
TYPE_VARARGS (pfn_type));
- type = lookup_pointer_type (type);
+ type = lookup_methodptr_type (type);
set_die_type (die, type, cu);
return 1;
return;
}
- type = alloc_type (objfile);
to_type = die_type (die, cu);
domain = die_containing_type (die, cu);
- smash_to_member_type (type, domain, to_type);
+
+ if (TYPE_CODE (check_typedef (to_type)) == TYPE_CODE_METHOD)
+ type = lookup_methodptr_type (to_type);
+ else
+ type = lookup_memberptr_type (to_type, domain);
set_die_type (die, type, cu);
}
/* Evaluate expressions for GDB.
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
- 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005 Free
- Software Foundation, Inc.
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006
+ Free Software Foundation, Inc.
This file is part of GDB.
#include "parser-defs.h"
#include "cp-support.h"
+#include "gdb_assert.h"
+
/* This is defined in valops.c */
extern int overload_resolution;
case OP_SCOPE:
tem = longest_to_int (exp->elts[pc + 2].longconst);
(*pos) += 4 + BYTES_TO_EXP_ELEM (tem + 1);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
arg1 = value_aggregate_elt (exp->elts[pc + 1].type,
&exp->elts[pc + 3].string,
- noside);
+ 0, noside);
if (arg1 == NULL)
error (_("There is no field named %s"), &exp->elts[pc + 3].string);
return arg1;
argvec = (struct value **) alloca (sizeof (struct value *) * (nargs + 3));
if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR)
{
- LONGEST fnptr;
-
/* 1997-08-01 Currently we do not support function invocation
via pointers-to-methods with HP aCC. Pointer does not point
to the function, but possibly to some thunk. */
arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
- fnptr = value_as_long (arg1);
+ if (TYPE_CODE (check_typedef (value_type (arg1)))
+ != TYPE_CODE_METHODPTR)
+ error (_("Non-pointer-to-member value used in pointer-to-member "
+ "construct"));
- if (METHOD_PTR_IS_VIRTUAL (fnptr))
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
{
- int fnoffset = METHOD_PTR_TO_VOFFSET (fnptr);
- struct type *basetype;
- struct type *domain_type =
- TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (value_type (arg1)));
- int i, j;
- basetype = TYPE_TARGET_TYPE (value_type (arg2));
- if (domain_type != basetype)
- arg2 = value_cast (lookup_pointer_type (domain_type), arg2);
- basetype = TYPE_VPTR_BASETYPE (domain_type);
- for (i = TYPE_NFN_FIELDS (basetype) - 1; i >= 0; i--)
- {
- struct fn_field *f = TYPE_FN_FIELDLIST1 (basetype, i);
- /* If one is virtual, then all are virtual. */
- if (TYPE_FN_FIELD_VIRTUAL_P (f, 0))
- for (j = TYPE_FN_FIELDLIST_LENGTH (basetype, i) - 1; j >= 0; --j)
- if ((int) TYPE_FN_FIELD_VOFFSET (f, j) == fnoffset)
- {
- struct value *temp = value_ind (arg2);
- arg1 = value_virtual_fn_field (&temp, f, j, domain_type, 0);
- arg2 = value_addr (temp);
- goto got_it;
- }
- }
- if (i < 0)
- error (_("virtual function at index %d not found"), fnoffset);
+ struct type *method_type = check_typedef (value_type (arg1));
+ arg1 = value_zero (method_type, not_lval);
}
else
- {
- deprecated_set_value_type (arg1, lookup_pointer_type (TYPE_TARGET_TYPE (value_type (arg1))));
- }
- got_it:
+ arg1 = cplus_method_ptr_to_value (&arg2, arg1);
/* Now, say which argument to start evaluating from */
tem = 2;
}
case STRUCTOP_MEMBER:
- arg1 = evaluate_subexp_for_address (exp, pos, noside);
+ case STRUCTOP_MPTR:
+ if (op == STRUCTOP_MEMBER)
+ arg1 = evaluate_subexp_for_address (exp, pos, noside);
+ else
+ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
- /* With HP aCC, pointers to methods do not point to the function code */
- if (deprecated_hp_som_som_object_present &&
- (TYPE_CODE (value_type (arg2)) == TYPE_CODE_PTR) &&
- (TYPE_CODE (TYPE_TARGET_TYPE (value_type (arg2))) == TYPE_CODE_METHOD))
- error (_("Pointers to methods not supported with HP aCC")); /* 1997-08-19 */
+ if (noside == EVAL_SKIP)
+ goto nosideret;
- mem_offset = value_as_long (arg2);
- goto handle_pointer_to_member;
+ type = check_typedef (value_type (arg2));
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_METHODPTR:
+ if (deprecated_hp_som_som_object_present)
+ {
+ /* With HP aCC, pointers to methods do not point to the
+ function code. */
+ /* 1997-08-19 */
+ error (_("Pointers to methods not supported with HP aCC"));
+ }
- case STRUCTOP_MPTR:
- arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
- arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return value_zero (TYPE_TARGET_TYPE (type), not_lval);
+ else
+ {
+ arg2 = cplus_method_ptr_to_value (&arg1, arg2);
+ gdb_assert (TYPE_CODE (value_type (arg2)) == TYPE_CODE_PTR);
+ return value_ind (arg2);
+ }
- /* With HP aCC, pointers to methods do not point to the function code */
- if (deprecated_hp_som_som_object_present &&
- (TYPE_CODE (value_type (arg2)) == TYPE_CODE_PTR) &&
- (TYPE_CODE (TYPE_TARGET_TYPE (value_type (arg2))) == TYPE_CODE_METHOD))
- error (_("Pointers to methods not supported with HP aCC")); /* 1997-08-19 */
+ case TYPE_CODE_MEMBERPTR:
+ /* Now, convert these values to an address. */
+ arg1 = value_cast (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)),
+ arg1);
- mem_offset = value_as_long (arg2);
+ mem_offset = value_as_long (arg2);
+ if (deprecated_hp_som_som_object_present)
+ {
+ /* HP aCC generates offsets that have bit #29 set; turn it off to get
+ a real offset to the member. */
+ if (!mem_offset) /* no bias -> really null */
+ error (_("Attempted dereference of null pointer-to-member"));
+ mem_offset &= ~0x20000000;
+ }
- handle_pointer_to_member:
- /* HP aCC generates offsets that have bit #29 set; turn it off to get
- a real offset to the member. */
- if (deprecated_hp_som_som_object_present)
- {
- if (!mem_offset) /* no bias -> really null */
- error (_("Attempted dereference of null pointer-to-member"));
- mem_offset &= ~0x20000000;
+ arg3 = value_from_pointer (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
+ value_as_long (arg1) + mem_offset);
+ return value_ind (arg3);
+
+ default:
+ error (_("non-pointer-to-member value used in pointer-to-member construct"));
}
- if (noside == EVAL_SKIP)
- goto nosideret;
- type = check_typedef (value_type (arg2));
- if (TYPE_CODE (type) != TYPE_CODE_PTR)
- goto bad_pointer_to_member;
- type = check_typedef (TYPE_TARGET_TYPE (type));
- if (TYPE_CODE (type) == TYPE_CODE_METHOD)
- error (_("not implemented: pointer-to-method in pointer-to-member construct"));
- if (TYPE_CODE (type) != TYPE_CODE_MEMBER)
- goto bad_pointer_to_member;
- /* Now, convert these values to an address. */
- arg1 = value_cast (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)),
- arg1);
- arg3 = value_from_pointer (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
- value_as_long (arg1) + mem_offset);
- return value_ind (arg3);
- bad_pointer_to_member:
- error (_("non-pointer-to-member value used in pointer-to-member construct"));
case BINOP_CONCAT:
arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
the implementation yet; but the pointer appears to point to a code
sequence (thunk) in memory -- in any case it is *not* the address
of the function as it would be in a naive implementation. */
- if ((TYPE_CODE (value_type (arg1)) == TYPE_CODE_PTR) &&
- (TYPE_CODE (TYPE_TARGET_TYPE (value_type (arg1))) == TYPE_CODE_METHOD))
+ if (TYPE_CODE (value_type (arg1)) == TYPE_CODE_METHODPTR)
error (_("Assignment to pointers to methods not implemented with HP aCC"));
- /* HP aCC pointers to data members require a constant bias */
- if ((TYPE_CODE (value_type (arg1)) == TYPE_CODE_PTR) &&
- (TYPE_CODE (TYPE_TARGET_TYPE (value_type (arg1))) == TYPE_CODE_MEMBER))
+ /* HP aCC pointers to data members require a constant bias. */
+ if (TYPE_CODE (value_type (arg1)) == TYPE_CODE_MEMBERPTR)
{
unsigned int *ptr = (unsigned int *) value_contents (arg2); /* forces evaluation */
*ptr |= 0x20000000; /* set 29th bit */
if (expect_type && TYPE_CODE (expect_type) == TYPE_CODE_PTR)
expect_type = TYPE_TARGET_TYPE (check_typedef (expect_type));
arg1 = evaluate_subexp (expect_type, exp, pos, noside);
- if ((TYPE_TARGET_TYPE (value_type (arg1))) &&
- ((TYPE_CODE (TYPE_TARGET_TYPE (value_type (arg1))) == TYPE_CODE_METHOD) ||
- (TYPE_CODE (TYPE_TARGET_TYPE (value_type (arg1))) == TYPE_CODE_MEMBER)))
+ type = check_typedef (value_type (arg1));
+ if (TYPE_CODE (type) == TYPE_CODE_METHODPTR
+ || TYPE_CODE (type) == TYPE_CODE_MEMBERPTR)
error (_("Attempt to dereference pointer to member without an object"));
if (noside == EVAL_SKIP)
goto nosideret;
if (noside == EVAL_SKIP)
{
- if (op == OP_SCOPE)
- {
- int temm = longest_to_int (exp->elts[pc + 3].longconst);
- (*pos) += 3 + BYTES_TO_EXP_ELEM (temm + 1);
- }
- else
- evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+ evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
goto nosideret;
}
else
{
struct value *retvalp = evaluate_subexp_for_address (exp, pos, noside);
/* If HP aCC object, use bias for pointers to members */
- if (deprecated_hp_som_som_object_present &&
- (TYPE_CODE (value_type (retvalp)) == TYPE_CODE_PTR) &&
- (TYPE_CODE (TYPE_TARGET_TYPE (value_type (retvalp))) == TYPE_CODE_MEMBER))
+ if (deprecated_hp_som_som_object_present
+ && TYPE_CODE (value_type (retvalp)) == TYPE_CODE_MEMBERPTR)
{
unsigned int *ptr = (unsigned int *) value_contents (retvalp); /* forces evaluation */
*ptr |= 0x20000000; /* set 29th bit */
int pc;
struct symbol *var;
struct value *x;
+ int tem;
pc = (*pos);
op = exp->elts[pc].opcode;
if (unop_user_defined_p (op, x))
{
x = value_x_unop (x, op, noside);
- if (noside == EVAL_AVOID_SIDE_EFFECTS)
- {
- if (VALUE_LVAL (x) == lval_memory)
- return value_zero (lookup_pointer_type (value_type (x)),
- not_lval);
- else
- error (_("Attempt to take address of non-lval"));
- }
- return value_addr (x);
+ goto default_case_after_eval;
}
return x;
(var,
block_innermost_frame (exp->elts[pc + 1].block));
+ case OP_SCOPE:
+ tem = longest_to_int (exp->elts[pc + 2].longconst);
+ (*pos) += 5 + BYTES_TO_EXP_ELEM (tem + 1);
+ x = value_aggregate_elt (exp->elts[pc + 1].type,
+ &exp->elts[pc + 3].string,
+ 1, noside);
+ if (x == NULL)
+ error (_("There is no field named %s"), &exp->elts[pc + 3].string);
+ return x;
+
default:
default_case:
x = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ default_case_after_eval:
if (noside == EVAL_AVOID_SIDE_EFFECTS)
{
+ struct type *type = check_typedef (value_type (x));
+
if (VALUE_LVAL (x) == lval_memory)
return value_zero (lookup_pointer_type (value_type (x)),
not_lval);
+ else if (TYPE_CODE (type) == TYPE_CODE_REF)
+ return value_zero (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
+ not_lval);
else
error (_("Attempt to take address of non-lval"));
}
(code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC
|| code == TYPE_CODE_METHOD
|| code == TYPE_CODE_ARRAY
- || code == TYPE_CODE_MEMBER
|| code == TYPE_CODE_REF)))
fputs_filtered (" ", stream);
f_type_print_varspec_prefix (type, stream, show, 0);
case TYPE_CODE_STRING:
case TYPE_CODE_BITSTRING:
case TYPE_CODE_METHOD:
- case TYPE_CODE_MEMBER:
case TYPE_CODE_REF:
case TYPE_CODE_COMPLEX:
case TYPE_CODE_TYPEDEF:
case TYPE_CODE_STRING:
case TYPE_CODE_BITSTRING:
case TYPE_CODE_METHOD:
- case TYPE_CODE_MEMBER:
case TYPE_CODE_COMPLEX:
case TYPE_CODE_TYPEDEF:
/* These types do not need a suffix. They are listed so that
gdbarch_register_reggroup_p_ftype *register_reggroup_p;
gdbarch_fetch_pointer_argument_ftype *fetch_pointer_argument;
gdbarch_regset_from_core_section_ftype *regset_from_core_section;
+ int vtable_function_descriptors;
+ int vbit_in_delta;
};
default_register_reggroup_p, /* register_reggroup_p */
0, /* fetch_pointer_argument */
0, /* regset_from_core_section */
+ 0, /* vtable_function_descriptors */
+ 0, /* vbit_in_delta */
/* startup_gdbarch() */
};
/* Skip verify of register_reggroup_p, invalid_p == 0 */
/* Skip verify of fetch_pointer_argument, has predicate */
/* Skip verify of regset_from_core_section, has predicate */
+ /* Skip verify of vtable_function_descriptors, invalid_p == 0 */
+ /* Skip verify of vbit_in_delta, invalid_p == 0 */
buf = ui_file_xstrdup (log, &dummy);
make_cleanup (xfree, buf);
if (strlen (buf) > 0)
fprintf_unfiltered (file,
"gdbarch_dump: value_to_register = <0x%lx>\n",
(long) current_gdbarch->value_to_register);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: vbit_in_delta = %s\n",
+ paddr_d (current_gdbarch->vbit_in_delta));
#ifdef TARGET_VIRTUAL_FRAME_POINTER
fprintf_unfiltered (file,
"gdbarch_dump: %s # %s\n",
fprintf_unfiltered (file,
"gdbarch_dump: virtual_frame_pointer = <0x%lx>\n",
(long) current_gdbarch->virtual_frame_pointer);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: vtable_function_descriptors = %s\n",
+ paddr_d (current_gdbarch->vtable_function_descriptors));
#ifdef TARGET_WRITE_PC
fprintf_unfiltered (file,
"gdbarch_dump: %s # %s\n",
gdbarch->regset_from_core_section = regset_from_core_section;
}
+int
+gdbarch_vtable_function_descriptors (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of vtable_function_descriptors, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_vtable_function_descriptors called\n");
+ return gdbarch->vtable_function_descriptors;
+}
+
+void
+set_gdbarch_vtable_function_descriptors (struct gdbarch *gdbarch,
+ int vtable_function_descriptors)
+{
+ gdbarch->vtable_function_descriptors = vtable_function_descriptors;
+}
+
+int
+gdbarch_vbit_in_delta (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of vbit_in_delta, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_vbit_in_delta called\n");
+ return gdbarch->vbit_in_delta;
+}
+
+void
+set_gdbarch_vbit_in_delta (struct gdbarch *gdbarch,
+ int vbit_in_delta)
+{
+ gdbarch->vbit_in_delta = vbit_in_delta;
+}
+
/* Keep a registry of per-architecture data-pointers required by GDB
modules. */
extern const struct regset * gdbarch_regset_from_core_section (struct gdbarch *gdbarch, const char *sect_name, size_t sect_size);
extern void set_gdbarch_regset_from_core_section (struct gdbarch *gdbarch, gdbarch_regset_from_core_section_ftype *regset_from_core_section);
+/* If the elements of C++ vtables are in-place function descriptors rather
+ than normal function pointers (which may point to code or a descriptor),
+ set this to one. */
+
+extern int gdbarch_vtable_function_descriptors (struct gdbarch *gdbarch);
+extern void set_gdbarch_vtable_function_descriptors (struct gdbarch *gdbarch, int vtable_function_descriptors);
+
+/* Set if the least significant bit of the delta is used instead of the least
+ significant bit of the pfn for pointers to virtual member functions. */
+
+extern int gdbarch_vbit_in_delta (struct gdbarch *gdbarch);
+extern void set_gdbarch_vbit_in_delta (struct gdbarch *gdbarch, int vbit_in_delta);
+
extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
# Return the appropriate register set for a core file section with
# name SECT_NAME and size SECT_SIZE.
M::const struct regset *:regset_from_core_section:const char *sect_name, size_t sect_size:sect_name, sect_size
+
+# If the elements of C++ vtables are in-place function descriptors rather
+# than normal function pointers (which may point to code or a descriptor),
+# set this to one.
+v::int:vtable_function_descriptors:::0:0::0
+
+# Set if the least significant bit of the delta is used instead of the least
+# significant bit of the pfn for pointers to virtual member functions.
+v::int:vbit_in_delta:::0:0::0
EOF
}
of the aggregate that the member belongs to. */
struct type *
-lookup_member_type (struct type *type, struct type *domain)
+lookup_memberptr_type (struct type *type, struct type *domain)
{
struct type *mtype;
mtype = alloc_type (TYPE_OBJFILE (type));
- smash_to_member_type (mtype, domain, type);
+ smash_to_memberptr_type (mtype, domain, type);
return (mtype);
}
+/* Return a pointer-to-method type, for a method of type TO_TYPE. */
+
+struct type *
+lookup_methodptr_type (struct type *to_type)
+{
+ struct type *mtype;
+
+ mtype = alloc_type (TYPE_OBJFILE (to_type));
+ TYPE_TARGET_TYPE (mtype) = to_type;
+ TYPE_DOMAIN_TYPE (mtype) = TYPE_DOMAIN_TYPE (to_type);
+ TYPE_LENGTH (mtype) = cplus_method_ptr_size ();
+ TYPE_CODE (mtype) = TYPE_CODE_METHODPTR;
+ return mtype;
+}
+
/* Allocate a stub method whose return type is TYPE.
This apparently happens for speed of symbol reading, since parsing
out the arguments to the method is cpu-intensive, the way we are doing
return t;
}
-/* Smash TYPE to be a type of members of DOMAIN with type TO_TYPE.
- A MEMBER is a wierd thing -- it amounts to a typed offset into
- a struct, e.g. "an int at offset 8". A MEMBER TYPE doesn't
- include the offset (that's the value of the MEMBER itself), but does
- include the structure type into which it points (for some reason).
+/* Smash TYPE to be a type of pointers to members of DOMAIN with type
+ TO_TYPE. A member pointer is a wierd thing -- it amounts to a
+ typed offset into a struct, e.g. "an int at offset 8". A MEMBER
+ TYPE doesn't include the offset (that's the value of the MEMBER
+ itself), but does include the structure type into which it points
+ (for some reason).
When "smashing" the type, we preserve the objfile that the
old type pointed to, since we aren't changing where the type is actually
allocated. */
void
-smash_to_member_type (struct type *type, struct type *domain,
- struct type *to_type)
+smash_to_memberptr_type (struct type *type, struct type *domain,
+ struct type *to_type)
{
struct objfile *objfile;
TYPE_OBJFILE (type) = objfile;
TYPE_TARGET_TYPE (type) = to_type;
TYPE_DOMAIN_TYPE (type) = domain;
- TYPE_LENGTH (type) = 1; /* In practice, this is never needed. */
- TYPE_CODE (type) = TYPE_CODE_MEMBER;
+ /* Assume that a data member pointer is the same size as a normal
+ pointer. */
+ TYPE_LENGTH (type) = TARGET_PTR_BIT / TARGET_CHAR_BIT;
+ TYPE_CODE (type) = TYPE_CODE_MEMBERPTR;
}
/* Smash TYPE to be a type of method of DOMAIN with type TO_TYPE.
return INCOMPATIBLE_TYPE_BADNESS;
}
break;
- case TYPE_CODE_MEMBER:
+ case TYPE_CODE_MEMBERPTR:
switch (TYPE_CODE (arg))
{
default:
case TYPE_CODE_ERROR:
printf_filtered ("(TYPE_CODE_ERROR)");
break;
- case TYPE_CODE_MEMBER:
- printf_filtered ("(TYPE_CODE_MEMBER)");
+ case TYPE_CODE_MEMBERPTR:
+ printf_filtered ("(TYPE_CODE_MEMBERPTR)");
+ break;
+ case TYPE_CODE_METHODPTR:
+ printf_filtered ("(TYPE_CODE_METHODPTR)");
break;
case TYPE_CODE_METHOD:
printf_filtered ("(TYPE_CODE_METHOD)");
TYPE_CODE_ERROR,
/* C++ */
- TYPE_CODE_MEMBER, /* Member type */
TYPE_CODE_METHOD, /* Method type */
+
+ /* Pointer-to-member-function type. This describes how to access a
+ particular member function of a class (possibly a virtual
+ member function). The representation may vary between different
+ C++ ABIs. */
+ TYPE_CODE_METHODPTR,
+
+ /* Pointer-to-member type. This is the offset within a class to some
+ particular data member. The only currently supported representation
+ uses an unbiased offset, with -1 representing NULL; this is used
+ by the Itanium C++ ABI (used by GCC on all platforms). */
+ TYPE_CODE_MEMBERPTR,
+
TYPE_CODE_REF, /* C++ Reference types */
TYPE_CODE_CHAR, /* *real* character type */
/* For types with virtual functions (TYPE_CODE_STRUCT), VPTR_BASETYPE
is the base class which defined the virtual function table pointer.
- For types that are pointer to member types (TYPE_CODE_MEMBER),
- VPTR_BASETYPE is the type that this pointer is a member of.
+ For types that are pointer to member types (TYPE_CODE_METHODPTR,
+ TYPE_CODE_MEMBERPTR), VPTR_BASETYPE is the type that this pointer
+ is a member of.
For method types (TYPE_CODE_METHOD), VPTR_BASETYPE is the aggregate
type that contains the method.
extern struct type *make_type_with_address_space (struct type *type,
int space_identifier);
-extern struct type *lookup_member_type (struct type *, struct type *);
+extern struct type *lookup_memberptr_type (struct type *, struct type *);
+
+extern struct type *lookup_methodptr_type (struct type *);
-extern void
-smash_to_method_type (struct type *type, struct type *domain,
- struct type *to_type, struct field *args,
- int nargs, int varargs);
+extern void smash_to_method_type (struct type *type, struct type *domain,
+ struct type *to_type, struct field *args,
+ int nargs, int varargs);
-extern void smash_to_member_type (struct type *, struct type *, struct type *);
+extern void smash_to_memberptr_type (struct type *, struct type *,
+ struct type *);
extern struct type *allocate_stub_method (struct type *);
/* 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.
#include "cp-abi.h"
#include "cp-support.h"
#include "demangle.h"
+#include "valprint.h"
+
#include "gdb_assert.h"
#include "gdb_string.h"
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).
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)
{
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 */
/* Read hp debug symbols and convert to internal format, for GDB.
Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004 Free Software Foundation, Inc.
+ 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
This file is part of GDB.
objfile),
class_type = hpread_type_lookup (dn_bufp->dptrmem.pointsto,
objfile),
- ptrmemtype = alloc_type (objfile);
- smash_to_member_type (ptrmemtype, class_type, memtype);
- return make_pointer_type (ptrmemtype, NULL);
+ return lookup_memberptr_type (memtype, class_type);
}
break;
TYPE_FIELDS (functype),
TYPE_NFIELDS (functype),
0);
- return make_pointer_type (ptrmemtype, NULL);
+ return lookup_methodptr_type (ptrmemtype);
}
break;
#include "infcall.h"
#include "osabi.h"
#include "ia64-tdep.h"
+#include "cp-abi.h"
#ifdef HAVE_LIBUNWIND_IA64_H
#include "elf/ia64.h" /* for PT_IA_64_UNWIND value */
if (s && strcmp (s->the_bfd_section->name, ".opd") == 0)
return read_memory_unsigned_integer (addr, 8);
+ /* There are also descriptors embedded in vtables. */
+ if (s)
+ {
+ struct minimal_symbol *minsym;
+
+ minsym = lookup_minimal_symbol_by_pc (addr);
+
+ if (minsym && is_vtable_name (SYMBOL_LINKAGE_NAME (minsym)))
+ return read_memory_unsigned_integer (addr, 8);
+ }
+
return addr;
}
set_gdbarch_print_insn (gdbarch, ia64_print_insn);
set_gdbarch_convert_from_func_ptr_addr (gdbarch, ia64_convert_from_func_ptr_addr);
+ /* The virtual table contains 16-byte descriptors, not pointers to
+ descriptors. */
+ set_gdbarch_vtable_function_descriptors (gdbarch, 1);
+
/* Hook in ABI-specific overrides, if they have been registered. */
gdbarch_init_osabi (info, gdbarch);
/* Perform an inferior function call, for GDB, the GNU debugger.
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
- 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This file is part of GDB.
case TYPE_CODE_STRING:
case TYPE_CODE_BITSTRING:
case TYPE_CODE_ERROR:
- case TYPE_CODE_MEMBER:
+ case TYPE_CODE_MEMBERPTR:
+ case TYPE_CODE_METHODPTR:
case TYPE_CODE_METHOD:
case TYPE_CODE_COMPLEX:
default:
m2_ref (type, stream, show, level);
break;
- case TYPE_CODE_MEMBER:
- m2_unknown (_("member"), type, stream, show, level);
- break;
-
case TYPE_CODE_METHOD:
m2_unknown (_("method"), type, stream, show, level);
break;
}
break;
- case TYPE_CODE_MEMBER:
- error (_("not implemented: member type in m2_val_print"));
- break;
-
case TYPE_CODE_REF:
elttype = check_typedef (TYPE_TARGET_TYPE (type));
if (addressprint)
set_gdbarch_single_step_through_delay (gdbarch, mips_single_step_through_delay);
+ /* Virtual tables. */
+ set_gdbarch_vbit_in_delta (gdbarch, 1);
+
mips_register_g_packet_guesses (gdbarch);
/* Hook in OS ABI-specific overrides, if they have been registered. */
/* Pascal language support definitions for GDB, the GNU debugger.
- Copyright (C) 2000, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2005, 2006 Free Software Foundation, Inc.
This file is part of GDB.
extern int static_field_print;
-extern void pascal_object_print_class_member (const gdb_byte *, struct type *,
- struct ui_file *, char *);
-
-extern void pascal_object_print_class_method (const gdb_byte *, struct type *,
- struct ui_file *);
-
extern void pascal_object_print_value_fields (struct type *, const gdb_byte *,
CORE_ADDR, struct ui_file *,
int, int, enum val_prettyprint,
/* Support for printing Pascal types for GDB, the GNU debugger.
- Copyright (C) 2000, 2001, 2002
+ Copyright (C) 2000, 2001, 2002, 2006
Free Software Foundation, Inc.
This file is part of GDB.
pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1);
break; /* pointer should be handled normally in pascal */
- case TYPE_CODE_MEMBER:
- if (passed_a_ptr)
- fprintf_filtered (stream, "(");
- pascal_type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0);
- fprintf_filtered (stream, " ");
- name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
- if (name)
- fputs_filtered (name, stream);
- else
- pascal_type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, passed_a_ptr);
- fprintf_filtered (stream, "::");
- break;
-
case TYPE_CODE_METHOD:
if (passed_a_ptr)
fprintf_filtered (stream, "(");
fprintf_filtered (stream, ")");
break;
- case TYPE_CODE_MEMBER:
- if (passed_a_ptr)
- fprintf_filtered (stream, ")");
- pascal_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0, 0);
- break;
-
case TYPE_CODE_METHOD:
if (passed_a_ptr)
fprintf_filtered (stream, ")");
{
case TYPE_CODE_TYPEDEF:
case TYPE_CODE_PTR:
- case TYPE_CODE_MEMBER:
case TYPE_CODE_REF:
/* case TYPE_CODE_FUNC:
case TYPE_CODE_METHOD: */
break;
}
elttype = check_typedef (TYPE_TARGET_TYPE (type));
- if (TYPE_CODE (elttype) == TYPE_CODE_METHOD)
- {
- pascal_object_print_class_method (valaddr + embedded_offset, type, stream);
- }
- else if (TYPE_CODE (elttype) == TYPE_CODE_MEMBER)
- {
- pascal_object_print_class_member (valaddr + embedded_offset,
- TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)),
- stream, "&");
- }
- else
{
addr = unpack_pointer (type, valaddr + embedded_offset);
print_unpacked_pointer:
}
break;
- case TYPE_CODE_MEMBER:
- error (_("not implemented: member type in pascal_val_print"));
- break;
-
case TYPE_CODE_REF:
elttype = check_typedef (TYPE_TARGET_TYPE (type));
- if (TYPE_CODE (elttype) == TYPE_CODE_MEMBER)
- {
- pascal_object_print_class_member (valaddr + embedded_offset,
- TYPE_DOMAIN_TYPE (elttype),
- stream, "");
- break;
- }
if (addressprint)
{
fprintf_filtered (stream, "@");
int, int, enum val_prettyprint,
struct type **);
-void
-pascal_object_print_class_method (const gdb_byte *valaddr, struct type *type,
- struct ui_file *stream)
-{
- struct type *domain;
- struct fn_field *f = NULL;
- int j = 0;
- int len2;
- int offset;
- char *kind = "";
- CORE_ADDR addr;
- struct symbol *sym;
- unsigned len;
- unsigned int i;
- struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type));
-
- domain = TYPE_DOMAIN_TYPE (target_type);
- if (domain == (struct type *) NULL)
- {
- fprintf_filtered (stream, "<unknown>");
- return;
- }
- addr = unpack_pointer (lookup_pointer_type (builtin_type_void), valaddr);
- if (METHOD_PTR_IS_VIRTUAL (addr))
- {
- offset = METHOD_PTR_TO_VOFFSET (addr);
- len = TYPE_NFN_FIELDS (domain);
- for (i = 0; i < len; i++)
- {
- 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) == offset)
- {
- kind = "virtual ";
- goto common;
- }
- }
- }
- }
- else
- {
- sym = find_pc_function (addr);
- if (sym == 0)
- {
- error (_("invalid pointer to member function"));
- }
- len = TYPE_NFN_FIELDS (domain);
- for (i = 0; i < len; i++)
- {
- 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 (DEPRECATED_STREQ (DEPRECATED_SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j)))
- goto common;
- }
- }
- }
-common:
- if (i < len)
- {
- char *demangled_name;
-
- fprintf_filtered (stream, "&");
- fputs_filtered (kind, stream);
- demangled_name = cplus_demangle (TYPE_FN_FIELD_PHYSNAME (f, j),
- DMGL_ANSI | DMGL_PARAMS);
- if (demangled_name == NULL)
- fprintf_filtered (stream, "<badly mangled name %s>",
- TYPE_FN_FIELD_PHYSNAME (f, j));
- else
- {
- fputs_filtered (demangled_name, stream);
- xfree (demangled_name);
- }
- }
- else
- {
- fprintf_filtered (stream, "(");
- type_print (type, "", stream, -1);
- fprintf_filtered (stream, ") %d", (int) addr >> 3);
- }
-}
-
/* It was changed to this after 2.4.5. */
const char pascal_vtbl_ptr_name[] =
{'_', '_', 'v', 't', 'b', 'l', '_', 'p', 't', 'r', '_', 't', 'y', 'p', 'e', 0};
common_val_print (val, stream, format, 0, recurse, pretty);
}
-void
-pascal_object_print_class_member (const gdb_byte *valaddr, struct type *domain,
- struct ui_file *stream, char *prefix)
-{
-
- /* VAL is a byte offset into the structure type DOMAIN.
- Find the name of the field for that offset and
- print it. */
- int extra = 0;
- int bits = 0;
- unsigned int i;
- unsigned len = TYPE_NFIELDS (domain);
- /* @@ Make VAL into bit offset */
- LONGEST val = unpack_long (builtin_type_int, valaddr) << 3;
- for (i = TYPE_N_BASECLASSES (domain); i < len; i++)
- {
- int bitpos = TYPE_FIELD_BITPOS (domain, i);
- QUIT;
- if (val == bitpos)
- break;
- if (val < bitpos && i != 0)
- {
- /* Somehow pointing into a field. */
- i -= 1;
- extra = (val - TYPE_FIELD_BITPOS (domain, i));
- if (extra & 0x7)
- bits = 1;
- else
- extra >>= 3;
- break;
- }
- }
- if (i < len)
- {
- char *name;
- fputs_filtered (prefix, stream);
- name = type_name_no_tag (domain);
- if (name)
- fputs_filtered (name, stream);
- else
- pascal_type_print_base (domain, stream, 0, 0);
- fprintf_filtered (stream, "::");
- fputs_filtered (TYPE_FIELD_NAME (domain, i), stream);
- if (extra)
- fprintf_filtered (stream, " + %d bytes", extra);
- if (bits)
- fprintf_filtered (stream, " (offset in bits)");
- }
- else
- fprintf_filtered (stream, "%ld", (long int) (val >> 3));
-}
-
extern initialize_file_ftype _initialize_pascal_valprint; /* -Wmissing-prototypes */
void
/* Support routines for decoding "stabs" debugging information format.
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
- 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This file is part of GDB.
memtype = read_type (pp, objfile);
type = dbx_alloc_type (typenums, objfile);
- smash_to_member_type (type, domain, memtype);
+ smash_to_memberptr_type (type, domain, memtype);
}
else
/* type attribute */
+2007-01-03 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * 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().
+
2007-01-03 Daniel Jacobowitz <dan@codesourcery.com>
* gdb.threads/tls.exp: Allow stops in sem_post.
# Copyright 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004 Free Software Foundation, Inc.
+# 2003, 2004, 2006 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# Pointers to class members
proc test_pointers_to_class_members {} {
- gdb_test "print Bar::z" "\\$\[0-9\]+ = \\(int ?\\( ?Bar::& ?\\) ?\\) ?Bar::z"
- gdb_test "print &Foo::x" "\\$\[0-9\]+ = \\(int ?\\( ?Foo::\\* ?\\) ?\\) ?&Foo::x"
+ gdb_test "print Bar::z" "Cannot reference non-static field \"z\""
+ gdb_test "print &Foo::x" "\\$\[0-9\]+ = &Foo::x"
gdb_test "print (int)&Foo::x" "\\$\[0-9\]+ = 0"
gdb_test "print (int)&Bar::y == 2*sizeof(int)" "\\$\[0-9\]+ = true"
+ gdb_test "ptype Bar::z" "type = int"
+ gdb_test "ptype &Bar::z" "type = int Bar::\\*"
+
# TODO: this is a bogus test. It's looking at a variable that
# has not even been declared yet, so it's accessing random junk
# on the stack and comparing that it's NOT equal to a specific
# Print the types of qualified members; none of these tests pass today.
# Print all members of g_A.
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_A.A::a" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_A.A::x" "type = int"
# Print all members of g_B.
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_B.A::a" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_B.A::x" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_B.B::b" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_B.B::x" "type = int"
# Print all members of g_C.
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_C.A::a" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_C.A::x" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_C.C::c" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_C.C::x" "type = int"
# Print all members of g_D.
set name "ptype g_D.A::a"
gdb_test_multiple "ptype g_D.A::a" $name {
- -re "Attempt to take address of non-lval$nl$gdb_prompt $" {
- kfail "gdb/2092" "$name"
- }
-re "type = int$nl$gdb_prompt $" {
kfail "gdb/68" "ptype g_D.A::a"
}
set name "ptype g_D.A::x"
gdb_test_multiple "ptype g_D.A::x" $name {
- -re "Attempt to take address of non-lval$nl$gdb_prompt $" {
- kfail "gdb/2092" "$name"
- }
-re "type = int$nl$gdb_prompt $" {
kfail "gdb/68" "ptype g_D.A::x"
}
}
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_D.B::b" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_D.B::x" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_D.C::c" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_D.C::x" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_D.D::d" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_D.D::x" "type = int"
# Print all members of g_E.
set name "ptype g_E.A::a"
gdb_test_multiple "ptype g_E.A::a" $name {
- -re "Attempt to take address of non-lval$nl$gdb_prompt $" {
- kfail "gdb/2092" "$name"
- }
-re "type = int$nl$gdb_prompt $" {
kfail "gdb/68" "ptype g_E.A::a"
}
set name "ptype g_E.A::x"
gdb_test_multiple "ptype g_E.A::x" $name {
- -re "Attempt to take address of non-lval$nl$gdb_prompt $" {
- kfail "gdb/2092" "$name"
- }
-re "type = int$nl$gdb_prompt $" {
kfail "gdb/68" "ptype g_E.A::x"
}
}
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_E.B::b" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_E.B::x" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_E.C::c" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_E.C::x" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_E.D::d" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_E.D::x" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_E.E::e" "type = int"
- setup_kfail "gdb/2092" "*-*-*"
gdb_test "ptype g_E.E::x" "type = int"
}
/* This testcase is part of GDB, the GNU debugger.
- Copyright 1998, 1999, 2004 Free Software Foundation, Inc.
+ Copyright 1998, 1999, 2004, 2006 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
typedef int A::*PMI;
+/* This class is in front of the other base classes of Diamond, so
+ that we can detect if the offset for Left or the first Base is
+ added twice - otherwise it would be 2 * 0 == 0. */
+class Padding
+{
+ int spacer;
+ virtual int vspacer();
+};
+
+int Padding::vspacer()
+{
+ return this->spacer;
+}
+
+class Base
+{
+public:
+ int x;
+ int get_x();
+ virtual int vget_base ();
+};
+
+int Base::get_x ()
+{
+ return this->x;
+}
+
+int Base::vget_base ()
+{
+ return this->x + 1000;
+}
+
+class Left : public Base {
+public:
+ virtual int vget ();
+};
+
+int Left::vget ()
+{
+ return this->x + 100;
+}
+
+class Right : public Base {
+public:
+ virtual int vget ();
+};
+
+int Right::vget ()
+{
+ return this->x + 200;
+}
+
+class Diamond : public Padding, public Left, public Right
+{
+public:
+ virtual int vget_base ();
+};
+
+int Diamond::vget_base ()
+{
+ return this->Left::x + 2000;
+}
+
int main ()
{
A a;
PMF * pmf_p;
PMI pmi;
+ Diamond diamond;
+ int (Diamond::*left_pmf) ();
+ int (Diamond::*right_pmf) ();
+ int (Diamond::*left_vpmf) ();
+ int (Diamond::*left_base_vpmf) ();
+ int (Diamond::*right_vpmf) ();
+ int (Base::*base_vpmf) ();
+ int Diamond::*diamond_pmi;
+
+ PMI null_pmi;
+ PMF null_pmf;
+
a.j = 121;
a.jj = 1331;
pmf = &A::bar;
pmf_p = &pmf;
- pmi = NULL;
-
+ diamond.Left::x = 77;
+ diamond.Right::x = 88;
+
+ /* Some valid pointer to members from a base class. */
+ left_pmf = (int (Diamond::*) ()) (int (Left::*) ()) (&Base::get_x);
+ right_pmf = (int (Diamond::*) ()) (int (Right::*) ()) (&Base::get_x);
+ left_vpmf = &Left::vget;
+ left_base_vpmf = (int (Diamond::*) ()) (int (Left::*) ()) (&Base::vget_base);
+ right_vpmf = &Right::vget;
+
+ /* An unspecified, value preserving pointer to member cast. */
+ base_vpmf = (int (Base::*) ()) (int (Left::*) ()) &Diamond::vget_base;
+
+ /* A pointer to data member from a base class. */
+ diamond_pmi = (int Diamond::*) (int Left::*) &Base::x;
+
+ null_pmi = NULL;
+ null_pmf = NULL;
+
+ pmi = NULL; /* Breakpoint 1 here. */
+
k = (a.*pmf)(3);
pmi = &A::jj;
-# Copyright 1998, 1999, 2003, 2004 Free Software Foundation, Inc.
+# Copyright 1998, 1999, 2003, 2004, 2006 Free Software Foundation, Inc.
# This file is part of the gdb testsuite
# Written by Satish Pai <pai@apollo.hp.com> 1997-08-19
# Rewritten by Michael Chastain <mec.gnu@mindspring.com> 2004-01-11
-# TODO: copyright notice for member-ptr.cc
-
set vhn "\\$\[0-9\]+"
if $tracelevel then {
continue
}
-gdb_breakpoint [gdb_get_line_number "pmi = NULL"]
+gdb_breakpoint [gdb_get_line_number "Breakpoint 1 here"]
gdb_continue_to_breakpoint "continue to pmi = NULL"
-# gcc is not ready for production
-# -- chastain 2004-01-12
-
-if { [test_compiler_info "gcc-*"] } {
- continue
-}
-
# ======================
# pointer to member data
# ======================
set name "ptype pmi (A::j)"
gdb_test_multiple "ptype pmi" $name {
- -re "type = int *\\( ?A::\\*\\)\r\n$gdb_prompt $" {
+ -re "type = int A::\\*\r\n$gdb_prompt $" {
pass $name
}
- -re "type = int *A::\r\n$gdb_prompt $" {
- # gcc HEAD 2004-01-10 -gdwarf-2
- # gcc HEAD 2004-01-10 -gstabs+
- kfail "gdb/NNNN" $name
- }
}
# print pointer to data member
set name "print (int) pmi"
gdb_test_multiple "print (int) pmi" $name {
- -re "$vhn = (4|8)\r\n$gdb_prompt" {
+ -re "$vhn = (4|8|12)\r\n$gdb_prompt" {
pass $name
}
}
set name "ptype pmf"
gdb_test_multiple "ptype pmf" $name {
- -re "type = int \\( ?A::\\*\\)\\(int\\)\r\n$gdb_prompt $" {
+ -re "type = int \\( ?A::\\*\\)\\(A \\*, int\\)\r\n$gdb_prompt $" {
pass $name
}
-re "type = int \\( ?A::\\*\\)\\(void\\)\r\n$gdb_prompt $" {
set name "print pmf"
gdb_test_multiple "print pmf" $name {
- -re "$vhn = &A::bar\r\n$gdb_prompt $" {
+ -re "$vhn = $hex <A::bar\\(int\\)>\r\n$gdb_prompt $" {
pass $name
}
-re "$vhn = .*not supported with HP aCC.*\r\n$gdb_prompt $" {
set name "ptype pmf_p"
gdb_test_multiple "ptype pmf_p" $name {
- -re "type = int \\( ?A::\\*\\*\\)\\(int\\)\r\n$gdb_prompt $" {
+ -re "type = int \\( ?A::\\*\\*\\)\\(A \\*, int\\)\r\n$gdb_prompt $" {
pass $name
}
-re "type = int \\( ?A::\\*\\*\\)\\(void\\)\r\n$gdb_prompt $" {
set name "print a.*pmf"
gdb_test_multiple "print a.*pmf" $name {
- -re "$vhn = \\(int \\(\\*\\)\\(int\\)\\) $hex <A::bar\\(int\\)>\r\n$gdb_prompt$ " {
+ -re "$vhn = {int \\(A \\*, int\\)} $hex <A::bar\\(int\\)>\r\n$gdb_prompt $" {
pass $name
}
-re "Pointers to methods not supported with HP aCC\r\n$gdb_prompt $" {
set name "print a_p->*pmf"
gdb_test_multiple "print a_p->*pmf" $name {
- -re "$vhn = \\(int \\(\\*\\)\\(int\\)\\) $hex <A::bar\\(int\\)>\r\n$gdb_prompt$ " {
+ -re "$vhn = {int \\(A \\*, int\\)} $hex <A::bar\\(int\\)>\r\n$gdb_prompt $" {
pass $name
}
-re "Pointers to methods not supported with HP aCC\r\n$gdb_prompt $" {
kfail "gdb/NNNN" $name
}
}
+
+# Print out a pointer to data member which requires looking into
+# a base class.
+gdb_test "print diamond_pmi" "$vhn = &Base::x"
+gdb_test "print diamond.*diamond_pmi" "$vhn = 77"
+
+# Examine some more complicated pmfs, which require adjusting "this"
+# and looking through virtual tables.
+
+# These two have a different object adjustment, but call the same method.
+gdb_test "print diamond.*left_pmf" \
+ "$vhn = {int \\(Diamond \\*\\)} $hex <Base::get_x\\((void|)\\)>"
+gdb_test "print diamond.*right_pmf" \
+ "$vhn = {int \\(Diamond \\*\\)} $hex <Base::get_x\\((void|)\\)>"
+
+gdb_test "print (diamond.*left_pmf) ()" "$vhn = 77"
+gdb_test "print (diamond.*right_pmf) ()" "$vhn = 88"
+
+# These two point to different methods, although they have the same
+# virtual table offsets.
+gdb_test "print diamond.*left_vpmf" \
+ "$vhn = {int \\(Diamond \\*\\)} $hex <Left::vget\\((void|)\\)>"
+gdb_test "print diamond.*right_vpmf" \
+ "$vhn = {int \\(Diamond \\*\\)} $hex <Right::vget\\((void|)\\)>"
+
+gdb_test "print (diamond.*left_vpmf) ()" "$vhn = 177"
+gdb_test "print (diamond.*left_base_vpmf) ()" "$vhn = 2077"
+gdb_test "print (diamond.*right_vpmf) ()" "$vhn = 288"
+
+# We should be able to figure out left_vpmf even without an object,
+# because it comes from a non-virtual base. The same for right_vpmf.
+gdb_test "print left_vpmf" "$vhn = &virtual Left::vget\\(\\)"
+gdb_test "print right_vpmf" "$vhn = &virtual Right::vget\\(\\)"
+
+# But we should gracefully fail to figure out base_vpmf, because
+# its runtime type is more derived than its static type. This
+# is a valid but unspecified cast (it is value preserving, i.e.
+# can be casted back to the correct type and used).
+gdb_test "print base_vpmf" \
+ "$vhn = &virtual table offset \[0-9\]*, this adjustment -\[0-9\]*"
+
+# Make sure we parse this correctly; it's invalid.
+gdb_test "print diamond.*left_vpmf ()" \
+ "Invalid data type for function to be called\\."
+
+# NULL pointer to member tests.
+gdb_test "print null_pmi" "$vhn = NULL"
+gdb_test "print null_pmi = &A::j" "$vhn = &A::j"
+gdb_test "print null_pmi = 0" "$vhn = NULL"
+
+gdb_test "print null_pmf" "$vhn = NULL"
+gdb_test "print null_pmf = &A::foo" "$vhn = $hex <A::foo ?\\(int\\)>"
+gdb_test "print null_pmf = 0" "$vhn = NULL"
-# Copyright 2002, 2003, 2005 Free Software Foundation, Inc.
+# Copyright 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# The first of these is for PR gdb/653.
-gdb_test "print theA->virt" "\\$\[0-9\]* = &A::virt\\((void|)\\)" "print virtual method."
-gdb_test "print theA->nonvirt" "\\$\[0-9\]* = &A::nonvirt\\((void|)\\)" "print nonvirtual method."
+gdb_test "print theA->virt" \
+ "\\$\[0-9\]* = {void \\(A \\*\\)} $hex <A::virt\\((void|)\\)>" \
+ "print virtual method."
+gdb_test "print theA->nonvirt" \
+ "\\$\[0-9\]* = {void \\(A \\*\\)} $hex <A::nonvirt\\((void|)\\)>" \
+ "print nonvirtual method."
gdb_exit
return 0
-# Copyright 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004
+# Copyright 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004,
+# 2006
# Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
-re "\\$\[0-9]+ = 102$nl$gdb_prompt $" {
pass "print pEe->D::vg()"
}
+ -re "\\$\[0-9]+ = 202$nl$gdb_prompt $" {
+ # To get this result, we have called pEe->*(&D::vg) ().
+ # That's how GDB interprets this, but it's wrong; in fact
+ # the explicit D:: means to bypass virtual function lookup,
+ # and call D::vg as if it were non-virtual. We still have
+ # to e.g. adjust "this", though.
+ kfail "gdb/1064" "print pEe->D::vg()"
+ }
-re "Attempt to take address of value not located in memory.$nl$gdb_prompt $" {
kfail "gdb/1064" "print pEe->D::vg()"
}
/* Language independent support for printing types for GDB, the GNU debugger.
Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1998,
- 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2003, 2006 Free Software Foundation, Inc.
This file is part of GDB.
case TYPE_CODE_SET:
case TYPE_CODE_STRING:
case TYPE_CODE_ERROR:
- case TYPE_CODE_MEMBER:
+ case TYPE_CODE_MEMBERPTR:
+ case TYPE_CODE_METHODPTR:
case TYPE_CODE_METHOD:
case TYPE_CODE_REF:
case TYPE_CODE_NAMESPACE:
/* Perform non-arithmetic operations on values, for GDB.
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
- 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ 2006
Free Software Foundation, Inc.
This file is part of GDB.
struct type *curtype,
char *name,
struct type *intype,
+ int want_address,
enum noside noside);
static struct value *value_namespace_elt (const struct type *curtype,
- char *name,
+ char *name, int want_address,
enum noside noside);
static struct value *value_maybe_namespace_elt (const struct type *curtype,
- char *name,
+ char *name, int want_address,
enum noside noside);
static CORE_ADDR allocate_space_in_inferior (int);
}
/* No superclass found, just change the pointer type. */
+ arg2 = value_copy (arg2);
deprecated_set_value_type (arg2, type);
arg2 = value_change_enclosing_type (arg2, type);
set_value_pointed_to_offset (arg2, 0); /* pai: chk_val */
return value_from_double (type, value_as_double (arg2));
else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM
|| code1 == TYPE_CODE_RANGE)
- && (scalar || code2 == TYPE_CODE_PTR))
+ && (scalar || code2 == TYPE_CODE_PTR
+ || code2 == TYPE_CODE_MEMBERPTR))
{
LONGEST longest;
- if (deprecated_hp_som_som_object_present /* if target compiled by HP aCC */
- && (code2 == TYPE_CODE_PTR))
+ /* If target compiled by HP aCC. */
+ if (deprecated_hp_som_som_object_present
+ && code2 == TYPE_CODE_MEMBERPTR)
{
unsigned int *ptr;
struct value *retvalp;
- switch (TYPE_CODE (TYPE_TARGET_TYPE (type2)))
- {
- /* With HP aCC, pointers to data members have a bias */
- case TYPE_CODE_MEMBER:
- retvalp = value_from_longest (type, value_as_long (arg2));
- /* force evaluation */
- ptr = (unsigned int *) value_contents (retvalp);
- *ptr &= ~0x20000000; /* zap 29th bit to remove bias */
- return retvalp;
-
- /* While pointers to methods don't really point to a function */
- case TYPE_CODE_METHOD:
- error (_("Pointers to methods not supported with HP aCC"));
-
- default:
- break; /* fall out and go to normal handling */
- }
+ /* With HP aCC, pointers to data members have a bias. */
+ retvalp = value_from_longest (type, value_as_long (arg2));
+ /* force evaluation */
+ ptr = (unsigned int *) value_contents (retvalp);
+ *ptr &= ~0x20000000; /* zap 29th bit to remove bias */
+ return retvalp;
}
/* When we cast pointers to integers, we mustn't use
}
return value_from_longest (type, longest);
}
+ else if (code1 == TYPE_CODE_METHODPTR && code2 == TYPE_CODE_INT
+ && value_as_long (arg2) == 0)
+ {
+ struct value *result = allocate_value (type);
+ cplus_make_method_ptr (value_contents_writeable (result), 0, 0);
+ return result;
+ }
+ else if (code1 == TYPE_CODE_MEMBERPTR && code2 == TYPE_CODE_INT
+ && value_as_long (arg2) == 0)
+ {
+ /* The Itanium C++ ABI represents NULL pointers to members as
+ minus one, instead of biasing the normal case. */
+ return value_from_longest (type, -1);
+ }
else if (TYPE_LENGTH (type) == TYPE_LENGTH (type2))
{
if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR)
return value_cast_pointers (type, arg2);
+ arg2 = value_copy (arg2);
deprecated_set_value_type (arg2, type);
arg2 = value_change_enclosing_type (arg2, type);
set_value_pointed_to_offset (arg2, 0); /* pai: chk_val */
base_type = check_typedef (value_type (arg1));
- if (TYPE_CODE (base_type) == TYPE_CODE_MEMBER)
- error (_("not implemented: member types in value_ind"));
-
/* Allow * on an integer so we can cast it to whatever we want.
This returns an int, which seems like the most C-like thing
to do. "long long" variables are rare enough that
/* Get the real type of the enclosing object */
enc_type = check_typedef (value_enclosing_type (arg1));
enc_type = TYPE_TARGET_TYPE (enc_type);
- /* Retrieve the enclosing object pointed to */
- arg2 = value_at_lazy (enc_type, (value_as_address (arg1)
- - value_pointed_to_offset (arg1)));
+
+ if (TYPE_CODE (check_typedef (enc_type)) == TYPE_CODE_FUNC
+ || TYPE_CODE (check_typedef (enc_type)) == TYPE_CODE_METHOD)
+ /* For functions, go through find_function_addr, which knows
+ how to handle function descriptors. */
+ arg2 = value_at_lazy (enc_type, find_function_addr (arg1, NULL));
+ else
+ /* Retrieve the enclosing object pointed to */
+ arg2 = value_at_lazy (enc_type, (value_as_address (arg1)
+ - value_pointed_to_offset (arg1)));
+
/* Re-adjust type */
deprecated_set_value_type (arg2, TYPE_TARGET_TYPE (base_type));
/* Add embedding info */
t = check_typedef (value_type (*argp));
}
- if (TYPE_CODE (t) == TYPE_CODE_MEMBER)
- error (_("not implemented: member type in value_struct_elt"));
-
if (TYPE_CODE (t) != TYPE_CODE_STRUCT
&& TYPE_CODE (t) != TYPE_CODE_UNION)
error (_("Attempt to extract a component of a value that is not a %s."), err);
t = check_typedef (value_type (*argp));
}
- if (TYPE_CODE (t) == TYPE_CODE_MEMBER)
- error (_("Not implemented: member type in value_find_oload_lis"));
-
if (TYPE_CODE (t) != TYPE_CODE_STRUCT
&& TYPE_CODE (t) != TYPE_CODE_UNION)
error (_("Attempt to extract a component of a value that is not a struct or union"));
t = TYPE_TARGET_TYPE (t);
}
- if (TYPE_CODE (t) == TYPE_CODE_MEMBER)
- error (_("not implemented: member type in check_field"));
-
if (TYPE_CODE (t) != TYPE_CODE_STRUCT
&& TYPE_CODE (t) != TYPE_CODE_UNION)
error (_("Internal error: `this' is not an aggregate"));
}
/* C++: Given an aggregate type CURTYPE, and a member name NAME,
- return the appropriate member. This function is used to resolve
- user expressions of the form "DOMAIN::NAME". For more details on
- what happens, see the comment before
- value_struct_elt_for_reference. */
+ return the appropriate member (or the address of the member, if
+ WANT_ADDRESS). This function is used to resolve user expressions
+ of the form "DOMAIN::NAME". For more details on what happens, see
+ the comment before value_struct_elt_for_reference. */
struct value *
value_aggregate_elt (struct type *curtype,
- char *name,
+ char *name, int want_address,
enum noside noside)
{
switch (TYPE_CODE (curtype))
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
return value_struct_elt_for_reference (curtype, 0, curtype, name, NULL,
- noside);
+ want_address, noside);
case TYPE_CODE_NAMESPACE:
- return value_namespace_elt (curtype, name, noside);
+ return value_namespace_elt (curtype, name, want_address, noside);
default:
internal_error (__FILE__, __LINE__,
_("non-aggregate type in value_aggregate_elt"));
static struct value *
value_struct_elt_for_reference (struct type *domain, int offset,
struct type *curtype, char *name,
- struct type *intype,
+ struct type *intype, int want_address,
enum noside noside)
{
struct type *t = curtype;
int i;
- struct value *v;
+ struct value *v, *result;
if (TYPE_CODE (t) != TYPE_CODE_STRUCT
&& TYPE_CODE (t) != TYPE_CODE_UNION)
if (v == NULL)
error (_("static field %s has been optimized out"),
name);
+ if (want_address)
+ v = value_addr (v);
return v;
}
if (TYPE_FIELD_PACKED (t, i))
error (_("pointers to bitfield members not allowed"));
- return value_from_longest
- (lookup_reference_type (lookup_member_type (TYPE_FIELD_TYPE (t, i),
- domain)),
- offset + (LONGEST) (TYPE_FIELD_BITPOS (t, i) >> 3));
+ if (want_address)
+ return value_from_longest
+ (lookup_memberptr_type (TYPE_FIELD_TYPE (t, i), domain),
+ offset + (LONGEST) (TYPE_FIELD_BITPOS (t, i) >> 3));
+ else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return allocate_value (TYPE_FIELD_TYPE (t, i));
+ else
+ error (_("Cannot reference non-static field \"%s\""), name);
}
}
else
j = 0;
+ if (TYPE_FN_FIELD_STATIC_P (f, j))
+ {
+ struct symbol *s = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j),
+ 0, VAR_DOMAIN, 0, NULL);
+ if (s == NULL)
+ return NULL;
+
+ if (want_address)
+ return value_addr (read_var_value (s, 0));
+ else
+ return read_var_value (s, 0);
+ }
+
if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
{
- return value_from_longest
- (lookup_reference_type
- (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j),
- domain)),
- (LONGEST) METHOD_PTR_FROM_VOFFSET (TYPE_FN_FIELD_VOFFSET (f, j)));
+ if (want_address)
+ {
+ result = allocate_value
+ (lookup_methodptr_type (TYPE_FN_FIELD_TYPE (f, j)));
+ cplus_make_method_ptr (value_contents_writeable (result),
+ TYPE_FN_FIELD_VOFFSET (f, j), 1);
+ }
+ else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return allocate_value (TYPE_FN_FIELD_TYPE (f, j));
+ else
+ error (_("Cannot reference virtual member function \"%s\""),
+ name);
}
else
{
struct symbol *s = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j),
0, VAR_DOMAIN, 0, NULL);
if (s == NULL)
- {
- v = 0;
- }
+ return NULL;
+
+ v = read_var_value (s, 0);
+ if (!want_address)
+ result = v;
else
{
- v = read_var_value (s, 0);
-#if 0
- VALUE_TYPE (v) = lookup_reference_type
- (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j),
- domain));
-#endif
+ result = allocate_value (lookup_methodptr_type (TYPE_FN_FIELD_TYPE (f, j)));
+ cplus_make_method_ptr (value_contents_writeable (result),
+ VALUE_ADDRESS (v), 0);
}
- return v;
}
+ return result;
}
}
for (i = TYPE_N_BASECLASSES (t) - 1; i >= 0; i--)
offset + base_offset,
TYPE_BASECLASS (t, i),
name,
- intype,
+ intype, want_address,
noside);
if (v)
return v;
it up that way; this (frequently) works for types nested inside
classes. */
- return value_maybe_namespace_elt (curtype, name, noside);
+ return value_maybe_namespace_elt (curtype, name, want_address, noside);
}
/* C++: Return the member NAME of the namespace given by the type
static struct value *
value_namespace_elt (const struct type *curtype,
- char *name,
+ char *name, int want_address,
enum noside noside)
{
struct value *retval = value_maybe_namespace_elt (curtype, name,
- noside);
+ want_address, noside);
if (retval == NULL)
error (_("No symbol \"%s\" in namespace \"%s\"."), name,
static struct value *
value_maybe_namespace_elt (const struct type *curtype,
- char *name,
+ char *name, int want_address,
enum noside noside)
{
const char *namespace_name = TYPE_TAG_NAME (curtype);
struct symbol *sym;
+ struct value *result;
sym = cp_lookup_symbol_namespace (namespace_name, name, NULL,
get_selected_block (0), VAR_DOMAIN,
return NULL;
else if ((noside == EVAL_AVOID_SIDE_EFFECTS)
&& (SYMBOL_CLASS (sym) == LOC_TYPEDEF))
- return allocate_value (SYMBOL_TYPE (sym));
+ result = allocate_value (SYMBOL_TYPE (sym));
else
- return value_of_variable (sym, get_selected_block (0));
+ result = value_of_variable (sym, get_selected_block (0));
+
+ if (result && want_address)
+ result = value_addr (result);
+
+ return result;
}
/* Given a pointer value V, find the real (RTTI) type
case TYPE_CODE_INT:
case TYPE_CODE_CHAR:
case TYPE_CODE_RANGE:
+ case TYPE_CODE_MEMBERPTR:
if (nosign)
return extract_unsigned_integer (valaddr, len);
else
whether we want this to be true eventually. */
return extract_typed_address (valaddr, type);
- case TYPE_CODE_MEMBER:
- error (_("not implemented: member types in unpack_long"));
-
default:
error (_("Value can't be converted to integer."));
}
case TYPE_CODE_FLAGS:
case TYPE_CODE_BOOL:
case TYPE_CODE_RANGE:
+ case TYPE_CODE_MEMBERPTR:
store_signed_integer (value_contents_raw (val), len, num);
break;
/* Definitions for values of C expressions, for GDB.
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
- 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ 2006
Free Software Foundation, Inc.
This file is part of GDB.
char *err);
extern struct value *value_aggregate_elt (struct type *curtype,
- char *name, enum noside noside);
+ char *name,
+ int want_address,
+ enum noside noside);
extern struct value *value_static_field (struct type *type, int fieldno);
case TYPE_CODE_UNION:
case TYPE_CODE_ARRAY:
case TYPE_CODE_FUNC:
- case TYPE_CODE_MEMBER:
case TYPE_CODE_METHOD:
return 0;
break;