From patchwork Mon Jun 24 09:29:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Aktemur, Tankut Baris" X-Patchwork-Id: 33333 Received: (qmail 11223 invoked by alias); 24 Jun 2019 09:30:44 -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 10835 invoked by uid 89); 24 Jun 2019 09:30:37 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-21.1 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, H*r:LOCAL, UD:function X-HELO: mga14.intel.com Received: from mga14.intel.com (HELO mga14.intel.com) (192.55.52.115) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 24 Jun 2019 09:30:35 +0000 Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 24 Jun 2019 02:30:33 -0700 Received: from irvmail001.ir.intel.com ([163.33.26.43]) by orsmga006.jf.intel.com with ESMTP; 24 Jun 2019 02:30:32 -0700 Received: from ulvlx001.iul.intel.com (ulvlx001.iul.intel.com [172.28.207.17]) by irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id x5O9UVhw020944; Mon, 24 Jun 2019 10:30:31 +0100 Received: from ulvlx001.iul.intel.com (localhost [127.0.0.1]) by ulvlx001.iul.intel.com with ESMTP id x5O9UVjL022295; Mon, 24 Jun 2019 11:30:31 +0200 Received: (from taktemur@localhost) by ulvlx001.iul.intel.com with LOCAL id x5O9UVg0022291; Mon, 24 Jun 2019 11:30:31 +0200 From: Tankut Baris Aktemur To: gdb-patches@sourceware.org Cc: andrew.burgess@embecosm.com Subject: [PATCH v2 7/8] infcall: handle pass-by-reference arguments appropriately Date: Mon, 24 Jun 2019 11:29:47 +0200 Message-Id: <1561368588-21858-8-git-send-email-tankut.baris.aktemur@intel.com> In-Reply-To: <1561368588-21858-1-git-send-email-tankut.baris.aktemur@intel.com> References: <1561368588-21858-1-git-send-email-tankut.baris.aktemur@intel.com> X-IsSubscribed: yes 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 * infcall.c (call_function_by_hand_dummy): Update. (struct destructor_info): New struct. (call_destructors): New auxiliary function. 2019-06-24 Tankut Baris Aktemur --- gdb/infcall.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 3 deletions(-) diff --git a/gdb/infcall.c b/gdb/infcall.c index e81df995ff5..0c94d8a3d25 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -42,6 +42,7 @@ #include "thread-fsm.h" #include #include "common/scope-exit.h" +#include /* If we can't find a function's name from its address, we print this instead. */ @@ -704,6 +705,33 @@ reserve_stack_space (const type *values_type, CORE_ADDR &sp) 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 @@ call_function_by_hand_dummy (struct value *function, 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; @@ -1020,9 +1054,68 @@ call_function_by_hand_dummy (struct value *function, 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; + + /* This is a pass-by-ref value. Check for error cases before + pushing the temporary to the stack. */ + + if (!info.trivially_copy_constructible && info.cctor_name == NULL) + error (_("evaluation of this expression requires a copy constructor" + " for the type '%s'."), TYPE_NAME (param_type)); + + if (!info.trivially_destructible && info.dtor_name == NULL) + error (_("evaluation of this expression requires a destructor" + " for the type '%s'."), TYPE_NAME (param_type)); + + /* 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); + struct value *clone + = value_from_contents_and_address (param_type, NULL, addr); + push_thread_stack_temporary (call_thread.get (), clone); + struct 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 + { + struct value *copy_ctor + = find_function_in_inferior (info.cctor_name, 0); + struct value *cctor_args[2] = { clone_ptr, args[i] }; + 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) + { + struct value *dtor + = find_function_in_inferior (info.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 +1282,10 @@ call_function_by_hand_dummy (struct value *function, maybe_remove_breakpoints (); gdb_assert (retval != NULL); + + /* Destruct the pass-by-ref argument clones. */ + call_destructors (dtors_to_invoke, default_return_type); + return retval; }