From patchwork Mon Dec 9 17:45:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Simon Marchi (Code Review)" X-Patchwork-Id: 36671 Received: (qmail 39233 invoked by alias); 9 Dec 2019 17:45:54 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 39181 invoked by uid 89); 9 Dec 2019 17:45:54 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-21.6 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3 autolearn=ham version=3.3.1 spammy=Reserve X-HELO: mx1.osci.io Received: from polly.osci.io (HELO mx1.osci.io) (8.43.85.229) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 09 Dec 2019 17:45:51 +0000 Received: by mx1.osci.io (Postfix, from userid 994) id 118942012A; Mon, 9 Dec 2019 12:45:50 -0500 (EST) Received: from gnutoolchain-gerrit.osci.io (gnutoolchain-gerrit.osci.io [8.43.85.239]) by mx1.osci.io (Postfix) with ESMTP id 232642012A; Mon, 9 Dec 2019 12:45:41 -0500 (EST) Received: from localhost (localhost [127.0.0.1]) by gnutoolchain-gerrit.osci.io (Postfix) with ESMTP id 07FAD28176; Mon, 9 Dec 2019 12:45:41 -0500 (EST) X-Gerrit-PatchSet: 2 Date: Mon, 9 Dec 2019 12:45:40 -0500 From: "Tankut Baris Aktemur (Code Review)" To: Tom Tromey , gdb-patches@sourceware.org Auto-Submitted: auto-generated X-Gerrit-MessageType: newpatchset Subject: [review v2] infcall: handle pass-by-reference arguments appropriately X-Gerrit-Change-Id: I18fa5d0df814dfa0defe9e862a88a6dbf1d99d01 X-Gerrit-Change-Number: 141 X-Gerrit-ChangeURL: X-Gerrit-Commit: d34b87d8d810644c4853ca8ed8cbd259bf605365 In-Reply-To: References: Reply-To: tankut.baris.aktemur@intel.com, tromey@sourceware.org, gdb-patches@sourceware.org MIME-Version: 1.0 Content-Disposition: inline User-Agent: Gerrit/3.0.3-79-g83ff7f88f1 Message-Id: <20191209174541.07FAD28176@gnutoolchain-gerrit.osci.io> Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/141 ...................................................................... infcall: handle pass-by-reference arguments appropriately If an aggregate argument is implicitly pass-by-reference, allocate a temporary object on the stack, initialize it via the copy constructor (if exists) or trivially by memcpy'ing. Pass the reference of the temporary to the callee function. After the callee returns, invoke the destructor of the temporary. gdb/ChangeLog: 2019-MM-DD Tankut Baris Aktemur PR gdb/25054 * infcall.c (call_function_by_hand_dummy): Update the argument- passing section for call-by-value parameters. (struct destructor_info): New struct. (call_destructors): New auxiliary function. Change-Id: I18fa5d0df814dfa0defe9e862a88a6dbf1d99d01 --- M gdb/infcall.c 1 file changed, 124 insertions(+), 3 deletions(-) diff --git a/gdb/infcall.c b/gdb/infcall.c index f3664d5..b6b617a 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -42,6 +42,7 @@ #include "thread-fsm.h" #include #include "gdbsupport/scope-exit.h" +#include /* If we can't find a function's name from its address, we print this instead. */ @@ -704,6 +705,33 @@ return addr; } +/* The data structure which keeps a destructor function and + its implicit 'this' parameter. */ + +struct destructor_info +{ + destructor_info (struct value *function, struct value *self) + : function (function), self (self) { } + + struct value *function; + struct value *self; +}; + + +/* Auxiliary function that takes a list of destructor functions + with their 'this' parameters, and invokes the functions. */ + +static void +call_destructors (const std::list &dtors_to_invoke, + struct type *default_return_type) +{ + for (auto vals : dtors_to_invoke) + { + call_function_by_hand (vals.function, default_return_type, + gdb::make_array_view (&(vals.self), 1)); + } +} + /* See infcall.h. */ struct value * @@ -983,6 +1011,12 @@ internal_error (__FILE__, __LINE__, _("bad switch")); } + /* Coerce the arguments and handle pass-by-reference. + We want to remember the destruction required for pass-by-ref values. + For these, store the dtor function and the 'this' argument + in DTORS_TO_INVOKE. */ + std::list dtors_to_invoke; + for (int i = args.size () - 1; i >= 0; i--) { int prototyped; @@ -1017,12 +1051,95 @@ else param_type = NULL; + value *original_arg = args[i]; args[i] = value_arg_coerce (gdbarch, args[i], param_type, prototyped); - if (param_type != NULL - && !(language_pass_by_reference (param_type).trivially_copyable)) - args[i] = value_addr (args[i]); + if (param_type == NULL) + continue; + + auto info = language_pass_by_reference (param_type); + if (!info.copy_constructible) + error (_("expression cannot be evaluated because the type '%s' " + "is not copy constructible"), TYPE_NAME (param_type)); + + if (!info.destructible) + error (_("expression cannot be evaluated because the type '%s' " + "is not destructible"), TYPE_NAME (param_type)); + + if (info.trivially_copyable) + continue; + + /* Make a copy of the argument on the stack. If the argument is + trivially copy ctor'able, copy bit by bit. Otherwise, call + the copy ctor to initialize the clone. */ + CORE_ADDR addr = reserve_stack_space (param_type, sp); + value *clone + = value_from_contents_and_address (param_type, nullptr, addr); + push_thread_stack_temporary (call_thread.get (), clone); + value *clone_ptr + = value_from_pointer (lookup_pointer_type (param_type), addr); + + if (info.trivially_copy_constructible) + { + int length = TYPE_LENGTH (param_type); + write_memory (addr, value_contents (args[i]), length); + } + else + { + value *copy_ctor; + value *cctor_args[2] = { clone_ptr, original_arg }; + find_overload_match (gdb::make_array_view (cctor_args, 2), + TYPE_NAME (param_type), METHOD, + &clone_ptr, nullptr, ©_ctor, nullptr, + nullptr, 0, EVAL_NORMAL); + + if (copy_ctor == nullptr) + error (_("expression cannot be evaluated because a copy " + "constructor for the type '%s' could not be found " + "(maybe inlined?)"), TYPE_NAME (param_type)); + + call_function_by_hand (copy_ctor, default_return_type, + gdb::make_array_view (cctor_args, 2)); + } + + /* If the argument has a destructor, remember it so that we + invoke it after the infcall is complete. */ + if (!info.trivially_destructible) + { + /* Looking up the function via overload resolution does not + work because the compiler (in particular, gcc) adds an + artificial int parameter in some cases. So we look up + the function by using the "~" name. This should be OK + because there can be only one dtor definition. */ + const char *dtor_name = nullptr; + for (int fieldnum = 0; + fieldnum < TYPE_NFN_FIELDS (param_type); + fieldnum++) + { + fn_field *fn + = TYPE_FN_FIELDLIST1 (param_type, fieldnum); + const char *field_name + = TYPE_FN_FIELDLIST_NAME (param_type, fieldnum); + + if (field_name[0] == '~') + dtor_name = TYPE_FN_FIELD_PHYSNAME (fn, 0); + } + + if (dtor_name == nullptr) + error (_("expression cannot be evaluated because a destructor " + "for the type '%s' could not be found " + "(maybe inlined?)"), TYPE_NAME (param_type)); + + value *dtor + = find_function_in_inferior (dtor_name, 0); + + /* Insert the dtor to the front of the list to call them + in reverse order later. */ + dtors_to_invoke.emplace_front (dtor, clone_ptr); + } + + args[i] = clone_ptr; } /* Reserve space for the return structure to be written on the @@ -1189,6 +1306,10 @@ maybe_remove_breakpoints (); gdb_assert (retval != NULL); + + /* Destruct the pass-by-ref argument clones. */ + call_destructors (dtors_to_invoke, default_return_type); + return retval; }