From: Daniel Jacobowitz Date: Sun, 23 Sep 2007 16:25:06 +0000 (+0000) Subject: * infcall.c (call_function_by_hand): Handle language-specific X-Git-Tag: sid-snapshot-20071001~88 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=41f1b6975dce5616800a8ff1acb544019c7bc132;p=external%2Fbinutils.git * infcall.c (call_function_by_hand): Handle language-specific pass and return by reference. * cp-abi.c (cp_pass_by_reference): New. * cp-abi.h (cp_pass_by_reference): Declare. (struct cp_abi_ops): Add pass_by_reference. * gnu-v3-abi.c (gnuv3_pass_by_reference): New. (init_gnuv3_ops): Set pass_by_reference. * language.c (language_pass_by_reference): New. (default_pass_by_reference): New. (unknown_language_defn, auto_language_defn, local_language_defn): Add default_pass_by_reference. * langauge.h (struct language_defn): Add la_pass_by_reference. (language_pass_by_reference, default_pass_by_reference): Declare. * ada-lang.c (ada_language_defn): Add default_pass_by_reference. * c-lang.c (c_language_defn, asm_language_defn) (minimal_language_defn): Likewise. (cplus_language_defn): Add cp_pass_by_reference. * f-lang.c (f_language_defn): Add default_pass_by_reference. * jv-lang.c (java_language_defn): Likewise. * m2-lang.c (m2_language_defn): Likewise. * objc-lang.c (objc_language_defn): Likewise. * p-lang.c (pascal_language_defn): Likewise. * scm-lang.c (scm_language_defn): Likewise * gdb.cp/pass-by-ref.cc, gdb.cp/pass-by-ref.exp: New files. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index b9ba285..3c55358 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,31 @@ +2007-09-23 Daniel Jacobowitz + + * infcall.c (call_function_by_hand): Handle language-specific + pass and return by reference. + + * cp-abi.c (cp_pass_by_reference): New. + * cp-abi.h (cp_pass_by_reference): Declare. + (struct cp_abi_ops): Add pass_by_reference. + * gnu-v3-abi.c (gnuv3_pass_by_reference): New. + (init_gnuv3_ops): Set pass_by_reference. + + * language.c (language_pass_by_reference): New. + (default_pass_by_reference): New. + (unknown_language_defn, auto_language_defn, local_language_defn): Add + default_pass_by_reference. + * langauge.h (struct language_defn): Add la_pass_by_reference. + (language_pass_by_reference, default_pass_by_reference): Declare. + * ada-lang.c (ada_language_defn): Add default_pass_by_reference. + * c-lang.c (c_language_defn, asm_language_defn) + (minimal_language_defn): Likewise. + (cplus_language_defn): Add cp_pass_by_reference. + * f-lang.c (f_language_defn): Add default_pass_by_reference. + * jv-lang.c (java_language_defn): Likewise. + * m2-lang.c (m2_language_defn): Likewise. + * objc-lang.c (objc_language_defn): Likewise. + * p-lang.c (pascal_language_defn): Likewise. + * scm-lang.c (scm_language_defn): Likewise + 2007-09-23 Vladimir Prus Allow a code breakpoint to have several locations diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index 4960fda..04135fe 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -10441,6 +10441,7 @@ const struct language_defn ada_language_defn = { ada_get_gdb_completer_word_break_characters, ada_language_arch_info, ada_print_array_index, + default_pass_by_reference, LANG_MAGIC }; diff --git a/gdb/c-lang.c b/gdb/c-lang.c index 7b9ebbb..7855551 100644 --- a/gdb/c-lang.c +++ b/gdb/c-lang.c @@ -606,6 +606,7 @@ const struct language_defn c_language_defn = default_word_break_characters, c_language_arch_info, default_print_array_index, + default_pass_by_reference, LANG_MAGIC }; @@ -711,6 +712,7 @@ const struct language_defn cplus_language_defn = default_word_break_characters, cplus_language_arch_info, default_print_array_index, + cp_pass_by_reference, LANG_MAGIC }; @@ -747,6 +749,7 @@ const struct language_defn asm_language_defn = default_word_break_characters, c_language_arch_info, /* FIXME: la_language_arch_info. */ default_print_array_index, + default_pass_by_reference, LANG_MAGIC }; @@ -788,6 +791,7 @@ const struct language_defn minimal_language_defn = default_word_break_characters, c_language_arch_info, default_print_array_index, + default_pass_by_reference, LANG_MAGIC }; diff --git a/gdb/cp-abi.c b/gdb/cp-abi.c index 9d5d60c..ced1a96 100644 --- a/gdb/cp-abi.c +++ b/gdb/cp-abi.c @@ -135,6 +135,14 @@ cplus_method_ptr_to_value (struct value **this_p, struct value *method_ptr) return (*current_cp_abi.method_ptr_to_value) (this_p, method_ptr); } +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 diff --git a/gdb/cp-abi.h b/gdb/cp-abi.h index a0efb33..2b1838d 100644 --- a/gdb/cp-abi.h +++ b/gdb/cp-abi.h @@ -172,6 +172,10 @@ void cplus_make_method_ptr (gdb_byte *CONTENTS, CORE_ADDR address, CORE_ADDR cplus_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc); +/* 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; @@ -195,6 +199,7 @@ struct cp_abi_ops void (*make_method_ptr) (gdb_byte *, CORE_ADDR, int); struct value * (*method_ptr_to_value) (struct value **, struct value *); CORE_ADDR (*skip_trampoline) (struct frame_info *, CORE_ADDR); + int (*pass_by_reference) (struct type *type); }; diff --git a/gdb/f-lang.c b/gdb/f-lang.c index b0189a2..0006ff8 100644 --- a/gdb/f-lang.c +++ b/gdb/f-lang.c @@ -503,6 +503,7 @@ const struct language_defn f_language_defn = default_word_break_characters, f_language_arch_info, default_print_array_index, + default_pass_by_reference, LANG_MAGIC }; diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c index 469fc57..c3e07a1 100644 --- a/gdb/gnu-v3-abi.c +++ b/gdb/gnu-v3-abi.c @@ -716,6 +716,87 @@ gnuv3_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc) return real_stop_pc; } +/* 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, + but we have to get the argument passing right anyway. */ +static int +gnuv3_pass_by_reference (struct type *type) +{ + int fieldnum, fieldelem; + + 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/2007-09-23: 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. Similarly for members, which + are constructed whenever this class is. We do not need to worry + about recursive loops here, since we are only looking at members + of complete class type. */ + for (fieldnum = 0; fieldnum < TYPE_NFIELDS (type); fieldnum++) + if (gnuv3_pass_by_reference (TYPE_FIELD_TYPE (type, fieldnum))) + return 1; + + return 0; +} + static void init_gnuv3_ops (void) { @@ -738,6 +819,7 @@ init_gnuv3_ops (void) gnu_v3_abi_ops.make_method_ptr = gnuv3_make_method_ptr; gnu_v3_abi_ops.method_ptr_to_value = gnuv3_method_ptr_to_value; gnu_v3_abi_ops.skip_trampoline = gnuv3_skip_trampoline; + gnu_v3_abi_ops.pass_by_reference = gnuv3_pass_by_reference; } extern initialize_file_ftype _initialize_gnu_v3_abi; /* -Wmissing-prototypes */ diff --git a/gdb/infcall.c b/gdb/infcall.c index b603da8..3012d7f 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -339,8 +339,8 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) { CORE_ADDR sp; CORE_ADDR dummy_addr; - struct type *values_type; - unsigned char struct_return; + struct type *values_type, *target_values_type; + unsigned char struct_return = 0, lang_struct_return = 0; CORE_ADDR struct_addr = 0; struct regcache *retbuf; struct cleanup *retbuf_cleanup; @@ -354,6 +354,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) struct regcache *caller_regcache; struct cleanup *caller_regcache_cleanup; struct frame_id dummy_id; + struct cleanup *args_cleanup; if (TYPE_CODE (ftype) == TYPE_CODE_PTR) ftype = check_typedef (TYPE_TARGET_TYPE (ftype)); @@ -460,10 +461,30 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) 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: language-mandated structure return and + target ABI structure return. The variable STRUCT_RETURN only + describes the latter. The language 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. */ + + if (language_pass_by_reference (values_type)) + { + lang_struct_return = 1; - struct_return = using_struct_return (values_type, using_gcc); + /* Tell the target specific argument pushing routine not to + expect a value. */ + target_values_type = builtin_type_void; + } + else + { + struct_return = using_struct_return (values_type, using_gcc); + target_values_type = values_type; + } /* Determine the location of the breakpoint (and possibly other stuff) that the called function will return to. The SPARC, for a @@ -482,7 +503,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) if (gdbarch_inner_than (current_gdbarch, 1, 2)) { sp = push_dummy_code (current_gdbarch, sp, funaddr, - using_gcc, args, nargs, values_type, + using_gcc, args, nargs, target_values_type, &real_pc, &bp_addr, get_current_regcache ()); dummy_addr = sp; } @@ -490,7 +511,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) { dummy_addr = sp; sp = push_dummy_code (current_gdbarch, sp, funaddr, - using_gcc, args, nargs, values_type, + using_gcc, args, nargs, target_values_type, &real_pc, &bp_addr, get_current_regcache ()); } break; @@ -557,9 +578,12 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) param_type = TYPE_FIELD_TYPE (ftype, i); else param_type = NULL; - + args[i] = value_arg_coerce (args[i], param_type, prototyped); + if (param_type != NULL && language_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 @@ -659,7 +683,7 @@ You must use a pointer to function type variable. Command ignored."), arg_name); stack, if necessary. Make certain that the value is correctly aligned. */ - if (struct_return) + if (struct_return || lang_struct_return) { int len = TYPE_LENGTH (values_type); if (gdbarch_inner_than (current_gdbarch, 1, 2)) @@ -684,6 +708,22 @@ You must use a pointer to function type variable. Command ignored."), arg_name); } } + if (lang_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 (values_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. */ @@ -691,6 +731,8 @@ You must use a pointer to function type variable. Command ignored."), arg_name); get_current_regcache (), bp_addr, nargs, args, sp, struct_return, struct_addr); + 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 @@ -882,7 +924,9 @@ the function call)."), name); { struct value *retval = NULL; - if (TYPE_CODE (values_type) == TYPE_CODE_VOID) + if (lang_struct_return) + retval = value_at (values_type, struct_addr); + else if (TYPE_CODE (target_values_type) == TYPE_CODE_VOID) { /* If the function returns void, don't bother fetching the return value. */ @@ -892,7 +936,7 @@ the function call)."), name); { struct gdbarch *arch = current_gdbarch; - switch (gdbarch_return_value (arch, values_type, NULL, NULL, NULL)) + switch (gdbarch_return_value (arch, target_values_type, NULL, NULL, NULL)) { case RETURN_VALUE_REGISTER_CONVENTION: case RETURN_VALUE_ABI_RETURNS_ADDRESS: diff --git a/gdb/jv-lang.c b/gdb/jv-lang.c index 3460184..d28df02 100644 --- a/gdb/jv-lang.c +++ b/gdb/jv-lang.c @@ -1115,6 +1115,7 @@ const struct language_defn java_language_defn = default_word_break_characters, c_language_arch_info, default_print_array_index, + default_pass_by_reference, LANG_MAGIC }; diff --git a/gdb/language.c b/gdb/language.c index 3cc513f..d5c6a94 100644 --- a/gdb/language.c +++ b/gdb/language.c @@ -1045,6 +1045,23 @@ language_class_name_from_physname (const struct language_defn *current_language, return NULL; } +/* Return non-zero if TYPE should be passed (and returned) by + reference at the language level. */ +int +language_pass_by_reference (struct type *type) +{ + return current_language->la_pass_by_reference (type); +} + +/* Return zero; by default, types are passed by value at the language + level. The target ABI may pass or return some structs by reference + independent of this. */ +int +default_pass_by_reference (struct type *type) +{ + return 0; +} + /* Return the default string containing the list of characters delimiting words. This is a reasonable default value that most languages should be able to use. */ @@ -1191,6 +1208,7 @@ const struct language_defn unknown_language_defn = default_word_break_characters, unknown_language_arch_info, /* la_language_arch_info. */ default_print_array_index, + default_pass_by_reference, LANG_MAGIC }; @@ -1228,6 +1246,7 @@ const struct language_defn auto_language_defn = default_word_break_characters, unknown_language_arch_info, /* la_language_arch_info. */ default_print_array_index, + default_pass_by_reference, LANG_MAGIC }; @@ -1264,6 +1283,7 @@ const struct language_defn local_language_defn = default_word_break_characters, unknown_language_arch_info, /* la_language_arch_info. */ default_print_array_index, + default_pass_by_reference, LANG_MAGIC }; diff --git a/gdb/language.h b/gdb/language.h index e6dc544..3649b00 100644 --- a/gdb/language.h +++ b/gdb/language.h @@ -280,6 +280,10 @@ struct language_defn int format, enum val_prettyprint pretty); + /* Return non-zero if TYPE should be passed (and returned) by + reference at the language level. */ + int (*la_pass_by_reference) (struct type *type); + /* Add fields above this point, so the magic number is always last. */ /* Magic number for compat checking */ @@ -471,4 +475,13 @@ extern void default_print_array_index (struct value *index_value, int format, enum val_prettyprint pretty); +/* Return non-zero if TYPE should be passed (and returned) by + reference at the language level. */ +int language_pass_by_reference (struct type *type); + +/* Return zero; by default, types are passed by value at the language + level. The target ABI may pass or return some structs by reference + independent of this. */ +int default_pass_by_reference (struct type *type); + #endif /* defined (LANGUAGE_H) */ diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c index a2014bb..128869c 100644 --- a/gdb/m2-lang.c +++ b/gdb/m2-lang.c @@ -459,6 +459,7 @@ const struct language_defn m2_language_defn = default_word_break_characters, m2_language_arch_info, default_print_array_index, + default_pass_by_reference, LANG_MAGIC }; diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c index ffe3d03..d1771d9 100644 --- a/gdb/objc-lang.c +++ b/gdb/objc-lang.c @@ -668,6 +668,7 @@ const struct language_defn objc_language_defn = { default_word_break_characters, c_language_arch_info, default_print_array_index, + default_pass_by_reference, LANG_MAGIC }; diff --git a/gdb/p-lang.c b/gdb/p-lang.c index e1a656d..ab204a1 100644 --- a/gdb/p-lang.c +++ b/gdb/p-lang.c @@ -525,6 +525,7 @@ const struct language_defn pascal_language_defn = default_word_break_characters, pascal_language_arch_info, default_print_array_index, + default_pass_by_reference, LANG_MAGIC }; diff --git a/gdb/scm-lang.c b/gdb/scm-lang.c index a6e5622..a8de4b0 100644 --- a/gdb/scm-lang.c +++ b/gdb/scm-lang.c @@ -267,6 +267,7 @@ const struct language_defn scm_language_defn = default_word_break_characters, c_language_arch_info, default_print_array_index, + default_pass_by_reference, LANG_MAGIC }; diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 8b30f8c..ae563f5 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2007-09-23 Daniel Jacobowitz + + * gdb.cp/pass-by-ref.cc, gdb.cp/pass-by-ref.exp: New files. + 2007-09-23 Pedro Alves * configure.ac: Do gdb.stabs tests by default on Cygwin and MinGW diff --git a/gdb/testsuite/gdb.cp/pass-by-ref.cc b/gdb/testsuite/gdb.cp/pass-by-ref.cc new file mode 100644 index 0000000..2a34b36 --- /dev/null +++ b/gdb/testsuite/gdb.cp/pass-by-ref.cc @@ -0,0 +1,79 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2007 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 3 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, see . */ + +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 () +{ + +} + +struct Derived : public Obj +{ + int other; +}; + +int blap (Derived arg) +{ + return foo (arg); +} + +struct Container +{ + Obj obj; +}; + +int blip (Container arg) +{ + return foo (arg.obj); +} + +Obj global_obj; +Derived global_derived; +Container global_container; + +int +main () +{ + int bar = foo (global_obj); + blap (global_derived); + blip (global_container); + return bar; +} diff --git a/gdb/testsuite/gdb.cp/pass-by-ref.exp b/gdb/testsuite/gdb.cp/pass-by-ref.exp new file mode 100644 index 0000000..f218c82 --- /dev/null +++ b/gdb/testsuite/gdb.cp/pass-by-ref.exp @@ -0,0 +1,41 @@ +# Copyright 2007 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 3 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, see . + +# Check that GDB can call C++ functions whose parameters have +# object type, but are passed by reference. + +if { [skip_cplus_tests] } { continue } + +set testfile "pass-by-ref" +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ + executable {debug c++}] != "" } { + untested pass-by-ref.exp + 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 in obj" +gdb_test "print blap (global_derived)" " = 3" "call function in derived" +gdb_test "print blip (global_container)" " = 3" "call function in container"