From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 2182 invoked by alias); 18 Apr 2012 13:18:25 -0000 Received: (qmail 1498 invoked by uid 22791); 18 Apr 2012 13:18:19 -0000 X-SWARE-Spam-Status: No, hits=-2.9 required=5.0 tests=AWL,BAYES_00,FROM_12LTRDOM,KHOP_RCVD_UNTRUST,RCVD_IN_HOSTKARMA_W,RCVD_IN_HOSTKARMA_WL,SUBJ_OBFU_PUNCT_FEW,SUBJ_OBFU_PUNCT_MANY,TW_EG X-Spam-Check-By: sourceware.org Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 18 Apr 2012 13:17:38 +0000 Received: from svr-orw-fem-01.mgc.mentorg.com ([147.34.98.93]) by relay1.mentorg.com with esmtp id 1SKUlN-0007PS-1I from Yao_Qi@mentor.com for gdb-patches@sourceware.org; Wed, 18 Apr 2012 06:17:37 -0700 Received: from SVR-ORW-FEM-03.mgc.mentorg.com ([147.34.97.39]) by svr-orw-fem-01.mgc.mentorg.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.4675); Wed, 18 Apr 2012 06:17:36 -0700 Received: from localhost.localdomain (147.34.91.1) by svr-orw-fem-03.mgc.mentorg.com (147.34.97.39) with Microsoft SMTP Server id 14.1.289.1; Wed, 18 Apr 2012 06:17:35 -0700 From: Yao Qi To: CC: Subject: [PATCH 1/4] New gdb arch hook: return_with_first_hidden_param_p Date: Wed, 18 Apr 2012 13:28:00 -0000 Message-ID: <1334755073-26528-1-git-send-email-yao@codesourcery.com> MIME-Version: 1.0 Content-Type: text/plain X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2012-04/txt/msg00566.txt.bz2 Hi, this patch series is about fixing return values in C++ in GDB inf-call. In C++ ABI, section 3.1.4: "...if the return value type has a non-trivial copy constructor or destructor, the caller allocates space for a temporary, and passes a pointer to the temporary as an implicit first parameter preceding both the this parameter and user parameters. The callee constructs the return value into this temporary." Looks GDB is correct on handling C++ inf-call of return value (by checking language_pass_by_reference). Unfortunately, GCC is not correct here. currently GCC processes the return value RTL expanding like this, in gcc/function.c:assign_parms_augmented_arg_list(): /* If struct value address is treated as the first argument, make it so. */ if (aggregate_value_p (DECL_RESULT (fndecl), fndecl) && ! cfun->returns_pcc_struct && targetm.calls.struct_value_rtx (TREE_TYPE (fndecl), 1) == 0) { tree type = build_pointer_type (TREE_TYPE (fntype)); tree decl; ... The use of the TARGET_STRUCT_VALUE_RTX hook to determine whether to honor this convention, effectively makes what should be a language-dependent rule, into a target-dependent convention instead. The ia64 hook takes care to detect the C++ types to return NULL (which is referred to in the comments as an ABI bug resolved in G++ 3.4). Looking across other targets, sh, c6x, m68k, are examples of targets which always return non-NULL in their TARGET_STRUCT_VALUE_RTX hooks, and are exactly those that I also predicted and reproduced the same symptoms. C++ ABI is intended to be cross-architecture, but C++ ABI ends up being target-dependent at some points. In practice, GDB has to know which architecture is special. As I said above, GCC changes a language-dependent rule to a target-dependent rule 'by mistake', so GDB has to be aware of this. That is the motivation to create this new gdbarch hook. If the hook is not installed, the default version still complies to existing GDB's behavior, nothing is changed. gdb: 2012-04-16 Yao Qi Chung-Lin Tang * arch-utils.c (default_return_with_first_hidden_param_p): New. * arch-utils.h: Declare. * gdbarch.sh: Add return_with_first_hidden_param_p. * gdbarch.c, gdbarch.h: Regenerated. * infcall.c (call_function_by_hand): Call gdbarch_return_with_first_hidden_param_p instead of language_pass_by_reference. --- gdb/arch-utils.c | 8 ++++++++ gdb/arch-utils.h | 2 ++ gdb/gdbarch.c | 24 ++++++++++++++++++++++++ gdb/gdbarch.h | 9 +++++++++ gdb/gdbarch.sh | 6 ++++++ gdb/infcall.c | 12 ++++++------ 6 files changed, 55 insertions(+), 6 deletions(-) diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index fabb515..f68d211 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -31,6 +31,7 @@ #include "osabi.h" #include "target-descriptions.h" #include "objfiles.h" +#include "language.h" #include "version.h" @@ -805,6 +806,13 @@ default_target_signal_from_host (struct gdbarch *gdbarch, int signo) return target_signal_from_host (signo); } +int +default_return_with_first_hidden_param_p (struct gdbarch *gdbarch, + struct type *type) +{ + return language_pass_by_reference (type); +} + /* */ /* -Wmissing-prototypes */ diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h index c2c3398..15bd14d 100644 --- a/gdb/arch-utils.h +++ b/gdb/arch-utils.h @@ -177,4 +177,6 @@ extern enum target_signal default_target_signal_from_host (struct gdbarch *, extern int default_target_signal_to_host (struct gdbarch *, enum target_signal); +extern int default_return_with_first_hidden_param_p (struct gdbarch *, + struct type *); #endif diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index c079932..63ccecc 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -199,6 +199,7 @@ struct gdbarch gdbarch_address_to_pointer_ftype *address_to_pointer; gdbarch_integer_to_address_ftype *integer_to_address; gdbarch_return_value_ftype *return_value; + gdbarch_return_with_first_hidden_param_p_ftype *return_with_first_hidden_param_p; gdbarch_skip_prologue_ftype *skip_prologue; gdbarch_skip_main_prologue_ftype *skip_main_prologue; gdbarch_inner_than_ftype *inner_than; @@ -357,6 +358,7 @@ struct gdbarch startup_gdbarch = unsigned_address_to_pointer, /* address_to_pointer */ 0, /* integer_to_address */ 0, /* return_value */ + default_return_with_first_hidden_param_p, /* return_with_first_hidden_param_p */ 0, /* skip_prologue */ 0, /* skip_main_prologue */ 0, /* inner_than */ @@ -498,6 +500,7 @@ gdbarch_alloc (const struct gdbarch_info *info, gdbarch->value_from_register = default_value_from_register; gdbarch->pointer_to_address = unsigned_pointer_to_address; gdbarch->address_to_pointer = unsigned_address_to_pointer; + gdbarch->return_with_first_hidden_param_p = default_return_with_first_hidden_param_p; gdbarch->remote_breakpoint_from_pc = default_remote_breakpoint_from_pc; gdbarch->memory_insert_breakpoint = default_memory_insert_breakpoint; gdbarch->memory_remove_breakpoint = default_memory_remove_breakpoint; @@ -645,6 +648,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of address_to_pointer, invalid_p == 0 */ /* Skip verify of integer_to_address, has predicate. */ /* Skip verify of return_value, has predicate. */ + /* Skip verify of return_with_first_hidden_param_p, invalid_p == 0 */ if (gdbarch->skip_prologue == 0) fprintf_unfiltered (log, "\n\tskip_prologue"); /* Skip verify of skip_main_prologue, has predicate. */ @@ -1210,6 +1214,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) "gdbarch_dump: return_value = <%s>\n", host_address_to_string (gdbarch->return_value)); fprintf_unfiltered (file, + "gdbarch_dump: return_with_first_hidden_param_p = <%s>\n", + host_address_to_string (gdbarch->return_with_first_hidden_param_p)); + fprintf_unfiltered (file, "gdbarch_dump: sdb_reg_to_regnum = <%s>\n", host_address_to_string (gdbarch->sdb_reg_to_regnum)); fprintf_unfiltered (file, @@ -2486,6 +2493,23 @@ set_gdbarch_return_value (struct gdbarch *gdbarch, gdbarch->return_value = return_value; } +int +gdbarch_return_with_first_hidden_param_p (struct gdbarch *gdbarch, struct type *type) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->return_with_first_hidden_param_p != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_return_with_first_hidden_param_p called\n"); + return gdbarch->return_with_first_hidden_param_p (gdbarch, type); +} + +void +set_gdbarch_return_with_first_hidden_param_p (struct gdbarch *gdbarch, + gdbarch_return_with_first_hidden_param_p_ftype return_with_first_hidden_param_p) +{ + gdbarch->return_with_first_hidden_param_p = return_with_first_hidden_param_p; +} + CORE_ADDR gdbarch_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR ip) { diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 84e6ff8..663251c 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -450,6 +450,15 @@ typedef enum return_value_convention (gdbarch_return_value_ftype) (struct gdbarc extern enum return_value_convention gdbarch_return_value (struct gdbarch *gdbarch, struct type *functype, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf); extern void set_gdbarch_return_value (struct gdbarch *gdbarch, gdbarch_return_value_ftype *return_value); +/* Return true if the return value of function is stored in the first hidden parameter. + In theory, this feature should be language-dependent, specified by language and its ABI, + such as C++. Unfortunately, compiler may implement it to a target-dependent feature. + So that we need such hook here to be aware of this in GDB. */ + +typedef int (gdbarch_return_with_first_hidden_param_p_ftype) (struct gdbarch *gdbarch, struct type *type); +extern int gdbarch_return_with_first_hidden_param_p (struct gdbarch *gdbarch, struct type *type); +extern void set_gdbarch_return_with_first_hidden_param_p (struct gdbarch *gdbarch, gdbarch_return_with_first_hidden_param_p_ftype *return_with_first_hidden_param_p); + typedef CORE_ADDR (gdbarch_skip_prologue_ftype) (struct gdbarch *gdbarch, CORE_ADDR ip); extern CORE_ADDR gdbarch_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR ip); extern void set_gdbarch_skip_prologue (struct gdbarch *gdbarch, gdbarch_skip_prologue_ftype *skip_prologue); diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 5831172..ade7840 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -515,6 +515,12 @@ M:CORE_ADDR:integer_to_address:struct type *type, const gdb_byte *buf:type, buf # for instance). M:enum return_value_convention:return_value:struct type *functype, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf:functype, valtype, regcache, readbuf, writebuf +# Return true if the return value of function is stored in the first hidden parameter. +# In theory, this feature should be language-dependent, specified by language and its ABI, +# such as C++. Unfortunately, compiler may implement it to a target-dependent feature. +# So that we need such hook here to be aware of this in GDB. +m:int:return_with_first_hidden_param_p:struct type *type:type::default_return_with_first_hidden_param_p::0 + m:CORE_ADDR:skip_prologue:CORE_ADDR ip:ip:0:0 M:CORE_ADDR:skip_main_prologue:CORE_ADDR ip:ip f:int:inner_than:CORE_ADDR lhs, CORE_ADDR rhs:lhs, rhs:0:0 diff --git a/gdb/infcall.c b/gdb/infcall.c index 6c250e3..442965b 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -464,7 +464,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) { CORE_ADDR sp; struct type *values_type, *target_values_type; - unsigned char struct_return = 0, lang_struct_return = 0; + unsigned char struct_return = 0, hidden_first_param_p = 0; CORE_ADDR struct_addr = 0; struct infcall_control_state *inf_status; struct cleanup *inf_status_cleanup; @@ -598,9 +598,9 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) 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)) + if (gdbarch_return_with_first_hidden_param_p (gdbarch, values_type)) { - lang_struct_return = 1; + hidden_first_param_p = 1; /* Tell the target specific argument pushing routine not to expect a value. */ @@ -708,7 +708,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) stack, if necessary. Make certain that the value is correctly aligned. */ - if (struct_return || lang_struct_return) + if (struct_return || hidden_first_param_p) { int len = TYPE_LENGTH (values_type); @@ -734,7 +734,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) } } - if (lang_struct_return) + if (hidden_first_param_p) { struct value **new_args; @@ -1040,7 +1040,7 @@ When the function is done executing, GDB will silently stop."), /* Figure out the value returned by the function. */ retval = allocate_value (values_type); - if (lang_struct_return) + if (hidden_first_param_p) read_value_memory (retval, 0, 1, struct_addr, value_contents_raw (retval), TYPE_LENGTH (values_type)); -- 1.7.0.4