From: Andrew Burgess <aburgess@redhat.com>
To: Jan Vrany via Gdb-patches <gdb-patches@sourceware.org>,
gdb-patches@sourceware.org
Cc: Jan Vrany <jan.vrany@labware.com>
Subject: Re: [PATCH 2/2] gdb/python: implement support for sending custom MI async notifications
Date: Mon, 11 Sep 2023 15:21:40 +0100 [thread overview]
Message-ID: <87zg1skcy3.fsf@redhat.com> (raw)
In-Reply-To: <20230908210504.89194-2-jan.vrany@labware.com>
Jan Vrany via Gdb-patches <gdb-patches@sourceware.org> writes:
> This commit adds a new Python function, gdb.notify_mi, that can be used
> to emit custom async notification to MI channel. This can be used, among
> other things, to implement notifications about events MI does not support,
> such as remote connection closed or register change.
> ---
> gdb/NEWS | 3 ++
> gdb/doc/python.texi | 38 ++++++++++++++++++
> gdb/python/py-mi.c | 49 +++++++++++++++++++++++
> gdb/python/python-internal.h | 3 ++
> gdb/python/python.c | 4 ++
> gdb/testsuite/gdb.python/py-mi-notify.exp | 47 ++++++++++++++++++++++
> 6 files changed, 144 insertions(+)
> create mode 100644 gdb/testsuite/gdb.python/py-mi-notify.exp
>
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 98ff00d5efc..4a1f383a666 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -286,6 +286,9 @@ info main
> might be array- or string-like, even if they do not have the
> corresponding type code.
>
> + ** New function gdb.notify_mi(NAME, DATA), that emits custom
> + GDB/MI async notification.
> +
> *** Changes in GDB 13
>
> * MI version 1 is deprecated, and will be removed in GDB 14.
> diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
> index e9936991c49..cb2073976ba 100644
> --- a/gdb/doc/python.texi
> +++ b/gdb/doc/python.texi
> @@ -4704,6 +4704,44 @@ Here is how this works using the commands from the example above:
> @{'string': 'abc, def, ghi'@}
> @end smallexample
>
> +@node GDB/MI Notifications In Python
> +@subsubsection @sc{gdb/mi} Notifications In Python
> +
> +@cindex MI notifications in python
> +@cindex notifications in python, GDB/MI
> +@cindex python notifications, GDB/MI
> +
> +It is possible to emit @sc{gdb/mi} notifications from
> +Python. This is done with the @code{gdb.notify_mi} function.
> +
> +@defun gdb.notify_mi (name , data)
> +Emit a @sc{gdb/mi} asynchronous notification. @var{name} is the name of the
> +notification, a string. @var{data} are additional values emitted with the notification, passed
> +as Python dictionary. The dictionary is converted to converted
> +to a @sc{gdb/mi} @var{result-record} (@pxref{GDB/MI Output Syntax}) the same way
> +as result of Python MI command (@pxref{GDB/MI Commands In Python}).
> +
> +If @var{data} is @code{None} then no additional values are emitted.
> +@end defun
> +
> +Here is how to emit @code{=connection-removed} whenever a connection to remote
> +GDB server is closed (see @pxref{Connections In Python}):
> +
> +@smallexample
> +def notify_connection_removed (event):
> + data = @{ 'id' : event.connection.num,
> + 'type' : event.connection.type @}
> + gdb.notify_mi("connection-removed", data)
> +
> +gdb.events.connection_removed.connect (notify_connection_removed)
> +@end smallexample
> +
> +Then, each time a connection is closed, there will be a notification on MI channel:
> +
> +@smallexample
> +=connection-removed,id="1",type="remote"
> +@end smallexample
> +
> @node Parameters In Python
> @subsubsection Parameters In Python
>
> diff --git a/gdb/python/py-mi.c b/gdb/python/py-mi.c
> index 66dc6fb8a32..dc2ec5ddd0f 100644
> --- a/gdb/python/py-mi.c
> +++ b/gdb/python/py-mi.c
> @@ -19,8 +19,14 @@
>
> #include "defs.h"
> #include "python-internal.h"
> +#include "utils.h"
> +#include "ui.h"
> #include "ui-out.h"
> +#include "interps.h"
> +#include "target.h"
> #include "mi/mi-parse.h"
> +#include "mi/mi-console.h"
> +#include "mi/mi-interp.h"
>
> /* A ui_out subclass that creates a Python object based on the data
> that is passed in. */
> @@ -296,3 +302,46 @@ gdbpy_execute_mi_command (PyObject *self, PyObject *args, PyObject *kw)
>
> return uiout.result ();
> }
> +
> +/* Implementation of the gdb.notify_mi function. */
> +
> +PyObject *
> +gdbpy_notify_mi (PyObject *self, PyObject *args, PyObject *kwargs)
> +{
> + static const char *keywords[] = { "name", "data", nullptr };
> + const char *name;
> + PyObject *data;
> +
> + if (!gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "sO", keywords,
> + &name, &data))
> + return nullptr; // FIXME: is this the correct way to signal error?
I knew there was something else I wanted to say :)
I think you should add some validation of 'name' here too. If you check
patch 1/2 in this series and look for 'is_valid_key_name', you should do
something similar for 'name', and document the restrictions. e.g. I
don't think a name like " *** bad idea *** " would be a great choice
for a notification name.
Thanks,
Andrew
> +
> + SWITCH_THRU_ALL_UIS ()
> + {
> + struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +
> + if (mi == NULL)
> + continue;
> +
> + gdb_printf (mi->event_channel, "%s", name);
> + if (data != Py_None)
> + {
> + /* At the top-level, the data must be a dictionary. */
> + if (!PyDict_Check (data))
> + gdbpy_error (_("Data passed to notify_mi must be either None or a dictionary"));
> +
> + target_terminal::scoped_restore_terminal_state term_state;
> + target_terminal::ours_for_output ();
> +
> + ui_out *mi_uiout = mi->interp_ui_out ();
> + ui_out_redirect_pop redir (mi_uiout, mi->event_channel);
> + scoped_restore restore_uiout
> + = make_scoped_restore (¤t_uiout, mi_uiout);
> +
> + serialize_mi_data (data);
> + }
> + gdb_flush (mi->event_channel);
> + }
> +
> + Py_RETURN_NONE;
> +}
> diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
> index 3f53b0ab6f0..2a7e8d68179 100644
> --- a/gdb/python/python-internal.h
> +++ b/gdb/python/python-internal.h
> @@ -501,6 +501,9 @@ extern PyObject *gdbpy_execute_mi_command (PyObject *self, PyObject *args,
>
> extern void serialize_mi_data (PyObject *result);
>
> +extern PyObject *gdbpy_notify_mi (PyObject *self, PyObject *args,
> + PyObject *kw);
> +
> /* Convert Python object OBJ to a program_space pointer. OBJ must be a
> gdb.Progspace reference. Return nullptr if the gdb.Progspace is not
> valid (see gdb.Progspace.is_valid), otherwise return the program_space
> diff --git a/gdb/python/python.c b/gdb/python/python.c
> index 6a978d632e9..faa7e0c217d 100644
> --- a/gdb/python/python.c
> +++ b/gdb/python/python.c
> @@ -2669,6 +2669,10 @@ Return the name of the currently selected language." },
> "print_options () -> dict\n\
> Return the current print options." },
>
> + { "notify_mi", (PyCFunction) gdbpy_notify_mi,
> + METH_VARARGS | METH_KEYWORDS,
> + "notify_mi (name, data) -> None\n\
> +Output async record to MI channels if any." },
> {NULL, NULL, 0, NULL}
> };
>
> diff --git a/gdb/testsuite/gdb.python/py-mi-notify.exp b/gdb/testsuite/gdb.python/py-mi-notify.exp
> new file mode 100644
> index 00000000000..8221794c4f3
> --- /dev/null
> +++ b/gdb/testsuite/gdb.python/py-mi-notify.exp
> @@ -0,0 +1,47 @@
> +# Copyright (C) 2019-2023 Free Software Foundation, Inc.
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program. If not, see <http://www.gnu.org/licenses/>.
> +
> +# Test custom MI notifications implemented in Python.
> +
> +load_lib gdb-python.exp
> +load_lib mi-support.exp
> +set MIFLAGS "-i=mi"
> +
> +gdb_exit
> +if {[mi_gdb_start]} {
> + return
> +}
> +
> +if {[lsearch -exact [mi_get_features] python] < 0} {
> + unsupported "python support is disabled"
> + return -1
> +}
> +
> +standard_testfile
> +
> +mi_gdb_test "set python print-stack full" \
> + ".*\\^done" \
> + "set python print-stack full"
> +
> +mi_gdb_test "python gdb.notify_mi('test-notification', None)" \
> + ".*=test-notification\r\n\\^done" \
> + "python notification, no additional data"
> +
> +mi_gdb_test "python gdb.notify_mi('test-notification', \{ 'data1' : 1 , 'data2' : 2 })" \
> + ".*=test-notification,data1=\"1\",data2=\"2\"\r\n\\^done" \
> + "python notification, with additional data"
> +
> +mi_gdb_test "python gdb.notify_mi('test-notification', 1)" \
> + ".*\\^error,msg=\".*\"" \
> + "python notification, invalid additional data"
> --
> 2.40.1
next prev parent reply other threads:[~2023-09-11 14:21 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-09-08 21:05 [PATCH 1/2] gdb/python: generalize serialize_mi_result() Jan Vrany
2023-09-08 21:05 ` [PATCH 2/2] gdb/python: implement support for sending custom MI async notifications Jan Vrany
2023-09-09 6:39 ` Eli Zaretskii
2023-09-11 12:42 ` Andrew Burgess
2023-09-11 13:02 ` Jan Vraný
2023-09-11 13:43 ` Eli Zaretskii
2023-09-11 14:22 ` Andrew Burgess
2023-09-11 14:14 ` Andrew Burgess
2023-09-12 10:58 ` Jan Vraný
2023-09-12 13:07 ` Andrew Burgess
2023-09-12 13:45 ` Jan Vraný
2023-09-12 13:53 ` Andrew Burgess
2023-09-11 14:21 ` Andrew Burgess [this message]
2023-09-11 14:24 ` Jan Vraný
2023-09-11 14:18 ` [PATCH 1/2] gdb/python: generalize serialize_mi_result() Andrew Burgess
2023-09-12 16:35 ` Tom Tromey
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87zg1skcy3.fsf@redhat.com \
--to=aburgess@redhat.com \
--cc=gdb-patches@sourceware.org \
--cc=jan.vrany@labware.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).