public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: "Jan Vraný" <Jan.Vrany@labware.com>
To: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>,
	"aburgess@redhat.com" <aburgess@redhat.com>
Subject: Re: [PATCH 2/2] gdb/python: implement support for sending custom MI async notifications
Date: Mon, 11 Sep 2023 14:24:23 +0000	[thread overview]
Message-ID: <2456368e0168790034d08225d20eaf3a222e970e.camel@labware.com> (raw)
In-Reply-To: <87zg1skcy3.fsf@redhat.com>

On Mon, 2023-09-11 at 15:21 +0100, Andrew Burgess wrote:
> 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.

Yes, that's exactly what I have added to (not yet submitted) V2. 

Thanks! Jan
> 
> 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 (&current_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


  reply	other threads:[~2023-09-11 14:24 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
2023-09-11 14:24     ` Jan Vraný [this message]
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=2456368e0168790034d08225d20eaf3a222e970e.camel@labware.com \
    --to=jan.vrany@labware.com \
    --cc=aburgess@redhat.com \
    --cc=gdb-patches@sourceware.org \
    /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).