yann@96: This patch needs to be submitted for the FSF. Also, there may be testcases yann@96: already in the GDB testsuite (currently disabled) that it would probably fix. yann@96: yann@96: Index: gdb-6.3/gdb/infcall.c yann@96: =================================================================== yann@96: --- gdb-6.3.orig/gdb/infcall.c 2004-10-08 04:15:56.000000000 -0400 yann@96: +++ gdb-6.3/gdb/infcall.c 2004-11-10 12:30:07.000000000 -0500 yann@96: @@ -36,6 +36,7 @@ yann@96: #include "gdb_string.h" yann@96: #include "infcall.h" yann@96: #include "dummy-frame.h" yann@96: +#include "cp-abi.h" yann@96: yann@96: /* NOTE: cagney/2003-04-16: What's the future of this code? yann@96: yann@96: @@ -297,8 +298,8 @@ call_function_by_hand (struct value *fun yann@96: { yann@96: CORE_ADDR sp; yann@96: CORE_ADDR dummy_addr; yann@96: - struct type *value_type; yann@96: - unsigned char struct_return; yann@96: + struct type *value_type, *target_value_type; yann@96: + unsigned char struct_return = 0, cp_struct_return = 0; yann@96: CORE_ADDR struct_addr = 0; yann@96: struct regcache *retbuf; yann@96: struct cleanup *retbuf_cleanup; yann@96: @@ -312,6 +313,7 @@ call_function_by_hand (struct value *fun yann@96: struct regcache *caller_regcache; yann@96: struct cleanup *caller_regcache_cleanup; yann@96: struct frame_id dummy_id; yann@96: + struct cleanup *args_cleanup; yann@96: yann@96: if (!target_has_execution) yann@96: noprocess (); yann@96: @@ -410,10 +412,31 @@ call_function_by_hand (struct value *fun yann@96: using_gcc = (b == NULL ? 2 : BLOCK_GCC_COMPILED (b)); yann@96: } yann@96: yann@96: - /* Are we returning a value using a structure return or a normal yann@96: - value return? */ yann@96: + /* Are we returning a value using a structure return (passing a yann@96: + hidden argument pointing to storage) or a normal value return? yann@96: + There are two cases: C++ ABI mandated structure return and yann@96: + target ABI structure return. The variable STRUCT_RETURN only yann@96: + describes the latter. The C++ version is handled by passing yann@96: + the return location as the first parameter to the function, yann@96: + even preceding "this". This is different from the target yann@96: + ABI version, which is target-specific; for instance, on ia64 yann@96: + the first argument is passed in out0 but the hidden structure yann@96: + return pointer would normally be passed in r8. */ yann@96: yann@96: - struct_return = using_struct_return (value_type, using_gcc); yann@96: + if (current_language->la_language == language_cplus yann@96: + && cp_pass_by_reference (value_type)) yann@96: + { yann@96: + cp_struct_return = 1; yann@96: + yann@96: + /* Tell the target specific argument pushing routine not to yann@96: + expect a value. */ yann@96: + target_value_type = builtin_type_void; yann@96: + } yann@96: + else yann@96: + { yann@96: + struct_return = using_struct_return (value_type, using_gcc); yann@96: + target_value_type = value_type; yann@96: + } yann@96: yann@96: /* Determine the location of the breakpoint (and possibly other yann@96: stuff) that the called function will return to. The SPARC, for a yann@96: @@ -432,7 +455,7 @@ call_function_by_hand (struct value *fun yann@96: if (INNER_THAN (1, 2)) yann@96: { yann@96: sp = push_dummy_code (current_gdbarch, sp, funaddr, yann@96: - using_gcc, args, nargs, value_type, yann@96: + using_gcc, args, nargs, target_value_type, yann@96: &real_pc, &bp_addr); yann@96: dummy_addr = sp; yann@96: } yann@96: @@ -440,7 +463,7 @@ call_function_by_hand (struct value *fun yann@96: { yann@96: dummy_addr = sp; yann@96: sp = push_dummy_code (current_gdbarch, sp, funaddr, yann@96: - using_gcc, args, nargs, value_type, yann@96: + using_gcc, args, nargs, target_value_type, yann@96: &real_pc, &bp_addr); yann@96: } yann@96: break; yann@96: @@ -507,9 +530,15 @@ call_function_by_hand (struct value *fun yann@96: param_type = TYPE_FIELD_TYPE (ftype, i); yann@96: else yann@96: param_type = NULL; yann@96: - yann@96: + yann@96: args[i] = value_arg_coerce (args[i], param_type, prototyped); yann@96: yann@96: + /* FIXME: Is current_language the right language? */ yann@96: + if (current_language->la_language == language_cplus yann@96: + && param_type != NULL yann@96: + && cp_pass_by_reference (param_type)) yann@96: + args[i] = value_addr (args[i]); yann@96: + yann@96: /* elz: this code is to handle the case in which the function yann@96: to be called has a pointer to function as parameter and the yann@96: corresponding actual argument is the address of a function yann@96: @@ -607,7 +636,7 @@ You must use a pointer to function type yann@96: stack, if necessary. Make certain that the value is correctly yann@96: aligned. */ yann@96: yann@96: - if (struct_return) yann@96: + if (struct_return || cp_struct_return) yann@96: { yann@96: int len = TYPE_LENGTH (value_type); yann@96: if (INNER_THAN (1, 2)) yann@96: @@ -632,6 +661,22 @@ You must use a pointer to function type yann@96: } yann@96: } yann@96: yann@96: + if (cp_struct_return) yann@96: + { yann@96: + struct value **new_args; yann@96: + yann@96: + /* Add the new argument to the front of the argument list. */ yann@96: + new_args = xmalloc (sizeof (struct value *) * (nargs + 1)); yann@96: + new_args[0] = value_from_pointer (lookup_pointer_type (value_type), yann@96: + struct_addr); yann@96: + memcpy (&new_args[1], &args[0], sizeof (struct value *) * nargs); yann@96: + args = new_args; yann@96: + nargs++; yann@96: + args_cleanup = make_cleanup (xfree, args); yann@96: + } yann@96: + else yann@96: + args_cleanup = make_cleanup (null_cleanup, NULL); yann@96: + yann@96: /* Create the dummy stack frame. Pass in the call dummy address as, yann@96: presumably, the ABI code knows where, in the call dummy, the yann@96: return address should be pointed. */ yann@96: @@ -649,6 +694,8 @@ You must use a pointer to function type yann@96: else yann@96: error ("This target does not support function calls"); yann@96: yann@96: + do_cleanups (args_cleanup); yann@96: + yann@96: /* Set up a frame ID for the dummy frame so we can pass it to yann@96: set_momentary_breakpoint. We need to give the breakpoint a frame yann@96: ID so that the breakpoint code can correctly re-identify the yann@96: @@ -839,11 +886,7 @@ the function call).", name); yann@96: /* Figure out the value returned by the function, return that. */ yann@96: { yann@96: struct value *retval; yann@96: - if (TYPE_CODE (value_type) == TYPE_CODE_VOID) yann@96: - /* If the function returns void, don't bother fetching the yann@96: - return value. */ yann@96: - retval = allocate_value (value_type); yann@96: - else if (struct_return) yann@96: + if (struct_return || cp_struct_return) yann@96: /* NOTE: cagney/2003-09-27: This assumes that PUSH_DUMMY_CALL yann@96: has correctly stored STRUCT_ADDR in the target. In the past yann@96: that hasn't been the case, the old MIPS PUSH_ARGUMENTS yann@96: @@ -853,6 +896,10 @@ the function call).", name); yann@96: "struct return convention", check that PUSH_DUMMY_CALL isn't yann@96: playing tricks. */ yann@96: retval = value_at (value_type, struct_addr, NULL); yann@96: + else if (TYPE_CODE (value_type) == TYPE_CODE_VOID) yann@96: + /* If the function returns void, don't bother fetching the yann@96: + return value. */ yann@96: + retval = allocate_value (value_type); yann@96: else yann@96: { yann@96: /* This code only handles "register convention". */ yann@96: Index: gdb-6.3/gdb/cp-abi.h yann@96: =================================================================== yann@96: --- gdb-6.3.orig/gdb/cp-abi.h 2003-04-12 13:41:25.000000000 -0400 yann@96: +++ gdb-6.3/gdb/cp-abi.h 2004-11-10 12:30:07.000000000 -0500 yann@96: @@ -1,7 +1,7 @@ yann@96: /* Abstraction of various C++ ABI's we support, and the info we need yann@96: to get from them. yann@96: Contributed by Daniel Berlin yann@96: - Copyright 2001 Free Software Foundation, Inc. yann@96: + Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc. yann@96: yann@96: This file is part of GDB. yann@96: yann@96: @@ -145,6 +145,10 @@ extern struct type *value_rtti_type (str yann@96: extern int baseclass_offset (struct type *type, int index, char *valaddr, yann@96: CORE_ADDR address); yann@96: yann@96: +/* Return non-zero if an argument of type TYPE should be passed by reference yann@96: + instead of value. */ yann@96: +extern int cp_pass_by_reference (struct type *type); yann@96: + yann@96: struct cp_abi_ops yann@96: { yann@96: const char *shortname; yann@96: @@ -162,6 +166,7 @@ struct cp_abi_ops yann@96: int *using_enc); yann@96: int (*baseclass_offset) (struct type *type, int index, char *valaddr, yann@96: CORE_ADDR address); yann@96: + int (*pass_by_reference) (struct type *type); yann@96: }; yann@96: yann@96: yann@96: Index: gdb-6.3/gdb/cp-abi.c yann@96: =================================================================== yann@96: --- gdb-6.3.orig/gdb/cp-abi.c 2003-11-26 17:04:00.000000000 -0500 yann@96: +++ gdb-6.3/gdb/cp-abi.c 2004-11-10 12:30:07.000000000 -0500 yann@96: @@ -1,5 +1,5 @@ yann@96: /* Generic code for supporting multiple C++ ABI's yann@96: - Copyright 2001, 2002, 2003 Free Software Foundation, Inc. yann@96: + Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc. yann@96: yann@96: This file is part of GDB. yann@96: yann@96: @@ -94,6 +94,14 @@ value_rtti_type (struct value *v, int *f yann@96: return (*current_cp_abi.rtti_type) (v, full, top, using_enc); yann@96: } yann@96: yann@96: +int yann@96: +cp_pass_by_reference (struct type *type) yann@96: +{ yann@96: + if ((current_cp_abi.pass_by_reference) == NULL) yann@96: + return 0; yann@96: + return (*current_cp_abi.pass_by_reference) (type); yann@96: +} yann@96: + yann@96: /* Set the current C++ ABI to SHORT_NAME. */ yann@96: yann@96: static int yann@96: Index: gdb-6.3/gdb/gnu-v3-abi.c yann@96: =================================================================== yann@96: --- gdb-6.3.orig/gdb/gnu-v3-abi.c 2004-03-15 15:38:08.000000000 -0500 yann@96: +++ gdb-6.3/gdb/gnu-v3-abi.c 2004-11-10 12:30:07.000000000 -0500 yann@96: @@ -1,7 +1,7 @@ yann@96: /* Abstraction of GNU v3 abi. yann@96: Contributed by Jim Blandy yann@96: yann@96: - Copyright 2001, 2002, 2003 Free Software Foundation, Inc. yann@96: + Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc. yann@96: yann@96: This file is part of GDB. yann@96: yann@96: @@ -419,6 +419,84 @@ gnuv3_baseclass_offset (struct type *typ yann@96: return base_offset; yann@96: } yann@96: yann@96: +/* Return nonzero if a type should be passed by reference. yann@96: + yann@96: + The rule in the v3 ABI document comes from section 3.1.1. If the yann@96: + type has a non-trivial copy constructor or destructor, then the yann@96: + caller must make a copy (by calling the copy constructor if there yann@96: + is one or perform the copy itself otherwise), pass the address of yann@96: + the copy, and then destroy the temporary (if necessary). yann@96: + yann@96: + For return values with non-trivial copy constructors or yann@96: + destructors, space will be allocated in the caller, and a pointer yann@96: + will be passed as the first argument (preceding "this"). yann@96: + yann@96: + We don't have a bulletproof mechanism for determining whether a yann@96: + constructor or destructor is trivial. For GCC and DWARF2 debug yann@96: + information, we can check the artificial flag. yann@96: + yann@96: + We don't do anything with the constructors or destructors yet, yann@96: + but we have to get the argument passing right anyway. */ yann@96: +static int yann@96: +gnuv3_pass_by_reference (struct type *type) yann@96: +{ yann@96: + int fieldnum, fieldelem, basenum; yann@96: + yann@96: + CHECK_TYPEDEF (type); yann@96: + yann@96: + /* We're only interested in things that can have methods. */ yann@96: + if (TYPE_CODE (type) != TYPE_CODE_STRUCT yann@96: + && TYPE_CODE (type) != TYPE_CODE_CLASS yann@96: + && TYPE_CODE (type) != TYPE_CODE_UNION) yann@96: + return 0; yann@96: + yann@96: + for (fieldnum = 0; fieldnum < TYPE_NFN_FIELDS (type); fieldnum++) yann@96: + for (fieldelem = 0; fieldelem < TYPE_FN_FIELDLIST_LENGTH (type, fieldnum); yann@96: + fieldelem++) yann@96: + { yann@96: + struct fn_field *fn = TYPE_FN_FIELDLIST1 (type, fieldnum); yann@96: + char *name = TYPE_FN_FIELDLIST_NAME (type, fieldnum); yann@96: + struct type *fieldtype = TYPE_FN_FIELD_TYPE (fn, fieldelem); yann@96: + yann@96: + /* If this function is marked as artificial, it is compiler-generated, yann@96: + and we assume it is trivial. */ yann@96: + if (TYPE_FN_FIELD_ARTIFICIAL (fn, fieldelem)) yann@96: + continue; yann@96: + yann@96: + /* If we've found a destructor, we must pass this by reference. */ yann@96: + if (name[0] == '~') yann@96: + return 1; yann@96: + yann@96: + /* If the mangled name of this method doesn't indicate that it yann@96: + is a constructor, we're not interested. yann@96: + yann@96: + FIXME drow/2004-05-27: We could do this using the name of yann@96: + the method and the name of the class instead of dealing yann@96: + with the mangled name. We don't have a convenient function yann@96: + to strip off both leading scope qualifiers and trailing yann@96: + template arguments yet. */ yann@96: + if (!is_constructor_name (TYPE_FN_FIELD_PHYSNAME (fn, fieldelem))) yann@96: + continue; yann@96: + yann@96: + /* If this method takes two arguments, and the second argument is yann@96: + a reference to this class, then it is a copy constructor. */ yann@96: + if (TYPE_NFIELDS (fieldtype) == 2 yann@96: + && TYPE_CODE (TYPE_FIELD_TYPE (fieldtype, 1)) == TYPE_CODE_REF yann@96: + && check_typedef (TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (fieldtype, 1))) == type) yann@96: + return 1; yann@96: + } yann@96: + yann@96: + /* Even if all the constructors and destructors were artificial, one yann@96: + of them may have invoked a non-artificial constructor or yann@96: + destructor in a base class. If any base class needs to be passed yann@96: + by reference, so does this class. */ yann@96: + for (basenum = 0; basenum < TYPE_N_BASECLASSES (type); basenum++) yann@96: + if (gnuv3_pass_by_reference (TYPE_BASECLASS (type, basenum))) yann@96: + return 1; yann@96: + yann@96: + return 0; yann@96: +} yann@96: + yann@96: static void yann@96: init_gnuv3_ops (void) yann@96: { yann@96: @@ -434,6 +512,7 @@ init_gnuv3_ops (void) yann@96: gnu_v3_abi_ops.rtti_type = gnuv3_rtti_type; yann@96: gnu_v3_abi_ops.virtual_fn_field = gnuv3_virtual_fn_field; yann@96: gnu_v3_abi_ops.baseclass_offset = gnuv3_baseclass_offset; yann@96: + gnu_v3_abi_ops.pass_by_reference = gnuv3_pass_by_reference; yann@96: } yann@96: yann@96: extern initialize_file_ftype _initialize_gnu_v3_abi; /* -Wmissing-prototypes */ yann@96: Index: gdb-6.3/gdb/hpacc-abi.c yann@96: =================================================================== yann@96: --- gdb-6.3.orig/gdb/hpacc-abi.c 2003-06-08 14:27:13.000000000 -0400 yann@96: +++ gdb-6.3/gdb/hpacc-abi.c 2004-11-10 12:30:07.000000000 -0500 yann@96: @@ -3,7 +3,7 @@ yann@96: Most of the real code is from HP, i've just fiddled it to fit in yann@96: the C++ ABI abstraction framework. yann@96: yann@96: - Copyright 2001 Free Software Foundation, Inc. yann@96: + Copyright 2001, 2002, 2003 Free Software Foundation, Inc. yann@96: yann@96: This file is part of GDB. yann@96: yann@96: Index: gdb-6.3/gdb/Makefile.in yann@96: =================================================================== yann@96: --- gdb-6.3.orig/gdb/Makefile.in 2004-11-10 12:30:06.000000000 -0500 yann@96: +++ gdb-6.3/gdb/Makefile.in 2004-11-10 12:30:07.000000000 -0500 yann@96: @@ -2073,7 +2073,7 @@ ia64-tdep.o: ia64-tdep.c $(defs_h) $(inf yann@96: infcall.o: infcall.c $(defs_h) $(breakpoint_h) $(target_h) $(regcache_h) \ yann@96: $(inferior_h) $(gdb_assert_h) $(block_h) $(gdbcore_h) $(language_h) \ yann@96: $(objfiles_h) $(gdbcmd_h) $(command_h) $(gdb_string_h) $(infcall_h) \ yann@96: - $(dummy_frame_h) yann@96: + $(dummy_frame_h) $(cp_abi_h) yann@96: inf-child.o: inf-child.c $(defs_h) $(regcache_h) $(memattr_h) $(symtab_h) \ yann@96: $(target_h) $(inferior_h) $(gdb_string_h) yann@96: infcmd.o: infcmd.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \ yann@96: Index: gdb-6.3/gdb/testsuite/gdb.cp/pass-by-ref.exp yann@96: =================================================================== yann@96: --- /dev/null 1970-01-01 00:00:00.000000000 +0000 yann@96: +++ gdb-6.3/gdb/testsuite/gdb.cp/pass-by-ref.exp 2004-11-11 09:48:00.498518899 -0500 yann@96: @@ -0,0 +1,38 @@ yann@96: +# This testcase is part of GDB, the GNU debugger. yann@96: + yann@96: +# Copyright 2004 Free Software Foundation, Inc. yann@96: + yann@96: +# This program is free software; you can redistribute it and/or modify yann@96: +# it under the terms of the GNU General Public License as published by yann@96: +# the Free Software Foundation; either version 2 of the License, or yann@96: +# (at your option) any later version. yann@96: +# yann@96: +# This program is distributed in the hope that it will be useful, yann@96: +# but WITHOUT ANY WARRANTY; without even the implied warranty of yann@96: +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the yann@96: +# GNU General Public License for more details. yann@96: +# yann@96: +# You should have received a copy of the GNU General Public License yann@96: +# along with this program; if not, write to the Free Software yann@96: +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. yann@96: + yann@96: +# Check that GDB can call C++ functions whose parameters have yann@96: +# object type, but are passed by reference. yann@96: + yann@96: +set testfile "pass-by-ref" yann@96: +set srcfile ${testfile}.cc yann@96: +set binfile ${objdir}/${subdir}/${testfile} yann@96: +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { yann@96: + return -1 yann@96: +} yann@96: + yann@96: +gdb_exit yann@96: +gdb_start yann@96: +gdb_reinitialize_dir $srcdir/$subdir yann@96: +gdb_load ${binfile} yann@96: + yann@96: +if ![runto_main] then { yann@96: + return -1 yann@96: +} yann@96: + yann@96: +gdb_test "print foo (global_obj)" " = 3" "call function" yann@96: Index: gdb-6.3/gdb/testsuite/gdb.cp/pass-by-ref.cc yann@96: =================================================================== yann@96: --- /dev/null 1970-01-01 00:00:00.000000000 +0000 yann@96: +++ gdb-6.3/gdb/testsuite/gdb.cp/pass-by-ref.cc 2004-11-11 09:44:17.815014667 -0500 yann@96: @@ -0,0 +1,57 @@ yann@96: +/* This testcase is part of GDB, the GNU debugger. yann@96: + yann@96: + Copyright 2004 Free Software Foundation, Inc. yann@96: + yann@96: + This program is free software; you can redistribute it and/or modify yann@96: + it under the terms of the GNU General Public License as published by yann@96: + the Free Software Foundation; either version 2 of the License, or yann@96: + (at your option) any later version. yann@96: + yann@96: + This program is distributed in the hope that it will be useful, yann@96: + but WITHOUT ANY WARRANTY; without even the implied warranty of yann@96: + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the yann@96: + GNU General Public License for more details. yann@96: + yann@96: + You should have received a copy of the GNU General Public License yann@96: + along with this program; if not, write to the Free Software yann@96: + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, yann@96: + USA. */ yann@96: + yann@96: +class Obj { yann@96: +public: yann@96: + Obj (); yann@96: + Obj (const Obj &); yann@96: + ~Obj (); yann@96: + int var[2]; yann@96: +}; yann@96: + yann@96: +int foo (Obj arg) yann@96: +{ yann@96: + return arg.var[0] + arg.var[1]; yann@96: +} yann@96: + yann@96: +Obj::Obj () yann@96: +{ yann@96: + var[0] = 1; yann@96: + var[1] = 2; yann@96: +} yann@96: + yann@96: +Obj::Obj (const Obj &obj) yann@96: +{ yann@96: + var[0] = obj.var[0]; yann@96: + var[1] = obj.var[1]; yann@96: +} yann@96: + yann@96: +Obj::~Obj () yann@96: +{ yann@96: + yann@96: +} yann@96: + yann@96: +Obj global_obj; yann@96: + yann@96: +int yann@96: +main () yann@96: +{ yann@96: + int bar = foo (global_obj); yann@96: + return bar; yann@96: +}