From patchwork Thu May 30 13:48:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Vrany X-Patchwork-Id: 32917 Received: (qmail 39821 invoked by alias); 30 May 2019 13:49:21 -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 32734 invoked by uid 89); 30 May 2019 13:49:16 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_PASS autolearn=ham version=3.3.1 spammy=developing, interpreter X-HELO: relay.fit.cvut.cz Received: from relay.fit.cvut.cz (HELO relay.fit.cvut.cz) (147.32.232.237) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 30 May 2019 13:49:13 +0000 Received: from imap.fit.cvut.cz (imap.fit.cvut.cz [IPv6:2001:718:2:2901:0:0:0:238]) by relay.fit.cvut.cz (8.15.2/8.15.2) with ESMTPS id x4UDn8Yh039375 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 30 May 2019 15:49:10 +0200 (CEST) (envelope-from jan.vrany@fit.cvut.cz) Received: from localhost ([IPv6:2a02:c7d:2fcb:c700:6267:20ff:fee4:3e2c]) (authenticated bits=0 as user vranyj1) by imap.fit.cvut.cz (8.15.2/8.15.2) with ESMTPSA id x4UDn8Hl097748 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT); Thu, 30 May 2019 15:49:08 +0200 (CEST) (envelope-from jan.vrany@fit.cvut.cz) From: Jan Vrany To: gdb-patches@sourceware.org Cc: Jan Vrany Subject: [PATCH v3 4/5] mi/python: Allow redefinition of python MI commands Date: Thu, 30 May 2019 14:48:49 +0100 Message-Id: <20190530134850.3236-5-jan.vrany@fit.cvut.cz> In-Reply-To: <20190128124101.26243-1-jan.vrany@fit.cvut.cz> References: <20190128124101.26243-1-jan.vrany@fit.cvut.cz> MIME-Version: 1.0 Redefining python MI commands is especially useful when developing them. gdb/Changelog: * mi/mi-cmds.h (mi_command::can_be_redefined): New method. * mi/mi-cmds.c: (mi_command::can_be_redefined): New method. (insert_mi_cmd_entry): Allow redefinition of python-defined MI commands. * python/py-micmd.h (mi_command_py::can_be_redefined): New method. * python/py-micmd.c: (mi_command_py::can_be_redefined): New method. --- gdb/ChangeLog | 8 ++++++++ gdb/mi/mi-cmds.c | 10 +++++++++- gdb/mi/mi-cmds.h | 3 +++ gdb/python/py-micmd.c | 24 +++++++++++++++++------- gdb/python/py-micmd.h | 2 +- 5 files changed, 38 insertions(+), 9 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 241e5da68f..1d264c44f7 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,11 @@ +2019-05-02 Jan Vrany + + * mi/mi-cmds.h (mi_command::can_be_redefined): New method. + * mi/mi-cmds.c: (mi_command::can_be_redefined): New method. + (insert_mi_cmd_entry): Allow redefinition of python-defined MI commands. + * python/py-micmd.h (mi_command_py::can_be_redefined): New method. + * python/py-micmd.c: (mi_command_py::can_be_redefined): New method. + 2019-05-02 Didier Nadeau Jan Vrany diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c index 0aead954f9..e280e51daf 100644 --- a/gdb/mi/mi-cmds.c +++ b/gdb/mi/mi-cmds.c @@ -41,7 +41,8 @@ insert_mi_cmd_entry (mi_cmd_up command) const std::string &name = command->name (); if (mi_cmd_table.find (name) != mi_cmd_table.end ()) - return false; + if (! mi_cmd_table[name]->can_be_redefined ()) + return false; mi_cmd_table[name] = std::move (command); @@ -80,6 +81,13 @@ mi_command::mi_command (const char *name, int *suppress_notification) m_suppress_notification (suppress_notification) {} +bool +mi_command::can_be_redefined() +{ + return false; +} + + void mi_command::invoke (struct mi_parse *parse) diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h index 5ca7232fca..331b1349df 100644 --- a/gdb/mi/mi-cmds.h +++ b/gdb/mi/mi-cmds.h @@ -143,6 +143,9 @@ public: /* Execute the MI command. */ void invoke (struct mi_parse *parse); + /* Return TRUE if command can be redefined, FALSE otherwise. */ + virtual bool can_be_redefined(); + protected: gdb::optional> do_suppress_notification (); virtual void do_invoke(struct mi_parse *parse) = 0; diff --git a/gdb/python/py-micmd.c b/gdb/python/py-micmd.c index e99632c97a..4f2b13f3c7 100644 --- a/gdb/python/py-micmd.c +++ b/gdb/python/py-micmd.c @@ -171,6 +171,12 @@ mi_command_py::mi_command_py (const char *name, gdbpy_ref<> object) { } +bool +mi_command_py::can_be_redefined() +{ + return true; +} + void mi_command_py::do_invoke (struct mi_parse *parse) { @@ -179,6 +185,7 @@ mi_command_py::do_invoke (struct mi_parse *parse) if (parse->argv == NULL) error (_("Problem parsing arguments: %s %s"), parse->command, parse->args); + std::string name (this->name ()); PyObject *obj = this->pyobj.get (); gdbpy_enter enter_py (get_current_arch (), current_language); @@ -187,15 +194,14 @@ mi_command_py::do_invoke (struct mi_parse *parse) if (!PyObject_HasAttr (obj, invoke_cst)) error (_("-%s: Python command object missing 'invoke' method."), - name ().c_str ()); - + name.c_str ()); gdbpy_ref<> argobj (PyList_New (parse->argc)); if (argobj == nullptr) { gdbpy_print_stack (); error (_("-%s: failed to create the Python arguments list."), - name ().c_str ()); + name.c_str ()); } for (int i = 0; i < parse->argc; ++i) @@ -205,11 +211,16 @@ mi_command_py::do_invoke (struct mi_parse *parse) if (PyList_SetItem (argobj.get (), i, str.release ()) != 0) { error (_("-%s: failed to create the Python arguments list."), - name ().c_str ()); + name.c_str ()); } } gdb_assert (PyErr_Occurred () == NULL); + + /* From this point on, THIS must not be used since Python code may replace + the the very same command that is currently executing. This in turn leads + to desctruction of THIS making it invalid. See insert_mi_cmd_entry. */ + gdbpy_ref<> result ( PyObject_CallMethodObjArgs (obj, invoke_cst, argobj.get (), NULL)); if (PyErr_Occurred () != NULL) @@ -218,9 +229,9 @@ mi_command_py::do_invoke (struct mi_parse *parse) gdb::unique_xmalloc_ptr ex_msg (ex.to_string ()); if (ex_msg == NULL || *ex_msg == '\0') - error (_("-%s: failed to execute command"), name ().c_str ()); + error (_("-%s: failed to execute command"), name.c_str ()); else - error (_("-%s: %s"), name ().c_str (), ex_msg.get ()); + error (_("-%s: %s"), name.c_str (), ex_msg.get ()); } else { @@ -233,7 +244,6 @@ void mi_command_py::finalize () { this->pyobj.reset (nullptr); } - /* Initialize the MI command object. */ int diff --git a/gdb/python/py-micmd.h b/gdb/python/py-micmd.h index deadc0116b..0d61069ca5 100644 --- a/gdb/python/py-micmd.h +++ b/gdb/python/py-micmd.h @@ -44,7 +44,7 @@ class mi_command_py : public mi_command mi_command_py (const char *name, gdbpy_ref<> object); - + bool can_be_redefined() override; /* This is called just before shutting down a Python interpreter to release python object implementing the command. */