mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 10:03:47 +08:00
* NEWS: Mention pointer to member improvements.
* Makefile.in (gnu-v3-abi.o): Delete special rule. (eval.o, gnu-v3-abi.o, ia64-tdep.o): Update. * ada-valprint.c (ada_print_scalar): Update for new type codes. * c-typeprint.c (c_print_type): Update for new type codes. (c_type_print_varspec_prefix, c_type_print_varspec_suffix) (c_type_print_base): Likewise. (c_type_print_args): Rewrite. * c-valprint.c (c_val_print): Update for new type codes. Remove support for references to members. Treat methods like functions. * cp-abi.c (cplus_print_method_ptr, cplus_method_ptr_size) (cplus_make_method_ptr, cplus_method_ptr_to_value): New. * cp-abi.h (cplus_print_method_ptr, cplus_method_ptr_size) (cplus_make_method_ptr, cplus_method_ptr_to_value): New prototypes. (struct cp_abi_ops): Add corresponding members. * cp-valprint.c (cp_print_class_method): Delete. (cp_find_class_member): New function. (cp_print_class_member): Use it. Simplify support for bogus member pointers. * dwarf2read.c (quirk_gcc_member_function_pointer): Use lookup_methodptr_type. (read_tag_ptr_to_member_type): Likewise, and lookup_memberptr_type. * eval.c (evaluate_subexp_standard): Implement EVAL_SKIP for OP_SCOPE. Update call to value_aggregate_elt. Rewrite member pointer support. (evaluate_subexp_for_address): Handle OP_SCOPE explicitly. Handle references returned by user defined operators. * f-typeprint.c (f_print_type, f_type_print_varspec_prefix) (f_type_print_varspec_suffix): Remove support for member pointers. * gdbtypes.c (lookup_memberptr_type): Renamed from lookup_member_type and adjusted. (smash_to_memberptr_type): Likewise, from smash_to_member_type. (lookup_methodptr_type): New. (rank_one_type): Adjust for TYPE_CODE_MEMBERPTR. (recursive_dump_type): Update for new types. * gdbtypes.h (enum type_code): Replace TYPE_CODE_MEMBER with TYPE_CODE_MEMBERPTR and TYPE_CODE_METHODPTR. (lookup_memberptr_type, lookup_methodptr_type) (smash_to_memberptr_type): New prototypes. (smash_to_method_type): Formatting fix. (lookup_member_type, smash_to_member_type): Delete prototypes. * gnu-v3-abi.c (gnuv3_get_vtable, gnuv3_get_virtual_fn): New. Do not rely on debug information for the vptr or the method's enclosing type. Handle function descriptors for IA64. (gnuv3_virtual_fn_field): Rewrite using the new functions. (gnuv3_find_method_in, gnuv3_print_method_ptr) (gnuv3_method_ptr_size, gnuv3_make_method_ptr) (gnuv3_method_ptr_to_value): New. (init_gnuv3_ops): Set new members of gnu_v3_abi_ops. * hpread.c (hpread_type_lookup): Update for new types. * infcall.c (value_arg_coerce): Likewise. * m2-typeprint.c (m2_print_type): Remove explicit support for member pointers. * m2-valprint.c (m2_val_print): Likewise. * p-typeprint.c (pascal_type_print_varspec_prefix) (pascal_type_print_varspec_suffix, pascal_type_print_base): Likewise. * p-valprint.c (pascal_val_print): Likewise. (pascal_object_print_class_method, pascal_object_print_class_member): Delete. * p-lang.h (pascal_object_print_class_method) (pascal_object_print_class_member): Delete prototypes. * stabsread.c (read_type): Update for new types. * typeprint.c (print_type_scalar): Likewise. * valops.c (value_struct_elt_for_reference, value_namespace_elt) (value_maybe_namespace_elt, value_aggregate_elt): Add want_address argument. Construct a pointer to member if the address of a function or data member is requested. (value_cast_pointers): Don't modify the input value. (value_cast): Adjust pointer to member handling for new types. Allow null pointer to member constants. Don't modify the input value. (value_ind): Remove pointer to member check. Handle function descriptors for function pointers. (value_struct_elt, value_find_oload_method_list, check_field): Remove pointer to member checks. * value.c (unpack_long): Allow pointers to data members. (value_from_longest): Allow member pointers. * value.h (value_aggregate_elt): Add want_address. * varobj.c (c_variable_editable): Remove check for members. * gdbarch.sh: Add vtable_function_descriptors and vbit_in_delta. * ia64-tdep.c (ia64_convert_from_func_ptr_addr): Handle descriptors in virtual tables. (ia64_gdbarch_init): Call set_gdbarch_vtable_function_descriptors. * c-lang.h (cp_print_class_method): Delete prototype. * arm-tdep.c (arm_gdbarch_init): Call set_gdbarch_vbit_in_delta. * mips-tdep.c (mips_gdbarch_init): Likewise. * gdbarch.c, gdbarch.h: Regenerated. * gdb.cp/classes.exp (test_pointers_to_class_members): Update expected output. Test the types of members and member pointers. * gdb.cp/inherit.exp (test_print_mi_member_types): Remove KFAILs for gdb/2092. * gdb.cp/member-ptr.exp: Search for a comment instead of a statement. Enable for GCC. Update expected output for some tests and add new tests. Remove obsolete GCC KFAILs. Allow GCC's class layout. * gdb.cp/member-ptr.cc (Padding, Padding::vspacer, Base, Base::get_x) (Base::vget_base, Left, Left::vget, Right, Right::vget, Diamond) (Diamond::vget_base): New. (main): Add new tests. * gdb.cp/printmethod.exp: Update expected output for member functions. * gdb.cp/virtfunc.exp (test_virtual_calls): Add a KFAIL for print pEe->D::vg().
This commit is contained in:
parent
9d6063994f
commit
0d5de0100f
@ -1,3 +1,93 @@
|
||||
2007-01-03 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* NEWS: Mention pointer to member improvements.
|
||||
* Makefile.in (gnu-v3-abi.o): Delete special rule.
|
||||
(eval.o, gnu-v3-abi.o, ia64-tdep.o): Update.
|
||||
* ada-valprint.c (ada_print_scalar): Update for new type codes.
|
||||
* c-typeprint.c (c_print_type): Update for new type codes.
|
||||
(c_type_print_varspec_prefix, c_type_print_varspec_suffix)
|
||||
(c_type_print_base): Likewise.
|
||||
(c_type_print_args): Rewrite.
|
||||
* c-valprint.c (c_val_print): Update for new type codes. Remove
|
||||
support for references to members. Treat methods like functions.
|
||||
* cp-abi.c (cplus_print_method_ptr, cplus_method_ptr_size)
|
||||
(cplus_make_method_ptr, cplus_method_ptr_to_value): New.
|
||||
* cp-abi.h (cplus_print_method_ptr, cplus_method_ptr_size)
|
||||
(cplus_make_method_ptr, cplus_method_ptr_to_value): New prototypes.
|
||||
(struct cp_abi_ops): Add corresponding members.
|
||||
* cp-valprint.c (cp_print_class_method): Delete.
|
||||
(cp_find_class_member): New function.
|
||||
(cp_print_class_member): Use it. Simplify support for bogus
|
||||
member pointers.
|
||||
* dwarf2read.c (quirk_gcc_member_function_pointer): Use
|
||||
lookup_methodptr_type.
|
||||
(read_tag_ptr_to_member_type): Likewise, and lookup_memberptr_type.
|
||||
* eval.c (evaluate_subexp_standard): Implement EVAL_SKIP for
|
||||
OP_SCOPE. Update call to value_aggregate_elt. Rewrite member
|
||||
pointer support.
|
||||
(evaluate_subexp_for_address): Handle OP_SCOPE explicitly. Handle
|
||||
references returned by user defined operators.
|
||||
* f-typeprint.c (f_print_type, f_type_print_varspec_prefix)
|
||||
(f_type_print_varspec_suffix): Remove support for member pointers.
|
||||
* gdbtypes.c (lookup_memberptr_type): Renamed from lookup_member_type
|
||||
and adjusted.
|
||||
(smash_to_memberptr_type): Likewise, from smash_to_member_type.
|
||||
(lookup_methodptr_type): New.
|
||||
(rank_one_type): Adjust for TYPE_CODE_MEMBERPTR.
|
||||
(recursive_dump_type): Update for new types.
|
||||
* gdbtypes.h (enum type_code): Replace TYPE_CODE_MEMBER with
|
||||
TYPE_CODE_MEMBERPTR and TYPE_CODE_METHODPTR.
|
||||
(lookup_memberptr_type, lookup_methodptr_type)
|
||||
(smash_to_memberptr_type): New prototypes.
|
||||
(smash_to_method_type): Formatting fix.
|
||||
(lookup_member_type, smash_to_member_type): Delete prototypes.
|
||||
* gnu-v3-abi.c (gnuv3_get_vtable, gnuv3_get_virtual_fn): New.
|
||||
Do not rely on debug information for the vptr or the method's
|
||||
enclosing type. Handle function descriptors for IA64.
|
||||
(gnuv3_virtual_fn_field): Rewrite using the new functions.
|
||||
(gnuv3_find_method_in, gnuv3_print_method_ptr)
|
||||
(gnuv3_method_ptr_size, gnuv3_make_method_ptr)
|
||||
(gnuv3_method_ptr_to_value): New.
|
||||
(init_gnuv3_ops): Set new members of gnu_v3_abi_ops.
|
||||
* hpread.c (hpread_type_lookup): Update for new types.
|
||||
* infcall.c (value_arg_coerce): Likewise.
|
||||
* m2-typeprint.c (m2_print_type): Remove explicit support
|
||||
for member pointers.
|
||||
* m2-valprint.c (m2_val_print): Likewise.
|
||||
* p-typeprint.c (pascal_type_print_varspec_prefix)
|
||||
(pascal_type_print_varspec_suffix, pascal_type_print_base): Likewise.
|
||||
* p-valprint.c (pascal_val_print): Likewise.
|
||||
(pascal_object_print_class_method, pascal_object_print_class_member):
|
||||
Delete.
|
||||
* p-lang.h (pascal_object_print_class_method)
|
||||
(pascal_object_print_class_member): Delete prototypes.
|
||||
* stabsread.c (read_type): Update for new types.
|
||||
* typeprint.c (print_type_scalar): Likewise.
|
||||
* valops.c (value_struct_elt_for_reference, value_namespace_elt)
|
||||
(value_maybe_namespace_elt, value_aggregate_elt): Add want_address
|
||||
argument. Construct a pointer to member if the address of a
|
||||
function or data member is requested.
|
||||
(value_cast_pointers): Don't modify the input value.
|
||||
(value_cast): Adjust pointer to member handling for new types.
|
||||
Allow null pointer to member constants. Don't modify the input
|
||||
value.
|
||||
(value_ind): Remove pointer to member check. Handle function
|
||||
descriptors for function pointers.
|
||||
(value_struct_elt, value_find_oload_method_list, check_field):
|
||||
Remove pointer to member checks.
|
||||
* value.c (unpack_long): Allow pointers to data members.
|
||||
(value_from_longest): Allow member pointers.
|
||||
* value.h (value_aggregate_elt): Add want_address.
|
||||
* varobj.c (c_variable_editable): Remove check for members.
|
||||
* gdbarch.sh: Add vtable_function_descriptors and vbit_in_delta.
|
||||
* ia64-tdep.c (ia64_convert_from_func_ptr_addr): Handle descriptors
|
||||
in virtual tables.
|
||||
(ia64_gdbarch_init): Call set_gdbarch_vtable_function_descriptors.
|
||||
* c-lang.h (cp_print_class_method): Delete prototype.
|
||||
* arm-tdep.c (arm_gdbarch_init): Call set_gdbarch_vbit_in_delta.
|
||||
* mips-tdep.c (mips_gdbarch_init): Likewise.
|
||||
* gdbarch.c, gdbarch.h: Regenerated.
|
||||
|
||||
2007-01-01 Mark Kettenis <kettenis@gnu.org>
|
||||
|
||||
* rs6000-tdep.c (rs6000_use_struct_convention)
|
||||
|
@ -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) \
|
||||
|
2
gdb/NEWS
2
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
|
||||
|
@ -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"));
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
35
gdb/cp-abi.c
35
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
|
||||
|
30
gdb/cp-abi.h
30
gdb/cp-abi.h
@ -3,7 +3,7 @@
|
||||
|
||||
Contributed by Daniel Berlin <dberlin@redhat.com>
|
||||
|
||||
Copyright (C) 2001, 2005 Free Software Foundation, Inc.
|
||||
Copyright (C) 2001, 2005, 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
@ -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 *);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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, "<unknown>");
|
||||
return;
|
||||
}
|
||||
addr = unpack_pointer (type, valaddr);
|
||||
if (METHOD_PTR_IS_VIRTUAL (addr))
|
||||
{
|
||||
offset = METHOD_PTR_TO_VOFFSET (addr);
|
||||
len = TYPE_NFN_FIELDS (domain);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
f = TYPE_FN_FIELDLIST1 (domain, i);
|
||||
len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
|
||||
|
||||
check_stub_method_group (domain, i);
|
||||
for (j = 0; j < len2; j++)
|
||||
{
|
||||
if (TYPE_FN_FIELD_VOFFSET (f, j) == offset)
|
||||
{
|
||||
kind = "virtual ";
|
||||
goto common;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sym = find_pc_function (addr);
|
||||
if (sym == 0)
|
||||
{
|
||||
/* 1997-08-01 Currently unsupported with HP aCC */
|
||||
if (deprecated_hp_som_som_object_present)
|
||||
{
|
||||
fputs_filtered ("?? <not supported with HP aCC>", stream);
|
||||
return;
|
||||
}
|
||||
error (_("invalid pointer to member function"));
|
||||
}
|
||||
len = TYPE_NFN_FIELDS (domain);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
f = TYPE_FN_FIELDLIST1 (domain, i);
|
||||
len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
|
||||
|
||||
check_stub_method_group (domain, i);
|
||||
for (j = 0; j < len2; j++)
|
||||
{
|
||||
if (strcmp (DEPRECATED_SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j))
|
||||
== 0)
|
||||
goto common;
|
||||
}
|
||||
}
|
||||
}
|
||||
common:
|
||||
if (i < len)
|
||||
{
|
||||
char *demangled_name;
|
||||
|
||||
fprintf_filtered (stream, "&");
|
||||
fputs_filtered (kind, stream);
|
||||
demangled_name = cplus_demangle (TYPE_FN_FIELD_PHYSNAME (f, j),
|
||||
DMGL_ANSI | DMGL_PARAMS);
|
||||
if (demangled_name == NULL)
|
||||
fprintf_filtered (stream, "<badly mangled name %s>",
|
||||
TYPE_FN_FIELD_PHYSNAME (f, j));
|
||||
else
|
||||
{
|
||||
fputs_filtered (demangled_name, stream);
|
||||
xfree (demangled_name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf_filtered (stream, "(");
|
||||
type_print (type, "", stream, -1);
|
||||
fprintf_filtered (stream, ") %d", (int) addr >> 3);
|
||||
}
|
||||
}
|
||||
|
||||
/* GCC versions after 2.4.5 use this. */
|
||||
const char vtbl_ptr_name[] = "__vtbl_ptr_type";
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
198
gdb/eval.c
198
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"));
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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)");
|
||||
|
@ -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 *);
|
||||
|
||||
|
381
gdb/gnu-v3-abi.c
381
gdb/gnu-v3-abi.c
@ -1,7 +1,8 @@
|
||||
/* Abstraction of GNU v3 abi.
|
||||
Contributed by Jim Blandy <jimb@redhat.com>
|
||||
|
||||
Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
|
||||
Copyright (C) 2001, 2002, 2003, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
@ -25,6 +26,8 @@
|
||||
#include "cp-abi.h"
|
||||
#include "cp-support.h"
|
||||
#include "demangle.h"
|
||||
#include "valprint.h"
|
||||
|
||||
#include "gdb_assert.h"
|
||||
#include "gdb_string.h"
|
||||
|
||||
@ -274,77 +277,92 @@ gnuv3_rtti_type (struct value *value,
|
||||
return run_time_type;
|
||||
}
|
||||
|
||||
/* Find the vtable for CONTAINER and return a value of the correct
|
||||
vtable type for this architecture. */
|
||||
|
||||
static struct value *
|
||||
gnuv3_get_vtable (struct value *container)
|
||||
{
|
||||
struct type *vtable_type = gdbarch_data (current_gdbarch,
|
||||
vtable_type_gdbarch_data);
|
||||
struct type *vtable_pointer_type;
|
||||
struct value *vtable_pointer;
|
||||
CORE_ADDR vtable_pointer_address, vtable_address;
|
||||
|
||||
/* We do not consult the debug information to find the virtual table.
|
||||
The ABI specifies that it is always at offset zero in any class,
|
||||
and debug information may not represent it. We won't issue an
|
||||
error if there's a class with virtual functions but no virtual table
|
||||
pointer, but something's already gone seriously wrong if that
|
||||
happens.
|
||||
|
||||
We avoid using value_contents on principle, because the object might
|
||||
be large. */
|
||||
|
||||
/* Find the type "pointer to virtual table". */
|
||||
vtable_pointer_type = lookup_pointer_type (vtable_type);
|
||||
|
||||
/* Load it from the start of the class. */
|
||||
vtable_pointer_address = value_as_address (value_addr (container));
|
||||
vtable_pointer = value_at (vtable_pointer_type, vtable_pointer_address);
|
||||
vtable_address = value_as_address (vtable_pointer);
|
||||
|
||||
/* Correct it to point at the start of the virtual table, rather
|
||||
than the address point. */
|
||||
return value_at_lazy (vtable_type,
|
||||
vtable_address - vtable_address_point_offset ());
|
||||
}
|
||||
|
||||
/* Return a function pointer for CONTAINER's VTABLE_INDEX'th virtual
|
||||
function, of type FNTYPE. */
|
||||
|
||||
static struct value *
|
||||
gnuv3_get_virtual_fn (struct value *container, struct type *fntype,
|
||||
int vtable_index)
|
||||
{
|
||||
struct value *vtable = gnuv3_get_vtable (container);
|
||||
struct value *vfn;
|
||||
|
||||
/* Fetch the appropriate function pointer from the vtable. */
|
||||
vfn = value_subscript (value_field (vtable, vtable_field_virtual_functions),
|
||||
value_from_longest (builtin_type_int, vtable_index));
|
||||
|
||||
/* If this architecture uses function descriptors directly in the vtable,
|
||||
then the address of the vtable entry is actually a "function pointer"
|
||||
(i.e. points to the descriptor). We don't need to scale the index
|
||||
by the size of a function descriptor; GCC does that before outputing
|
||||
debug information. */
|
||||
if (gdbarch_vtable_function_descriptors (current_gdbarch))
|
||||
vfn = value_addr (vfn);
|
||||
|
||||
/* Cast the function pointer to the appropriate type. */
|
||||
vfn = value_cast (lookup_pointer_type (fntype), vfn);
|
||||
|
||||
return vfn;
|
||||
}
|
||||
|
||||
/* GNU v3 implementation of value_virtual_fn_field. See cp-abi.h
|
||||
for a description of the arguments. */
|
||||
|
||||
static struct value *
|
||||
gnuv3_virtual_fn_field (struct value **value_p,
|
||||
struct fn_field *f, int j,
|
||||
struct type *type, int offset)
|
||||
struct type *vfn_base, int offset)
|
||||
{
|
||||
struct type *vtable_type = gdbarch_data (current_gdbarch,
|
||||
vtable_type_gdbarch_data);
|
||||
struct value *value = *value_p;
|
||||
struct type *values_type = check_typedef (value_type (value));
|
||||
struct type *vfn_base;
|
||||
CORE_ADDR vtable_address;
|
||||
struct value *vtable;
|
||||
struct value *vfn;
|
||||
struct type *values_type = check_typedef (value_type (*value_p));
|
||||
|
||||
/* Some simple sanity checks. */
|
||||
if (TYPE_CODE (values_type) != TYPE_CODE_CLASS)
|
||||
error (_("Only classes can have virtual functions."));
|
||||
|
||||
/* Find the base class that defines this virtual function. */
|
||||
vfn_base = TYPE_FN_FIELD_FCONTEXT (f, j);
|
||||
if (! vfn_base)
|
||||
/* In programs compiled with G++ version 1, the debug info doesn't
|
||||
say which base class defined the virtual function. We'll guess
|
||||
it's the same base class that has our vtable; this is wrong for
|
||||
multiple inheritance, but it's better than nothing. */
|
||||
vfn_base = TYPE_VPTR_BASETYPE (type);
|
||||
|
||||
/* This type may have been defined before its virtual function table
|
||||
was. If so, fill in the virtual function table entry for the
|
||||
type now. */
|
||||
if (TYPE_VPTR_FIELDNO (vfn_base) < 0)
|
||||
fill_in_vptr_fieldno (vfn_base);
|
||||
if (TYPE_VPTR_FIELDNO (vfn_base) < 0)
|
||||
error (_("Could not find virtual table pointer for class \"%s\"."),
|
||||
TYPE_TAG_NAME (vfn_base) ? TYPE_TAG_NAME (vfn_base) : "<unknown>");
|
||||
|
||||
/* Now that we know which base class is defining our virtual
|
||||
function, cast our value to that baseclass. This takes care of
|
||||
any necessary `this' adjustments. */
|
||||
/* Cast our value to the base class which defines this virtual
|
||||
function. This takes care of any necessary `this'
|
||||
adjustments. */
|
||||
if (vfn_base != values_type)
|
||||
value = value_cast (vfn_base, value);
|
||||
*value_p = value_cast (vfn_base, *value_p);
|
||||
|
||||
/* Now value is an object of the appropriate base type. Fetch its
|
||||
virtual table. */
|
||||
/* It might be possible to do this cast at the same time as the above.
|
||||
Does multiple inheritance affect this?
|
||||
Can this even trigger, or is TYPE_VPTR_BASETYPE idempotent?
|
||||
*/
|
||||
if (TYPE_VPTR_BASETYPE (vfn_base) != vfn_base)
|
||||
value = value_cast (TYPE_VPTR_BASETYPE (vfn_base), value);
|
||||
vtable_address
|
||||
= value_as_address (value_field (value, TYPE_VPTR_FIELDNO (vfn_base)));
|
||||
|
||||
vtable = value_at_lazy (vtable_type,
|
||||
vtable_address - vtable_address_point_offset ());
|
||||
|
||||
/* Fetch the appropriate function pointer from the vtable. */
|
||||
vfn = value_subscript (value_field (vtable, vtable_field_virtual_functions),
|
||||
value_from_longest (builtin_type_int,
|
||||
TYPE_FN_FIELD_VOFFSET (f, j)));
|
||||
|
||||
/* Cast the function pointer to the appropriate type. */
|
||||
vfn = value_cast (lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j)),
|
||||
vfn);
|
||||
|
||||
/* Is (type)value always numerically the same as (vfn_base)value?
|
||||
If so we can spare this cast and use one of the ones above. */
|
||||
*value_p = value_addr (value_cast (type, *value_p));
|
||||
|
||||
return vfn;
|
||||
return gnuv3_get_virtual_fn (*value_p, TYPE_FN_FIELD_TYPE (f, j),
|
||||
TYPE_FN_FIELD_VOFFSET (f, j));
|
||||
}
|
||||
|
||||
/* Compute the offset of the baseclass which is
|
||||
@ -416,6 +434,245 @@ gnuv3_baseclass_offset (struct type *type, int index, const bfd_byte *valaddr,
|
||||
return base_offset;
|
||||
}
|
||||
|
||||
/* Locate a virtual method in DOMAIN or its non-virtual base classes
|
||||
which has virtual table index VOFFSET. The method has an associated
|
||||
"this" adjustment of ADJUSTMENT bytes. */
|
||||
|
||||
const char *
|
||||
gnuv3_find_method_in (struct type *domain, CORE_ADDR voffset,
|
||||
LONGEST adjustment)
|
||||
{
|
||||
int i;
|
||||
const char *physname;
|
||||
|
||||
/* Search this class first. */
|
||||
physname = NULL;
|
||||
if (adjustment == 0)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = TYPE_NFN_FIELDS (domain);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
int len2, j;
|
||||
struct fn_field *f;
|
||||
|
||||
f = TYPE_FN_FIELDLIST1 (domain, i);
|
||||
len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
|
||||
|
||||
check_stub_method_group (domain, i);
|
||||
for (j = 0; j < len2; j++)
|
||||
if (TYPE_FN_FIELD_VOFFSET (f, j) == voffset)
|
||||
return TYPE_FN_FIELD_PHYSNAME (f, j);
|
||||
}
|
||||
}
|
||||
|
||||
/* Next search non-virtual bases. If it's in a virtual base,
|
||||
we're out of luck. */
|
||||
for (i = 0; i < TYPE_N_BASECLASSES (domain); i++)
|
||||
{
|
||||
int pos;
|
||||
struct type *basetype;
|
||||
|
||||
if (BASETYPE_VIA_VIRTUAL (domain, i))
|
||||
continue;
|
||||
|
||||
pos = TYPE_BASECLASS_BITPOS (domain, i) / 8;
|
||||
basetype = TYPE_FIELD_TYPE (domain, i);
|
||||
/* Recurse with a modified adjustment. We don't need to adjust
|
||||
voffset. */
|
||||
if (adjustment >= pos && adjustment < pos + TYPE_LENGTH (basetype))
|
||||
return gnuv3_find_method_in (basetype, voffset, adjustment - pos);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* GNU v3 implementation of cplus_print_method_ptr. */
|
||||
|
||||
static void
|
||||
gnuv3_print_method_ptr (const gdb_byte *contents,
|
||||
struct type *type,
|
||||
struct ui_file *stream)
|
||||
{
|
||||
CORE_ADDR ptr_value;
|
||||
LONGEST adjustment;
|
||||
struct type *domain;
|
||||
int vbit;
|
||||
|
||||
domain = TYPE_DOMAIN_TYPE (type);
|
||||
|
||||
/* Extract the pointer to member. */
|
||||
ptr_value = extract_typed_address (contents, builtin_type_void_func_ptr);
|
||||
contents += TYPE_LENGTH (builtin_type_void_func_ptr);
|
||||
adjustment = extract_signed_integer (contents,
|
||||
TYPE_LENGTH (builtin_type_long));
|
||||
|
||||
if (!gdbarch_vbit_in_delta (current_gdbarch))
|
||||
{
|
||||
vbit = ptr_value & 1;
|
||||
ptr_value = ptr_value ^ vbit;
|
||||
}
|
||||
else
|
||||
{
|
||||
vbit = adjustment & 1;
|
||||
adjustment = adjustment >> 1;
|
||||
}
|
||||
|
||||
/* Check for NULL. */
|
||||
if (ptr_value == 0 && vbit == 0)
|
||||
{
|
||||
fprintf_filtered (stream, "NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Search for a virtual method. */
|
||||
if (vbit)
|
||||
{
|
||||
CORE_ADDR voffset;
|
||||
const char *physname;
|
||||
|
||||
/* It's a virtual table offset, maybe in this class. Search
|
||||
for a field with the correct vtable offset. First convert it
|
||||
to an index, as used in TYPE_FN_FIELD_VOFFSET. */
|
||||
voffset = ptr_value / TYPE_LENGTH (builtin_type_long);
|
||||
|
||||
physname = gnuv3_find_method_in (domain, voffset, adjustment);
|
||||
|
||||
/* If we found a method, print that. We don't bother to disambiguate
|
||||
possible paths to the method based on the adjustment. */
|
||||
if (physname)
|
||||
{
|
||||
char *demangled_name = cplus_demangle (physname,
|
||||
DMGL_ANSI | DMGL_PARAMS);
|
||||
if (demangled_name != NULL)
|
||||
{
|
||||
fprintf_filtered (stream, "&virtual ");
|
||||
fputs_filtered (demangled_name, stream);
|
||||
xfree (demangled_name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We didn't find it; print the raw data. */
|
||||
if (vbit)
|
||||
{
|
||||
fprintf_filtered (stream, "&virtual table offset ");
|
||||
print_longest (stream, 'd', 1, ptr_value);
|
||||
}
|
||||
else
|
||||
print_address_demangle (ptr_value, stream, demangle);
|
||||
|
||||
if (adjustment)
|
||||
{
|
||||
fprintf_filtered (stream, ", this adjustment ");
|
||||
print_longest (stream, 'd', 1, adjustment);
|
||||
}
|
||||
}
|
||||
|
||||
/* GNU v3 implementation of cplus_method_ptr_size. */
|
||||
|
||||
static int
|
||||
gnuv3_method_ptr_size (void)
|
||||
{
|
||||
return 2 * TYPE_LENGTH (builtin_type_void_data_ptr);
|
||||
}
|
||||
|
||||
/* GNU v3 implementation of cplus_make_method_ptr. */
|
||||
|
||||
static void
|
||||
gnuv3_make_method_ptr (gdb_byte *contents, CORE_ADDR value, int is_virtual)
|
||||
{
|
||||
int size = TYPE_LENGTH (builtin_type_void_data_ptr);
|
||||
|
||||
/* FIXME drow/2006-12-24: The adjustment of "this" is currently
|
||||
always zero, since the method pointer is of the correct type.
|
||||
But if the method pointer came from a base class, this is
|
||||
incorrect - it should be the offset to the base. The best
|
||||
fix might be to create the pointer to member pointing at the
|
||||
base class and cast it to the derived class, but that requires
|
||||
support for adjusting pointers to members when casting them -
|
||||
not currently supported by GDB. */
|
||||
|
||||
if (!gdbarch_vbit_in_delta (current_gdbarch))
|
||||
{
|
||||
store_unsigned_integer (contents, size, value | is_virtual);
|
||||
store_unsigned_integer (contents + size, size, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
store_unsigned_integer (contents, size, value);
|
||||
store_unsigned_integer (contents + size, size, is_virtual);
|
||||
}
|
||||
}
|
||||
|
||||
/* GNU v3 implementation of cplus_method_ptr_to_value. */
|
||||
|
||||
static struct value *
|
||||
gnuv3_method_ptr_to_value (struct value **this_p, struct value *method_ptr)
|
||||
{
|
||||
const gdb_byte *contents = value_contents (method_ptr);
|
||||
CORE_ADDR ptr_value;
|
||||
struct type *final_type, *method_type;
|
||||
LONGEST adjustment;
|
||||
struct value *adjval;
|
||||
int vbit;
|
||||
|
||||
final_type = TYPE_DOMAIN_TYPE (check_typedef (value_type (method_ptr)));
|
||||
final_type = lookup_pointer_type (final_type);
|
||||
|
||||
method_type = TYPE_TARGET_TYPE (check_typedef (value_type (method_ptr)));
|
||||
|
||||
ptr_value = extract_typed_address (contents, builtin_type_void_func_ptr);
|
||||
contents += TYPE_LENGTH (builtin_type_void_func_ptr);
|
||||
adjustment = extract_signed_integer (contents,
|
||||
TYPE_LENGTH (builtin_type_long));
|
||||
|
||||
if (!gdbarch_vbit_in_delta (current_gdbarch))
|
||||
{
|
||||
vbit = ptr_value & 1;
|
||||
ptr_value = ptr_value ^ vbit;
|
||||
}
|
||||
else
|
||||
{
|
||||
vbit = adjustment & 1;
|
||||
adjustment = adjustment >> 1;
|
||||
}
|
||||
|
||||
/* First convert THIS to match the containing type of the pointer to
|
||||
member. This cast may adjust the value of THIS. */
|
||||
*this_p = value_cast (final_type, *this_p);
|
||||
|
||||
/* Then apply whatever adjustment is necessary. This creates a somewhat
|
||||
strange pointer: it claims to have type FINAL_TYPE, but in fact it
|
||||
might not be a valid FINAL_TYPE. For instance, it might be a
|
||||
base class of FINAL_TYPE. And if it's not the primary base class,
|
||||
then printing it out as a FINAL_TYPE object would produce some pretty
|
||||
garbage.
|
||||
|
||||
But we don't really know the type of the first argument in
|
||||
METHOD_TYPE either, which is why this happens. We can't
|
||||
dereference this later as a FINAL_TYPE, but once we arrive in the
|
||||
called method we'll have debugging information for the type of
|
||||
"this" - and that'll match the value we produce here.
|
||||
|
||||
You can provoke this case by casting a Base::* to a Derived::*, for
|
||||
instance. */
|
||||
*this_p = value_cast (builtin_type_void_data_ptr, *this_p);
|
||||
adjval = value_from_longest (builtin_type_long, adjustment);
|
||||
*this_p = value_add (*this_p, adjval);
|
||||
*this_p = value_cast (final_type, *this_p);
|
||||
|
||||
if (vbit)
|
||||
{
|
||||
LONGEST voffset = ptr_value / TYPE_LENGTH (builtin_type_long);
|
||||
return gnuv3_get_virtual_fn (value_ind (*this_p), method_type, voffset);
|
||||
}
|
||||
else
|
||||
return value_from_pointer (lookup_pointer_type (method_type), ptr_value);
|
||||
}
|
||||
|
||||
static void
|
||||
init_gnuv3_ops (void)
|
||||
{
|
||||
@ -433,6 +690,10 @@ init_gnuv3_ops (void)
|
||||
gnu_v3_abi_ops.rtti_type = gnuv3_rtti_type;
|
||||
gnu_v3_abi_ops.virtual_fn_field = gnuv3_virtual_fn_field;
|
||||
gnu_v3_abi_ops.baseclass_offset = gnuv3_baseclass_offset;
|
||||
gnu_v3_abi_ops.print_method_ptr = gnuv3_print_method_ptr;
|
||||
gnu_v3_abi_ops.method_ptr_size = gnuv3_method_ptr_size;
|
||||
gnu_v3_abi_ops.make_method_ptr = gnuv3_make_method_ptr;
|
||||
gnu_v3_abi_ops.method_ptr_to_value = gnuv3_method_ptr_to_value;
|
||||
}
|
||||
|
||||
extern initialize_file_ftype _initialize_gnu_v3_abi; /* -Wmissing-prototypes */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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. */
|
||||
|
@ -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,
|
||||
|
@ -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: */
|
||||
|
164
gdb/p-valprint.c
164
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, "<unknown>");
|
||||
return;
|
||||
}
|
||||
addr = unpack_pointer (lookup_pointer_type (builtin_type_void), valaddr);
|
||||
if (METHOD_PTR_IS_VIRTUAL (addr))
|
||||
{
|
||||
offset = METHOD_PTR_TO_VOFFSET (addr);
|
||||
len = TYPE_NFN_FIELDS (domain);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
f = TYPE_FN_FIELDLIST1 (domain, i);
|
||||
len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
|
||||
|
||||
check_stub_method_group (domain, i);
|
||||
for (j = 0; j < len2; j++)
|
||||
{
|
||||
if (TYPE_FN_FIELD_VOFFSET (f, j) == offset)
|
||||
{
|
||||
kind = "virtual ";
|
||||
goto common;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sym = find_pc_function (addr);
|
||||
if (sym == 0)
|
||||
{
|
||||
error (_("invalid pointer to member function"));
|
||||
}
|
||||
len = TYPE_NFN_FIELDS (domain);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
f = TYPE_FN_FIELDLIST1 (domain, i);
|
||||
len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
|
||||
|
||||
check_stub_method_group (domain, i);
|
||||
for (j = 0; j < len2; j++)
|
||||
{
|
||||
if (DEPRECATED_STREQ (DEPRECATED_SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j)))
|
||||
goto common;
|
||||
}
|
||||
}
|
||||
}
|
||||
common:
|
||||
if (i < len)
|
||||
{
|
||||
char *demangled_name;
|
||||
|
||||
fprintf_filtered (stream, "&");
|
||||
fputs_filtered (kind, stream);
|
||||
demangled_name = cplus_demangle (TYPE_FN_FIELD_PHYSNAME (f, j),
|
||||
DMGL_ANSI | DMGL_PARAMS);
|
||||
if (demangled_name == NULL)
|
||||
fprintf_filtered (stream, "<badly mangled name %s>",
|
||||
TYPE_FN_FIELD_PHYSNAME (f, j));
|
||||
else
|
||||
{
|
||||
fputs_filtered (demangled_name, stream);
|
||||
xfree (demangled_name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf_filtered (stream, "(");
|
||||
type_print (type, "", stream, -1);
|
||||
fprintf_filtered (stream, ") %d", (int) addr >> 3);
|
||||
}
|
||||
}
|
||||
|
||||
/* It was changed to this after 2.4.5. */
|
||||
const char pascal_vtbl_ptr_name[] =
|
||||
{'_', '_', 'v', 't', 'b', 'l', '_', 'p', 't', 'r', '_', 't', 'y', 'p', 'e', 0};
|
||||
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -1,3 +1,21 @@
|
||||
2007-01-03 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* gdb.cp/classes.exp (test_pointers_to_class_members): Update expected
|
||||
output. Test the types of members and member pointers.
|
||||
* gdb.cp/inherit.exp (test_print_mi_member_types): Remove KFAILs for
|
||||
gdb/2092.
|
||||
* gdb.cp/member-ptr.exp: Search for a comment instead of a
|
||||
statement. Enable for GCC. Update expected output for some tests
|
||||
and add new tests. Remove obsolete GCC KFAILs. Allow GCC's class
|
||||
layout.
|
||||
* gdb.cp/member-ptr.cc (Padding, Padding::vspacer, Base, Base::get_x)
|
||||
(Base::vget_base, Left, Left::vget, Right, Right::vget, Diamond)
|
||||
(Diamond::vget_base): New.
|
||||
(main): Add new tests.
|
||||
* gdb.cp/printmethod.exp: Update expected output for member functions.
|
||||
* gdb.cp/virtfunc.exp (test_virtual_calls): Add a KFAIL for
|
||||
print pEe->D::vg().
|
||||
|
||||
2007-01-03 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* gdb.threads/tls.exp: Allow stops in sem_post.
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 <pai@apollo.hp.com> 1997-08-19
|
||||
# Rewritten by Michael Chastain <mec.gnu@mindspring.com> 2004-01-11
|
||||
|
||||
# TODO: copyright notice for member-ptr.cc
|
||||
|
||||
set vhn "\\$\[0-9\]+"
|
||||
|
||||
if $tracelevel then {
|
||||
@ -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 <A::bar\\(int\\)>\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 <A::bar\\(int\\)>\r\n$gdb_prompt$ " {
|
||||
-re "$vhn = {int \\(A \\*, int\\)} $hex <A::bar\\(int\\)>\r\n$gdb_prompt $" {
|
||||
pass $name
|
||||
}
|
||||
-re "Pointers to methods not supported with HP aCC\r\n$gdb_prompt $" {
|
||||
@ -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 <A::bar\\(int\\)>\r\n$gdb_prompt$ " {
|
||||
-re "$vhn = {int \\(A \\*, int\\)} $hex <A::bar\\(int\\)>\r\n$gdb_prompt $" {
|
||||
pass $name
|
||||
}
|
||||
-re "Pointers to methods not supported with HP aCC\r\n$gdb_prompt $" {
|
||||
@ -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 <Base::get_x\\((void|)\\)>"
|
||||
gdb_test "print diamond.*right_pmf" \
|
||||
"$vhn = {int \\(Diamond \\*\\)} $hex <Base::get_x\\((void|)\\)>"
|
||||
|
||||
gdb_test "print (diamond.*left_pmf) ()" "$vhn = 77"
|
||||
gdb_test "print (diamond.*right_pmf) ()" "$vhn = 88"
|
||||
|
||||
# These two point to different methods, although they have the same
|
||||
# virtual table offsets.
|
||||
gdb_test "print diamond.*left_vpmf" \
|
||||
"$vhn = {int \\(Diamond \\*\\)} $hex <Left::vget\\((void|)\\)>"
|
||||
gdb_test "print diamond.*right_vpmf" \
|
||||
"$vhn = {int \\(Diamond \\*\\)} $hex <Right::vget\\((void|)\\)>"
|
||||
|
||||
gdb_test "print (diamond.*left_vpmf) ()" "$vhn = 177"
|
||||
gdb_test "print (diamond.*left_base_vpmf) ()" "$vhn = 2077"
|
||||
gdb_test "print (diamond.*right_vpmf) ()" "$vhn = 288"
|
||||
|
||||
# We should be able to figure out left_vpmf even without an object,
|
||||
# because it comes from a non-virtual base. The same for right_vpmf.
|
||||
gdb_test "print left_vpmf" "$vhn = &virtual Left::vget\\(\\)"
|
||||
gdb_test "print right_vpmf" "$vhn = &virtual Right::vget\\(\\)"
|
||||
|
||||
# But we should gracefully fail to figure out base_vpmf, because
|
||||
# its runtime type is more derived than its static type. This
|
||||
# is a valid but unspecified cast (it is value preserving, i.e.
|
||||
# can be casted back to the correct type and used).
|
||||
gdb_test "print base_vpmf" \
|
||||
"$vhn = &virtual table offset \[0-9\]*, this adjustment -\[0-9\]*"
|
||||
|
||||
# Make sure we parse this correctly; it's invalid.
|
||||
gdb_test "print diamond.*left_vpmf ()" \
|
||||
"Invalid data type for function to be called\\."
|
||||
|
||||
# NULL pointer to member tests.
|
||||
gdb_test "print null_pmi" "$vhn = NULL"
|
||||
gdb_test "print null_pmi = &A::j" "$vhn = &A::j"
|
||||
gdb_test "print null_pmi = 0" "$vhn = NULL"
|
||||
|
||||
gdb_test "print null_pmf" "$vhn = NULL"
|
||||
gdb_test "print null_pmf = &A::foo" "$vhn = $hex <A::foo ?\\(int\\)>"
|
||||
gdb_test "print null_pmf = 0" "$vhn = NULL"
|
||||
|
@ -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 <A::virt\\((void|)\\)>" \
|
||||
"print virtual method."
|
||||
gdb_test "print theA->nonvirt" \
|
||||
"\\$\[0-9\]* = {void \\(A \\*\\)} $hex <A::nonvirt\\((void|)\\)>" \
|
||||
"print nonvirtual method."
|
||||
|
||||
gdb_exit
|
||||
return 0
|
||||
|
@ -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()"
|
||||
}
|
||||
|
@ -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:
|
||||
|
182
gdb/valops.c
182
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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user