From patchwork Tue May 14 11:24:17 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Vrany X-Patchwork-Id: 32674 Received: (qmail 113364 invoked by alias); 14 May 2019 11:57:11 -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 113356 invoked by uid 89); 14 May 2019 11:57:11 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-21.3 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_PASS autolearn=ham version=3.3.1 spammy= 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; Tue, 14 May 2019 11:57:10 +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 x4EBOc5T033262 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 14 May 2019 13:24:39 +0200 (CEST) (envelope-from jan.vrany@fit.cvut.cz) Received: from localhost (02791bac.bb.sky.com [2.121.27.172] (may be forged)) (authenticated bits=0 as user vranyj1) by imap.fit.cvut.cz (8.15.2/8.15.2) with ESMTPSA id x4EBObqq096957 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT); Tue, 14 May 2019 13:24:37 +0200 (CEST) (envelope-from jan.vrany@fit.cvut.cz) From: Jan Vrany To: gdb-patches@sourceware.org Cc: Jan Vrany Subject: [PATCH v2 4/5] mi/python: Allow redefinition of python MI commands Date: Tue, 14 May 2019 12:24:17 +0100 Message-Id: <20190514112418.24091-5-jan.vrany@fit.cvut.cz> In-Reply-To: <20190418152337.6376-1-jan.vrany@fit.cvut.cz> References: <20190418152337.6376-1-jan.vrany@fit.cvut.cz> MIME-Version: 1.0 Redefining python MI commands is especially useful when developing then. 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 | 34 +++++++++++++++++++++------------- gdb/python/py-micmd.h | 3 ++- 5 files changed, 43 insertions(+), 15 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4cbe97002b..0a5d95b4e3 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 7e1d2c3f2d..d7ac76d450 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 a2757bae20..dd2738f831 100644 --- a/gdb/mi/mi-cmds.h +++ b/gdb/mi/mi-cmds.h @@ -142,6 +142,9 @@ class mi_command /* 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 c8d429bb4b..994d715d02 100644 --- a/gdb/python/py-micmd.c +++ b/gdb/python/py-micmd.c @@ -158,17 +158,22 @@ mi_command_py::mi_command_py (const char *name, int *suppress_notification, { } -void -mi_command_py::invoke (struct mi_parse *parse) +bool +mi_command_py::can_be_redefined() { - std::unique_ptr> restore - = do_suppress_notification (); + return true; +} + +void +mi_command_py::do_invoke (struct mi_parse *parse) +{ mi_parse_argv (parse->args, 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 (); int i; @@ -176,20 +181,19 @@ mi_command_py::invoke (struct mi_parse *parse) if (!obj) error (_("-%s: invalid invocation of Python micommand object."), - name ().c_str ()); + name.c_str ()); 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 (i = 0; i < parse->argc; ++i) @@ -201,11 +205,16 @@ mi_command_py::invoke (struct mi_parse *parse) if (PyList_SetItem (argobj.get (), i, str) != 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) @@ -214,9 +223,9 @@ mi_command_py::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 if (result != nullptr) { @@ -228,7 +237,7 @@ mi_command_py::invoke (struct mi_parse *parse) error ( _("-%s: command invoke() method returned NULL but no python exception " "is set"), - name ().c_str ()); + name.c_str ()); } } @@ -236,7 +245,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 418de41a10..eaa5a6c47c 100644 --- a/gdb/python/py-micmd.h +++ b/gdb/python/py-micmd.h @@ -38,7 +38,7 @@ class mi_command_py : public mi_command public: mi_command_py (const char *name, int *suppress_notification, gdbpy_ref<> object); - void invoke (struct mi_parse *parse) override; + bool can_be_redefined() override; /* This is called just before shutting down a Python interpreter to release python object implementing the command */ @@ -46,6 +46,7 @@ public: private: gdbpy_ref<> pyobj; + virtual void do_invoke(struct mi_parse *parse) override; }; #endif