diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4c35ceb0e54..cd956b62d05 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,93 @@ +2007-01-03 Daniel Jacobowitz + + * 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 * rs6000-tdep.c (rs6000_use_struct_convention) diff --git a/gdb/Makefile.in b/gdb/Makefile.in index ead6f31092b..1b3e4730d58 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -1527,13 +1527,6 @@ main.o: main.c $(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 @@ -1973,7 +1966,7 @@ environ.o: environ.c $(defs_h) $(environ_h) $(gdb_string_h) 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) \ @@ -2052,7 +2045,7 @@ gnu-v2-abi.o: gnu-v2-abi.c $(defs_h) $(gdb_string_h) $(symtab_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) \ @@ -2168,7 +2161,8 @@ ia64-tdep.o: ia64-tdep.c $(defs_h) $(inferior_h) $(gdbcore_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) \ diff --git a/gdb/NEWS b/gdb/NEWS index 22b75188ef4..3a9f330bb3c 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -9,6 +9,8 @@ frequency signals (e.g. SIGALRM) via the QPassSignals packet. * 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 diff --git a/gdb/ada-valprint.c b/gdb/ada-valprint.c index 7781fada9a2..fd7bceff39e 100644 --- a/gdb/ada-valprint.c +++ b/gdb/ada-valprint.c @@ -420,7 +420,8 @@ ada_print_scalar (struct type *type, LONGEST val, struct ui_file *stream) 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")); diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index f4a6a37f2dd..a1c90533866 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -2816,6 +2816,9 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) 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); diff --git a/gdb/c-lang.h b/gdb/c-lang.h index 63a92ec2ab3..74d9fe6a326 100644 --- a/gdb/c-lang.h +++ b/gdb/c-lang.h @@ -1,7 +1,7 @@ /* 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. @@ -79,9 +79,6 @@ extern int static_field_print; 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, diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c index 8ac2c037cb6..518af681efb 100644 --- a/gdb/c-typeprint.c +++ b/gdb/c-typeprint.c @@ -1,6 +1,6 @@ /* 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. @@ -80,7 +80,8 @@ c_print_type (struct type *type, char *varstring, struct ui_file *stream, (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); @@ -218,29 +219,25 @@ c_type_print_varspec_prefix (struct type *type, struct ui_file *stream, 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: @@ -249,6 +246,7 @@ c_type_print_varspec_prefix (struct type *type, struct ui_file *stream, 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) @@ -337,42 +335,49 @@ c_type_print_modifier (struct type *type, struct ui_file *stream, } - +/* 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) + len = TYPE_NFIELDS (type); + + for (i = 0; i < TYPE_NFIELDS (type); i++) { - int i; - - /* FIXME drow/2002-05-31: Always skips the first argument, - should we be checking for static members? */ - - for (i = 1; 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, ")"); } @@ -548,22 +553,15 @@ c_type_print_varspec_suffix (struct type *type, struct ui_file *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: @@ -572,31 +570,12 @@ c_type_print_varspec_suffix (struct type *type, struct ui_file *stream, 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; @@ -696,10 +675,11 @@ c_type_print_base (struct type *type, struct ui_file *stream, int show, 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; diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c index 861e3bfe2e1..655786f81bc 100644 --- a/gdb/c-valprint.c +++ b/gdb/c-valprint.c @@ -142,6 +142,21 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, 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') { @@ -159,17 +174,6 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, 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: @@ -250,19 +254,8 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, } 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 @@ -351,6 +344,7 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, break; case TYPE_CODE_FUNC: + case TYPE_CODE_METHOD: if (format) { print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream); @@ -442,14 +436,6 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, } 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; diff --git a/gdb/cp-abi.c b/gdb/cp-abi.c index af35dd8896a..7dad2b7cc4c 100644 --- a/gdb/cp-abi.c +++ b/gdb/cp-abi.c @@ -1,6 +1,6 @@ /* 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. @@ -95,6 +95,39 @@ value_rtti_type (struct value *v, int *full, int *top, int *using_enc) 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 diff --git a/gdb/cp-abi.h b/gdb/cp-abi.h index 6c77824d15f..1e22dbbfc14 100644 --- a/gdb/cp-abi.h +++ b/gdb/cp-abi.h @@ -3,7 +3,7 @@ Contributed by Daniel Berlin - Copyright (C) 2001, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2005, 2006 Free Software Foundation, Inc. This file is part of GDB. @@ -30,6 +30,7 @@ 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 @@ -147,6 +148,28 @@ extern struct type *value_rtti_type (struct value *value, 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; @@ -164,6 +187,11 @@ struct cp_abi_ops 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 *); }; diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c index 84b66fe7a81..911c924f315 100644 --- a/gdb/cp-valprint.c +++ b/gdb/cp-valprint.c @@ -1,7 +1,8 @@ /* 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. @@ -92,104 +93,6 @@ static void cp_print_hpacc_virtual_table_entries (struct type *, int *, 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, ""); - 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 ("?? ", 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, "", - 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"; @@ -703,48 +606,82 @@ cp_print_static_field (struct type *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); @@ -754,14 +691,10 @@ cp_print_class_member (const gdb_byte *valaddr, struct type *domain, 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); } diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 19c51d60735..3dcf436210d 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -3699,7 +3699,6 @@ dwarf2_attach_fn_fields_to_type (struct field_info *fip, struct type *type, 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 @@ -3779,7 +3778,7 @@ quirk_gcc_member_function_pointer (struct die_info *die, struct dwarf2_cu *cu) 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; @@ -4561,10 +4560,13 @@ read_tag_ptr_to_member_type (struct die_info *die, struct dwarf2_cu *cu) 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); } diff --git a/gdb/eval.c b/gdb/eval.c index e1076e1efd4..1a3d72a5478 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -1,8 +1,8 @@ /* 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. @@ -38,6 +38,8 @@ #include "parser-defs.h" #include "cp-support.h" +#include "gdb_assert.h" + /* This is defined in valops.c */ extern int overload_resolution; @@ -434,9 +436,11 @@ evaluate_subexp_standard (struct type *expect_type, 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; @@ -993,8 +997,6 @@ evaluate_subexp_standard (struct type *expect_type, 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. */ @@ -1027,41 +1029,18 @@ evaluate_subexp_standard (struct type *expect_type, 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; @@ -1396,57 +1375,60 @@ evaluate_subexp_standard (struct type *expect_type, } case STRUCTOP_MEMBER: - arg1 = evaluate_subexp_for_address (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 */ - - mem_offset = value_as_long (arg2); - goto handle_pointer_to_member; - case STRUCTOP_MPTR: - arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + 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 */ - - mem_offset = value_as_long (arg2); - - 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; - } 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")); + 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")); + } + + 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); + } + + 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); + 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; + } + + 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")); + } case BINOP_CONCAT: arg1 = evaluate_subexp_with_coercion (exp, pos, noside); @@ -1469,13 +1451,11 @@ evaluate_subexp_standard (struct type *expect_type, 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 */ @@ -1934,9 +1914,9 @@ evaluate_subexp_standard (struct type *expect_type, 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; @@ -1967,22 +1947,15 @@ evaluate_subexp_standard (struct type *expect_type, 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 */ @@ -2148,6 +2121,7 @@ evaluate_subexp_for_address (struct expression *exp, int *pos, int pc; struct symbol *var; struct value *x; + int tem; pc = (*pos); op = exp->elts[pc].opcode; @@ -2162,15 +2136,7 @@ evaluate_subexp_for_address (struct expression *exp, int *pos, 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; @@ -2210,14 +2176,30 @@ evaluate_subexp_for_address (struct expression *exp, int *pos, (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")); } diff --git a/gdb/f-typeprint.c b/gdb/f-typeprint.c index 31b96a371f1..9c157dade76 100644 --- a/gdb/f-typeprint.c +++ b/gdb/f-typeprint.c @@ -73,7 +73,6 @@ f_print_type (struct type *type, char *varstring, struct ui_file *stream, (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); @@ -138,7 +137,6 @@ f_type_print_varspec_prefix (struct type *type, struct ui_file *stream, 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: @@ -250,7 +248,6 @@ f_type_print_varspec_suffix (struct type *type, struct ui_file *stream, 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 diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 6939312d833..3ef1bd3a45a 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -235,6 +235,8 @@ struct gdbarch 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; }; @@ -361,6 +363,8 @@ struct gdbarch startup_gdbarch = 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() */ }; @@ -615,6 +619,8 @@ verify_gdbarch (struct gdbarch *current_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) @@ -1595,6 +1601,9 @@ gdbarch_dump (struct gdbarch *current_gdbarch, struct ui_file *file) 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", @@ -1604,6 +1613,9 @@ gdbarch_dump (struct gdbarch *current_gdbarch, struct ui_file *file) 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", @@ -3653,6 +3665,40 @@ set_gdbarch_regset_from_core_section (struct gdbarch *gdbarch, 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. */ diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 30ae3d0164c..81761f8c1b9 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -1383,6 +1383,19 @@ typedef const struct regset * (gdbarch_regset_from_core_section_ftype) (struct g 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); diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index a3142ff33bb..f1549062f95 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -663,6 +663,15 @@ F:=:CORE_ADDR:fetch_pointer_argument:struct frame_info *frame, int argi, struct # 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 } diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 8a57678c19c..308e6c21a74 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -621,15 +621,30 @@ replace_type (struct type *ntype, struct type *type) 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 @@ -981,19 +996,20 @@ build_builtin_type_vec128 (void) 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; @@ -1003,8 +1019,10 @@ smash_to_member_type (struct type *type, struct type *domain, 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. @@ -2643,7 +2661,7 @@ rank_one_type (struct type *parm, struct type *arg) return INCOMPATIBLE_TYPE_BADNESS; } break; - case TYPE_CODE_MEMBER: + case TYPE_CODE_MEMBERPTR: switch (TYPE_CODE (arg)) { default: @@ -2957,8 +2975,11 @@ recursive_dump_type (struct type *type, int spaces) 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)"); diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 944e5f12bed..91207372f36 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -142,8 +142,20 @@ enum type_code 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 */ @@ -464,8 +476,9 @@ struct main_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. @@ -1220,14 +1233,16 @@ extern const char *address_space_int_to_name (int); 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 void -smash_to_method_type (struct type *type, struct type *domain, - struct type *to_type, struct field *args, - int nargs, int varargs); +extern struct type *lookup_methodptr_type (struct type *); -extern void smash_to_member_type (struct type *, struct 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_memberptr_type (struct type *, struct type *, + struct type *); extern struct type *allocate_stub_method (struct type *); diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c index 383b475f1b1..c3a3913a2a1 100644 --- a/gdb/gnu-v3-abi.c +++ b/gdb/gnu-v3-abi.c @@ -1,7 +1,8 @@ /* Abstraction of GNU v3 abi. Contributed by Jim Blandy - Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2003, 2005, 2006 + Free Software Foundation, Inc. This file is part of GDB. @@ -25,6 +26,8 @@ #include "cp-abi.h" #include "cp-support.h" #include "demangle.h" +#include "valprint.h" + #include "gdb_assert.h" #include "gdb_string.h" @@ -274,77 +277,92 @@ gnuv3_rtti_type (struct value *value, return run_time_type; } +/* Find the vtable for CONTAINER and return a value of the correct + vtable type for this architecture. */ + +static struct value * +gnuv3_get_vtable (struct value *container) +{ + struct type *vtable_type = gdbarch_data (current_gdbarch, + vtable_type_gdbarch_data); + struct type *vtable_pointer_type; + struct value *vtable_pointer; + CORE_ADDR vtable_pointer_address, vtable_address; + + /* We do not consult the debug information to find the virtual table. + The ABI specifies that it is always at offset zero in any class, + and debug information may not represent it. We won't issue an + error if there's a class with virtual functions but no virtual table + pointer, but something's already gone seriously wrong if that + happens. + + We avoid using value_contents on principle, because the object might + be large. */ + + /* Find the type "pointer to virtual table". */ + vtable_pointer_type = lookup_pointer_type (vtable_type); + + /* Load it from the start of the class. */ + vtable_pointer_address = value_as_address (value_addr (container)); + vtable_pointer = value_at (vtable_pointer_type, vtable_pointer_address); + vtable_address = value_as_address (vtable_pointer); + + /* Correct it to point at the start of the virtual table, rather + than the address point. */ + return value_at_lazy (vtable_type, + vtable_address - vtable_address_point_offset ()); +} + +/* Return a function pointer for CONTAINER's VTABLE_INDEX'th virtual + function, of type FNTYPE. */ + +static struct value * +gnuv3_get_virtual_fn (struct value *container, struct type *fntype, + int vtable_index) +{ + struct value *vtable = gnuv3_get_vtable (container); + struct value *vfn; + + /* Fetch the appropriate function pointer from the vtable. */ + vfn = value_subscript (value_field (vtable, vtable_field_virtual_functions), + value_from_longest (builtin_type_int, vtable_index)); + + /* If this architecture uses function descriptors directly in the vtable, + then the address of the vtable entry is actually a "function pointer" + (i.e. points to the descriptor). We don't need to scale the index + by the size of a function descriptor; GCC does that before outputing + debug information. */ + if (gdbarch_vtable_function_descriptors (current_gdbarch)) + vfn = value_addr (vfn); + + /* Cast the function pointer to the appropriate type. */ + vfn = value_cast (lookup_pointer_type (fntype), vfn); + + return vfn; +} + +/* GNU v3 implementation of value_virtual_fn_field. See cp-abi.h + for a description of the arguments. */ static struct value * gnuv3_virtual_fn_field (struct value **value_p, struct fn_field *f, int j, - struct type *type, int offset) + struct type *vfn_base, int offset) { - struct type *vtable_type = gdbarch_data (current_gdbarch, - vtable_type_gdbarch_data); - struct value *value = *value_p; - struct type *values_type = check_typedef (value_type (value)); - struct type *vfn_base; - CORE_ADDR vtable_address; - struct value *vtable; - struct value *vfn; + struct type *values_type = check_typedef (value_type (*value_p)); /* Some simple sanity checks. */ if (TYPE_CODE (values_type) != TYPE_CODE_CLASS) error (_("Only classes can have virtual functions.")); - /* Find the base class that defines this virtual function. */ - vfn_base = TYPE_FN_FIELD_FCONTEXT (f, j); - if (! vfn_base) - /* In programs compiled with G++ version 1, the debug info doesn't - say which base class defined the virtual function. We'll guess - it's the same base class that has our vtable; this is wrong for - multiple inheritance, but it's better than nothing. */ - vfn_base = TYPE_VPTR_BASETYPE (type); - - /* This type may have been defined before its virtual function table - was. If so, fill in the virtual function table entry for the - type now. */ - if (TYPE_VPTR_FIELDNO (vfn_base) < 0) - fill_in_vptr_fieldno (vfn_base); - if (TYPE_VPTR_FIELDNO (vfn_base) < 0) - error (_("Could not find virtual table pointer for class \"%s\"."), - TYPE_TAG_NAME (vfn_base) ? TYPE_TAG_NAME (vfn_base) : ""); - - /* Now that we know which base class is defining our virtual - function, cast our value to that baseclass. This takes care of - any necessary `this' adjustments. */ + /* Cast our value to the base class which defines this virtual + function. This takes care of any necessary `this' + adjustments. */ if (vfn_base != values_type) - value = value_cast (vfn_base, value); + *value_p = value_cast (vfn_base, *value_p); - /* Now value is an object of the appropriate base type. Fetch its - virtual table. */ - /* It might be possible to do this cast at the same time as the above. - Does multiple inheritance affect this? - Can this even trigger, or is TYPE_VPTR_BASETYPE idempotent? - */ - if (TYPE_VPTR_BASETYPE (vfn_base) != vfn_base) - value = value_cast (TYPE_VPTR_BASETYPE (vfn_base), value); - vtable_address - = value_as_address (value_field (value, TYPE_VPTR_FIELDNO (vfn_base))); - - vtable = value_at_lazy (vtable_type, - vtable_address - vtable_address_point_offset ()); - - /* Fetch the appropriate function pointer from the vtable. */ - vfn = value_subscript (value_field (vtable, vtable_field_virtual_functions), - value_from_longest (builtin_type_int, - TYPE_FN_FIELD_VOFFSET (f, j))); - - /* Cast the function pointer to the appropriate type. */ - vfn = value_cast (lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j)), - vfn); - - /* Is (type)value always numerically the same as (vfn_base)value? - If so we can spare this cast and use one of the ones above. */ - *value_p = value_addr (value_cast (type, *value_p)); - - return vfn; + return gnuv3_get_virtual_fn (*value_p, TYPE_FN_FIELD_TYPE (f, j), + TYPE_FN_FIELD_VOFFSET (f, j)); } /* Compute the offset of the baseclass which is @@ -416,6 +434,245 @@ gnuv3_baseclass_offset (struct type *type, int index, const bfd_byte *valaddr, return base_offset; } +/* Locate a virtual method in DOMAIN or its non-virtual base classes + which has virtual table index VOFFSET. The method has an associated + "this" adjustment of ADJUSTMENT bytes. */ + +const char * +gnuv3_find_method_in (struct type *domain, CORE_ADDR voffset, + LONGEST adjustment) +{ + int i; + const char *physname; + + /* Search this class first. */ + physname = NULL; + if (adjustment == 0) + { + int len; + + len = TYPE_NFN_FIELDS (domain); + for (i = 0; i < len; i++) + { + int len2, j; + struct fn_field *f; + + f = TYPE_FN_FIELDLIST1 (domain, i); + len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i); + + check_stub_method_group (domain, i); + for (j = 0; j < len2; j++) + if (TYPE_FN_FIELD_VOFFSET (f, j) == voffset) + return TYPE_FN_FIELD_PHYSNAME (f, j); + } + } + + /* Next search non-virtual bases. If it's in a virtual base, + we're out of luck. */ + for (i = 0; i < TYPE_N_BASECLASSES (domain); i++) + { + int pos; + struct type *basetype; + + if (BASETYPE_VIA_VIRTUAL (domain, i)) + continue; + + pos = TYPE_BASECLASS_BITPOS (domain, i) / 8; + basetype = TYPE_FIELD_TYPE (domain, i); + /* Recurse with a modified adjustment. We don't need to adjust + voffset. */ + if (adjustment >= pos && adjustment < pos + TYPE_LENGTH (basetype)) + return gnuv3_find_method_in (basetype, voffset, adjustment - pos); + } + + return NULL; +} + +/* GNU v3 implementation of cplus_print_method_ptr. */ + +static void +gnuv3_print_method_ptr (const gdb_byte *contents, + struct type *type, + struct ui_file *stream) +{ + CORE_ADDR ptr_value; + LONGEST adjustment; + struct type *domain; + int vbit; + + domain = TYPE_DOMAIN_TYPE (type); + + /* Extract the pointer to member. */ + ptr_value = extract_typed_address (contents, builtin_type_void_func_ptr); + contents += TYPE_LENGTH (builtin_type_void_func_ptr); + adjustment = extract_signed_integer (contents, + TYPE_LENGTH (builtin_type_long)); + + if (!gdbarch_vbit_in_delta (current_gdbarch)) + { + vbit = ptr_value & 1; + ptr_value = ptr_value ^ vbit; + } + else + { + vbit = adjustment & 1; + adjustment = adjustment >> 1; + } + + /* Check for NULL. */ + if (ptr_value == 0 && vbit == 0) + { + fprintf_filtered (stream, "NULL"); + return; + } + + /* Search for a virtual method. */ + if (vbit) + { + CORE_ADDR voffset; + const char *physname; + + /* It's a virtual table offset, maybe in this class. Search + for a field with the correct vtable offset. First convert it + to an index, as used in TYPE_FN_FIELD_VOFFSET. */ + voffset = ptr_value / TYPE_LENGTH (builtin_type_long); + + physname = gnuv3_find_method_in (domain, voffset, adjustment); + + /* If we found a method, print that. We don't bother to disambiguate + possible paths to the method based on the adjustment. */ + if (physname) + { + char *demangled_name = cplus_demangle (physname, + DMGL_ANSI | DMGL_PARAMS); + if (demangled_name != NULL) + { + fprintf_filtered (stream, "&virtual "); + fputs_filtered (demangled_name, stream); + xfree (demangled_name); + return; + } + } + } + + /* We didn't find it; print the raw data. */ + if (vbit) + { + fprintf_filtered (stream, "&virtual table offset "); + print_longest (stream, 'd', 1, ptr_value); + } + else + print_address_demangle (ptr_value, stream, demangle); + + if (adjustment) + { + fprintf_filtered (stream, ", this adjustment "); + print_longest (stream, 'd', 1, adjustment); + } +} + +/* GNU v3 implementation of cplus_method_ptr_size. */ + +static int +gnuv3_method_ptr_size (void) +{ + return 2 * TYPE_LENGTH (builtin_type_void_data_ptr); +} + +/* GNU v3 implementation of cplus_make_method_ptr. */ + +static void +gnuv3_make_method_ptr (gdb_byte *contents, CORE_ADDR value, int is_virtual) +{ + int size = TYPE_LENGTH (builtin_type_void_data_ptr); + + /* FIXME drow/2006-12-24: The adjustment of "this" is currently + always zero, since the method pointer is of the correct type. + But if the method pointer came from a base class, this is + incorrect - it should be the offset to the base. The best + fix might be to create the pointer to member pointing at the + base class and cast it to the derived class, but that requires + support for adjusting pointers to members when casting them - + not currently supported by GDB. */ + + if (!gdbarch_vbit_in_delta (current_gdbarch)) + { + store_unsigned_integer (contents, size, value | is_virtual); + store_unsigned_integer (contents + size, size, 0); + } + else + { + store_unsigned_integer (contents, size, value); + store_unsigned_integer (contents + size, size, is_virtual); + } +} + +/* GNU v3 implementation of cplus_method_ptr_to_value. */ + +static struct value * +gnuv3_method_ptr_to_value (struct value **this_p, struct value *method_ptr) +{ + const gdb_byte *contents = value_contents (method_ptr); + CORE_ADDR ptr_value; + struct type *final_type, *method_type; + LONGEST adjustment; + struct value *adjval; + int vbit; + + final_type = TYPE_DOMAIN_TYPE (check_typedef (value_type (method_ptr))); + final_type = lookup_pointer_type (final_type); + + method_type = TYPE_TARGET_TYPE (check_typedef (value_type (method_ptr))); + + ptr_value = extract_typed_address (contents, builtin_type_void_func_ptr); + contents += TYPE_LENGTH (builtin_type_void_func_ptr); + adjustment = extract_signed_integer (contents, + TYPE_LENGTH (builtin_type_long)); + + if (!gdbarch_vbit_in_delta (current_gdbarch)) + { + vbit = ptr_value & 1; + ptr_value = ptr_value ^ vbit; + } + else + { + vbit = adjustment & 1; + adjustment = adjustment >> 1; + } + + /* First convert THIS to match the containing type of the pointer to + member. This cast may adjust the value of THIS. */ + *this_p = value_cast (final_type, *this_p); + + /* Then apply whatever adjustment is necessary. This creates a somewhat + strange pointer: it claims to have type FINAL_TYPE, but in fact it + might not be a valid FINAL_TYPE. For instance, it might be a + base class of FINAL_TYPE. And if it's not the primary base class, + then printing it out as a FINAL_TYPE object would produce some pretty + garbage. + + But we don't really know the type of the first argument in + METHOD_TYPE either, which is why this happens. We can't + dereference this later as a FINAL_TYPE, but once we arrive in the + called method we'll have debugging information for the type of + "this" - and that'll match the value we produce here. + + You can provoke this case by casting a Base::* to a Derived::*, for + instance. */ + *this_p = value_cast (builtin_type_void_data_ptr, *this_p); + adjval = value_from_longest (builtin_type_long, adjustment); + *this_p = value_add (*this_p, adjval); + *this_p = value_cast (final_type, *this_p); + + if (vbit) + { + LONGEST voffset = ptr_value / TYPE_LENGTH (builtin_type_long); + return gnuv3_get_virtual_fn (value_ind (*this_p), method_type, voffset); + } + else + return value_from_pointer (lookup_pointer_type (method_type), ptr_value); +} + static void init_gnuv3_ops (void) { @@ -433,6 +690,10 @@ init_gnuv3_ops (void) gnu_v3_abi_ops.rtti_type = gnuv3_rtti_type; gnu_v3_abi_ops.virtual_fn_field = gnuv3_virtual_fn_field; gnu_v3_abi_ops.baseclass_offset = gnuv3_baseclass_offset; + gnu_v3_abi_ops.print_method_ptr = gnuv3_print_method_ptr; + gnu_v3_abi_ops.method_ptr_size = gnuv3_method_ptr_size; + gnu_v3_abi_ops.make_method_ptr = gnuv3_make_method_ptr; + gnu_v3_abi_ops.method_ptr_to_value = gnuv3_method_ptr_to_value; } extern initialize_file_ftype _initialize_gnu_v3_abi; /* -Wmissing-prototypes */ diff --git a/gdb/hpread.c b/gdb/hpread.c index cb617783ce3..16a445bfead 100644 --- a/gdb/hpread.c +++ b/gdb/hpread.c @@ -1,6 +1,6 @@ /* 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. @@ -4875,9 +4875,7 @@ hpread_type_lookup (dnttpointer hp_type, struct objfile *objfile) 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; @@ -4905,7 +4903,7 @@ hpread_type_lookup (dnttpointer hp_type, struct objfile *objfile) TYPE_FIELDS (functype), TYPE_NFIELDS (functype), 0); - return make_pointer_type (ptrmemtype, NULL); + return lookup_methodptr_type (ptrmemtype); } break; diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c index f815f6c92a4..00faa3b106b 100644 --- a/gdb/ia64-tdep.c +++ b/gdb/ia64-tdep.c @@ -40,6 +40,7 @@ #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 */ @@ -3306,6 +3307,17 @@ ia64_convert_from_func_ptr_addr (struct gdbarch *gdbarch, CORE_ADDR addr, 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; } @@ -3640,6 +3652,10 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) 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); diff --git a/gdb/infcall.c b/gdb/infcall.c index 9f12896102c..64772d7590f 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -1,7 +1,7 @@ /* 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. @@ -169,7 +169,8 @@ value_arg_coerce (struct value *arg, struct type *param_type, 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: diff --git a/gdb/m2-typeprint.c b/gdb/m2-typeprint.c index e057b65ce3c..cda9189e023 100644 --- a/gdb/m2-typeprint.c +++ b/gdb/m2-typeprint.c @@ -112,10 +112,6 @@ m2_print_type (struct type *type, char *varstring, struct ui_file *stream, 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; diff --git a/gdb/m2-valprint.c b/gdb/m2-valprint.c index 579ea8b8054..7ce653338a7 100644 --- a/gdb/m2-valprint.c +++ b/gdb/m2-valprint.c @@ -327,10 +327,6 @@ m2_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, } 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) diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 8b3ddb8870a..228422f624b 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -5231,6 +5231,9 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) 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. */ diff --git a/gdb/p-lang.h b/gdb/p-lang.h index 507ff200428..380d8acf997 100644 --- a/gdb/p-lang.h +++ b/gdb/p-lang.h @@ -1,6 +1,6 @@ /* 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. @@ -67,12 +67,6 @@ extern int vtblprint; /* Controls printing of vtbl's */ 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, diff --git a/gdb/p-typeprint.c b/gdb/p-typeprint.c index 697a2b9ec4e..d6f6b4ba13a 100644 --- a/gdb/p-typeprint.c +++ b/gdb/p-typeprint.c @@ -1,5 +1,5 @@ /* 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. @@ -208,19 +208,6 @@ pascal_type_print_varspec_prefix (struct type *type, struct ui_file *stream, 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, "("); @@ -353,12 +340,6 @@ pascal_type_print_varspec_suffix (struct type *type, struct ui_file *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, ")"); @@ -481,7 +462,6 @@ pascal_type_print_base (struct type *type, struct ui_file *stream, int show, { case TYPE_CODE_TYPEDEF: case TYPE_CODE_PTR: - case TYPE_CODE_MEMBER: case TYPE_CODE_REF: /* case TYPE_CODE_FUNC: case TYPE_CODE_METHOD: */ diff --git a/gdb/p-valprint.c b/gdb/p-valprint.c index 33b797451ec..8304196f1f6 100644 --- a/gdb/p-valprint.c +++ b/gdb/p-valprint.c @@ -151,17 +151,6 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, 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: @@ -259,19 +248,8 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, } 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, "@"); @@ -604,96 +582,6 @@ static void pascal_object_print_value (struct type *, const gdb_byte *, 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, ""); - 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, "", - 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}; @@ -1060,58 +948,6 @@ pascal_object_print_static_field (struct value *val, 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 diff --git a/gdb/stabsread.c b/gdb/stabsread.c index 428cbc2e8bf..a27ee536c95 100644 --- a/gdb/stabsread.c +++ b/gdb/stabsread.c @@ -1,7 +1,7 @@ /* 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. @@ -1731,7 +1731,7 @@ again: 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 */ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index dd8c387fe10..57f8aa6989c 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,21 @@ +2007-01-03 Daniel Jacobowitz + + * 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 * gdb.threads/tls.exp: Allow stops in sem_post. diff --git a/gdb/testsuite/gdb.cp/classes.exp b/gdb/testsuite/gdb.cp/classes.exp index e072667c03a..0f8592d5a6d 100644 --- a/gdb/testsuite/gdb.cp/classes.exp +++ b/gdb/testsuite/gdb.cp/classes.exp @@ -1,5 +1,5 @@ # 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 @@ -498,11 +498,14 @@ proc test_enums {} { # 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 diff --git a/gdb/testsuite/gdb.cp/inherit.exp b/gdb/testsuite/gdb.cp/inherit.exp index 47a08ae3c2b..40433deedc6 100644 --- a/gdb/testsuite/gdb.cp/inherit.exp +++ b/gdb/testsuite/gdb.cp/inherit.exp @@ -389,29 +389,19 @@ proc test_print_mi_member_types {} { # 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. @@ -423,9 +413,6 @@ proc test_print_mi_member_types {} { 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" } @@ -433,25 +420,16 @@ proc test_print_mi_member_types {} { 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. @@ -459,9 +437,6 @@ proc test_print_mi_member_types {} { 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" } @@ -469,29 +444,18 @@ proc test_print_mi_member_types {} { 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" } diff --git a/gdb/testsuite/gdb.cp/member-ptr.cc b/gdb/testsuite/gdb.cp/member-ptr.cc index e668c4623c1..d93875bd87d 100644 --- a/gdb/testsuite/gdb.cp/member-ptr.cc +++ b/gdb/testsuite/gdb.cp/member-ptr.cc @@ -1,6 +1,6 @@ /* 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 @@ -81,6 +81,69 @@ typedef int (A::*PMF)(int); 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; @@ -90,6 +153,18 @@ int main () 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; @@ -101,8 +176,27 @@ int main () 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; diff --git a/gdb/testsuite/gdb.cp/member-ptr.exp b/gdb/testsuite/gdb.cp/member-ptr.exp index ee1d1abe27d..07a9767c59d 100644 --- a/gdb/testsuite/gdb.cp/member-ptr.exp +++ b/gdb/testsuite/gdb.cp/member-ptr.exp @@ -1,4 +1,4 @@ -# 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 @@ -20,8 +20,6 @@ # Written by Satish Pai 1997-08-19 # Rewritten by Michael Chastain 2004-01-11 -# TODO: copyright notice for member-ptr.cc - set vhn "\\$\[0-9\]+" if $tracelevel then { @@ -56,16 +54,9 @@ if ![runto_main] 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 # ====================== @@ -74,14 +65,9 @@ if { [test_compiler_info "gcc-*"] } { 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 @@ -390,7 +376,7 @@ gdb_test_multiple "ptype *pmi" $name { 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 } } @@ -412,7 +398,7 @@ gdb_test_multiple "print ((int) pmi) == ((char *) &a.j - (char *) & a)" $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 $" { @@ -434,7 +420,7 @@ gdb_test_multiple "ptype pmf" $name { set name "print pmf" gdb_test_multiple "print pmf" $name { - -re "$vhn = &A::bar\r\n$gdb_prompt $" { + -re "$vhn = $hex \r\n$gdb_prompt $" { pass $name } -re "$vhn = .*not supported with HP aCC.*\r\n$gdb_prompt $" { @@ -456,7 +442,7 @@ gdb_test_multiple "print pmf" $name { 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 $" { @@ -498,7 +484,7 @@ gdb_test_multiple "print pmf_p" $name { set name "print a.*pmf" gdb_test_multiple "print a.*pmf" $name { - -re "$vhn = \\(int \\(\\*\\)\\(int\\)\\) $hex \r\n$gdb_prompt$ " { + -re "$vhn = {int \\(A \\*, int\\)} $hex \r\n$gdb_prompt $" { pass $name } -re "Pointers to methods not supported with HP aCC\r\n$gdb_prompt $" { @@ -520,7 +506,7 @@ gdb_test_multiple "print a.*pmf" $name { set name "print a_p->*pmf" gdb_test_multiple "print a_p->*pmf" $name { - -re "$vhn = \\(int \\(\\*\\)\\(int\\)\\) $hex \r\n$gdb_prompt$ " { + -re "$vhn = {int \\(A \\*, int\\)} $hex \r\n$gdb_prompt $" { pass $name } -re "Pointers to methods not supported with HP aCC\r\n$gdb_prompt $" { @@ -621,3 +607,56 @@ gdb_test_multiple "print (a.*pmf)(3)" $name { 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 " +gdb_test "print diamond.*right_pmf" \ + "$vhn = {int \\(Diamond \\*\\)} $hex " + +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 " +gdb_test "print diamond.*right_vpmf" \ + "$vhn = {int \\(Diamond \\*\\)} $hex " + +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 " +gdb_test "print null_pmf = 0" "$vhn = NULL" diff --git a/gdb/testsuite/gdb.cp/printmethod.exp b/gdb/testsuite/gdb.cp/printmethod.exp index 8c7a9c0e8e3..072695611cd 100644 --- a/gdb/testsuite/gdb.cp/printmethod.exp +++ b/gdb/testsuite/gdb.cp/printmethod.exp @@ -1,4 +1,4 @@ -# 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 @@ -63,8 +63,12 @@ gdb_continue_to_breakpoint "end of constructors" # 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 " \ + "print virtual method." +gdb_test "print theA->nonvirt" \ + "\\$\[0-9\]* = {void \\(A \\*\\)} $hex " \ + "print nonvirtual method." gdb_exit return 0 diff --git a/gdb/testsuite/gdb.cp/virtfunc.exp b/gdb/testsuite/gdb.cp/virtfunc.exp index 2da07638125..a9c9c7bf08e 100644 --- a/gdb/testsuite/gdb.cp/virtfunc.exp +++ b/gdb/testsuite/gdb.cp/virtfunc.exp @@ -1,4 +1,5 @@ -# 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 @@ -217,6 +218,14 @@ proc test_virtual_calls {} { -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()" } diff --git a/gdb/typeprint.c b/gdb/typeprint.c index d31d521bf8f..fb828081478 100644 --- a/gdb/typeprint.c +++ b/gdb/typeprint.c @@ -1,7 +1,7 @@ /* 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. @@ -257,7 +257,8 @@ print_type_scalar (struct type *type, LONGEST val, struct ui_file *stream) 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: diff --git a/gdb/valops.c b/gdb/valops.c index 15c407c0af2..b6a0ad76f91 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -1,7 +1,8 @@ /* 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. @@ -97,14 +98,15 @@ static struct value *value_struct_elt_for_reference (struct type *domain, 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); @@ -259,6 +261,7 @@ value_cast_pointers (struct type *type, struct value *arg2) } /* 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 */ @@ -366,33 +369,24 @@ value_cast (struct type *type, struct value *arg2) 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 @@ -434,11 +428,26 @@ value_cast (struct type *type, struct value *arg2) } 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 */ @@ -940,9 +949,6 @@ value_ind (struct value *arg1) 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 @@ -957,9 +963,17 @@ value_ind (struct value *arg1) /* 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 */ @@ -1599,9 +1613,6 @@ value_struct_elt (struct value **argp, struct value **args, 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); @@ -1798,9 +1809,6 @@ value_find_oload_method_list (struct value **argp, char *method, int offset, 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")); @@ -2334,9 +2342,6 @@ check_field (struct value *arg1, const char *name) 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")); @@ -2345,14 +2350,14 @@ check_field (struct value *arg1, const char *name) } /* 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)) @@ -2360,9 +2365,9 @@ value_aggregate_elt (struct type *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")); @@ -2379,12 +2384,12 @@ value_aggregate_elt (struct type *curtype, 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) @@ -2402,15 +2407,21 @@ value_struct_elt_for_reference (struct type *domain, int offset, 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); } } @@ -2461,33 +2472,52 @@ value_struct_elt_for_reference (struct type *domain, int offset, 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--) @@ -2503,7 +2533,7 @@ value_struct_elt_for_reference (struct type *domain, int offset, offset + base_offset, TYPE_BASECLASS (t, i), name, - intype, + intype, want_address, noside); if (v) return v; @@ -2513,7 +2543,7 @@ value_struct_elt_for_reference (struct type *domain, int offset, 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 @@ -2521,11 +2551,11 @@ value_struct_elt_for_reference (struct type *domain, int offset, 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, @@ -2542,11 +2572,12 @@ value_namespace_elt (const struct type *curtype, 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, @@ -2556,9 +2587,14 @@ value_maybe_namespace_elt (const struct type *curtype, 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 diff --git a/gdb/value.c b/gdb/value.c index c01444a4e9f..e1869acd57c 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -1090,6 +1090,7 @@ unpack_long (struct type *type, const gdb_byte *valaddr) 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 @@ -1104,9 +1105,6 @@ unpack_long (struct type *type, const gdb_byte *valaddr) 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.")); } @@ -1537,6 +1535,7 @@ retry: 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; diff --git a/gdb/value.h b/gdb/value.h index 001761a83c6..4c7990035ed 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -1,7 +1,8 @@ /* 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. @@ -345,7 +346,9 @@ extern struct value *value_struct_elt (struct value **argp, 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); diff --git a/gdb/varobj.c b/gdb/varobj.c index 92d43cba94a..25860cbd502 100644 --- a/gdb/varobj.c +++ b/gdb/varobj.c @@ -2106,7 +2106,6 @@ c_variable_editable (struct varobj *var) case TYPE_CODE_UNION: case TYPE_CODE_ARRAY: case TYPE_CODE_FUNC: - case TYPE_CODE_MEMBER: case TYPE_CODE_METHOD: return 0; break;