forked from Imagelibrary/binutils-gdb
gdb/python: implement support for sending custom MI async notifications
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. Reviewed-By: Eli Zaretskii <eliz@gnu.org> Approved-By: Andrew Burgess <aburgess@redhat.com>
This commit is contained in:
@@ -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. */
|
||||
@@ -455,3 +461,71 @@ serialize_mi_results (PyObject *results)
|
||||
serialize_mi_result_1 (value, key_string.get ());
|
||||
}
|
||||
}
|
||||
|
||||
/* See python-internal.h. */
|
||||
|
||||
PyObject *
|
||||
gdbpy_notify_mi (PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
static const char *keywords[] = { "name", "data", nullptr };
|
||||
char *name = nullptr;
|
||||
PyObject *data = Py_None;
|
||||
|
||||
if (!gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "s|O", keywords,
|
||||
&name, &data))
|
||||
return nullptr;
|
||||
|
||||
/* Validate notification name. */
|
||||
const int name_len = strlen (name);
|
||||
if (name_len == 0)
|
||||
{
|
||||
PyErr_SetString (PyExc_ValueError, _("MI notification name is empty."));
|
||||
return nullptr;
|
||||
}
|
||||
for (int i = 0; i < name_len; i++)
|
||||
{
|
||||
if (!isalnum (name[i]) && name[i] != '-')
|
||||
{
|
||||
PyErr_Format
|
||||
(PyExc_ValueError,
|
||||
_("MI notification name contains invalid character: %c."),
|
||||
name[i]);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Validate additional data. */
|
||||
if (!(data == Py_None || PyDict_Check (data)))
|
||||
{
|
||||
PyErr_Format
|
||||
(PyExc_ValueError,
|
||||
_("MI notification data must be either None or a dictionary, not %s"),
|
||||
Py_TYPE (data)->tp_name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SWITCH_THRU_ALL_UIS ()
|
||||
{
|
||||
struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
|
||||
|
||||
if (mi == nullptr)
|
||||
continue;
|
||||
|
||||
target_terminal::scoped_restore_terminal_state term_state;
|
||||
target_terminal::ours_for_output ();
|
||||
|
||||
gdb_printf (mi->event_channel, "%s", name);
|
||||
if (data != Py_None)
|
||||
{
|
||||
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_results (data);
|
||||
}
|
||||
gdb_flush (mi->event_channel);
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
@@ -499,6 +499,11 @@ extern PyObject *gdbpy_execute_mi_command (PyObject *self, PyObject *args,
|
||||
|
||||
extern void serialize_mi_results (PyObject *results);
|
||||
|
||||
/* Implementation of the gdb.notify_mi function. */
|
||||
|
||||
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
|
||||
|
||||
@@ -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}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user