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