Phil Muldoon
2010-08-13 14:54:24 UTC
Hi,
On the 23rd of August 2009 Oguz Kayral submitted an initial patch to
implement GDB inferior notification events in Python. Since then the
patch has bit-rotted somewhat. I've reconstituted this patch
against current GDB head and attached it. I've not changed very much:
renamed the files, re-ordered the Makefile.in and made some minor code
changes so that it compiles.
Why am I doing this?
Firstly as a historical context. Oguz's patches were a series of
patches and also emails containing code in-line and not in patch format.
This patch unifies this (though I left out the examples, as they
cannot belong in the CVS tree at the moment). I'll reconstitute the
ChangeLogs when we submit this code upstream. Secondly, I am planning
on working on this patch/code: improving, adding and eventually
submitting it upstream. As the patch that Oguz wrote is substantial
enough to give a general thrust of the design intentions I thought it
would be a good idea to re-spark any conversations before I work on
this code. So if there any ideas, let's here them!
Cheers
Phil
--
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 65eb1fe..33cccd9 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -272,7 +272,12 @@ SUBDIR_PYTHON_OBS = \
py-auto-load.o \
py-block.o \
py-breakpoint.o \
+ py-breakpointstopevent.o \
py-cmd.o \
+ py-continueevent.o \
+ py-event.o \
+ py-eventregistry.o \
+ py-exitedevent.o \
py-frame.o \
py-function.o \
py-inferior.o \
@@ -282,17 +287,25 @@ SUBDIR_PYTHON_OBS = \
py-param.o \
py-prettyprint.o \
py-progspace.o \
+ py-signalstopevent.o \
+ py-stopevent.o \
py-symbol.o \
py-symtab.o \
py-type.o \
py-utils.o \
py-value.o
+
SUBDIR_PYTHON_SRCS = \
python/python.c \
python/py-auto-load.c \
python/py-block.c \
python/py-breakpoint.c \
+ python/py-breakpointstopevent.c \
python/py-cmd.c \
+ python/py-continueevent.c \
+ python/py-event.c \
+ python/py-eventregistry.c \
+ python/py-exitedevent.c \
python/py-frame.c \
python/py-function.c \
python/py-inferior.c \
@@ -302,6 +315,8 @@ SUBDIR_PYTHON_SRCS = \
python/py-param.c \
python/py-prettyprint.c \
python/py-progspace.c \
+ python/py-signalstopevent.c \
+ python/py-stopevent.c \
python/py-symbol.c \
python/py-symtab.c \
python/py-type.c \
@@ -2010,10 +2025,30 @@ py-breakpoint.o: $(srcdir)/python/py-breakpoint.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpoint.c
$(POSTCOMPILE)
+py-breakpointstopevent.o: $(srcdir)/python/py-breakpointstopevent.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpointstopevent.c
+ $(POSTCOMPILE)
+
py-cmd.o: $(srcdir)/python/py-cmd.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-cmd.c
$(POSTCOMPILE)
+py-continueevent.o: $(srcdir)/python/py-continueevent.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-continueevent.c
+ $(POSTCOMPILE)
+
+py-event.o: $(srcdir)/python/py-event.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-event.c
+ $(POSTCOMPILE)
+
+py-eventregistry.o: $(srcdir)/python/py-eventregistry.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-eventregistry.c
+ $(POSTCOMPILE)
+
+py-exitedevent.o: $(srcdir)/python/py-exitedevent.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-exitedevent.c
+ $(POSTCOMPILE)
+
py-frame.o: $(srcdir)/python/py-frame.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-frame.c
$(POSTCOMPILE)
@@ -2050,6 +2085,14 @@ py-progspace.o: $(srcdir)/python/py-progspace.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-progspace.c
$(POSTCOMPILE)
+py-signalstopevent.o: $(srcdir)/python/py-signalstopevent.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-signalstopevent.c
+ $(POSTCOMPILE)
+
+py-stopevent.o: $(srcdir)/python/py-stopevent.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-stopevent.c
+ $(POSTCOMPILE)
+
py-symbol.o: $(srcdir)/python/py-symbol.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-symbol.c
$(POSTCOMPILE)
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 14f0417..d00048a 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -29,9 +29,6 @@
#include "cli/cli-script.h"
#include "ada-lang.h"
-/* From breakpoint.c. */
-typedef struct breakpoint_object breakpoint_object;
-
static PyTypeObject breakpoint_object_type;
/* A dynamically allocated vector of breakpoint objects. Each
@@ -52,18 +49,6 @@ static int bppy_live;
constructor and the breakpoint-created hook function. */
static breakpoint_object *bppy_pending_object;
-struct breakpoint_object
-{
- PyObject_HEAD
-
- /* The breakpoint number according to gdb. */
- int number;
-
- /* The gdb breakpoint object, or NULL if the breakpoint has been
- deleted. */
- struct breakpoint *bp;
-};
-
/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python
exception if it is invalid. */
#define BPPY_REQUIRE_VALID(Breakpoint) \
@@ -626,6 +611,34 @@ bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
return result;
}
+/* Function to get the corresponding breakpoint object for the given
+ bpstats. */
+
+breakpoint_object *
+gdbpy_breakpoint_from_bpstats (struct bpstats *bs)
+{
+ int i, out = 0;
+ breakpoint_object *breakpoint = NULL;
+
+ if (bppy_live == 0)
+ return NULL;
+
+ for (i = 0; out < bppy_live; i++)
+ {
+ if (! bppy_breakpoints[i])
+ continue;
+
+ if (bs->breakpoint_at == bppy_breakpoints[i]->bp->loc)
+ breakpoint = bppy_breakpoints[i];
+
+ ++out;
+ }
+
+ return breakpoint;
+}
+
+
+
/* Static function to return a tuple holding all breakpoints. */
diff --git a/gdb/python/py-breakpointstopevent.c b/gdb/python/py-breakpointstopevent.c
new file mode 100644
index 0000000..b63df7b
--- /dev/null
+++ b/gdb/python/py-breakpointstopevent.c
@@ -0,0 +1,166 @@
+/* Python interface to inferior breakpoint stop events.
+
+ Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+static PyTypeObject breakpoint_stop_event_object_type;
+
+typedef struct
+{
+ stop_event_object stop_event;
+ breakpoint_object *breakpoint;
+} breakpoint_stop_event_object;
+
+static void
+bp_stop_evpy_dealloc (PyObject *self)
+{
+ Py_DECREF (((breakpoint_stop_event_object *) self)->breakpoint);
+ self->ob_type->tp_free (self);
+}
+
+/* Python function to get the stop event's breakpoint. */
+static PyObject *
+bp_stop_evpy_get_breakpoint (PyObject *self, void *closure)
+{
+ breakpoint_stop_event_object *breakpoint_stop_event_obj =
+(breakpoint_stop_event_object *) self;
+
+ Py_INCREF (breakpoint_stop_event_obj->breakpoint);
+
+ return (PyObject *) (breakpoint_stop_event_obj->breakpoint);
+}
+
+breakpoint_stop_event_object *
+create_breakpoint_stop_event_object (breakpoint_object *bp)
+{
+ breakpoint_stop_event_object *breakpoint_stop_event_obj;
+
+ breakpoint_stop_event_obj = PyObject_New
+(breakpoint_stop_event_object, &breakpoint_stop_event_object_type);
+ if (!breakpoint_stop_event_obj)
+ return NULL;
+
+ breakpoint_stop_event_obj->stop_event.event.inferior_thread =
+find_thread_object (inferior_ptid);
+ Py_INCREF (breakpoint_stop_event_obj->stop_event.event.inferior_thread);
+ breakpoint_stop_event_obj->stop_event.event.event_type =
+(PyStringObject *) PyString_FromString ("stop");
+ breakpoint_stop_event_obj->stop_event.stop_reason = (PyStringObject
+*) PyString_FromString ("breakpoint");
+ breakpoint_stop_event_obj->breakpoint = bp;
+ Py_INCREF (breakpoint_stop_event_obj->breakpoint);
+
+ return breakpoint_stop_event_obj;
+}
+
+/* Initialize the Python breakpoint stop event code. */
+void
+gdbpy_initialize_breakpoint_stop_event (void)
+{
+ breakpoint_stop_event_object_type.tp_base = &stop_event_object_type;
+ if (PyType_Ready (&breakpoint_stop_event_object_type) < 0)
+ return;
+
+ Py_INCREF (&breakpoint_stop_event_object_type);
+ PyModule_AddObject (gdb_module, "BreakpointStopEvent", (PyObject *)
+&breakpoint_stop_event_object_type);
+}
+
+/* Callback that is used when a stop event occurs. This function will
+create a new Python breakpoint stop event object. */
+void
+emit_breakpoint_stop_event (struct bpstats *bs)
+{
+ thread_object *inferior_thread;
+ PyObject *callback_list;
+ PyObject *args_tuple;
+ Py_ssize_t i;
+ breakpoint_object *breakpoint;
+ breakpoint_stop_event_object *breakpoint_stop_event_obj;
+
+ inferior_thread = find_thread_object (inferior_ptid);
+
+ breakpoint = gdbpy_breakpoint_from_bpstats (bs);
+
+ breakpoint_stop_event_obj = create_breakpoint_stop_event_object (breakpoint);
+
+ callback_list = (PyObject *)
+(inferior_thread->breakpoint_stop_eventregistry->callbacks);
+
+ args_tuple = PyTuple_New ((Py_ssize_t) 1);
+ PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *)
+breakpoint_stop_event_obj);
+
+ for (i = 0; i < PyList_Size (callback_list); i++)
+ {
+ PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple);
+ }
+}
+
+static PyGetSetDef breakpoint_stop_event_object_getset[] =
+{
+ { "breakpoint", bp_stop_evpy_get_breakpoint, NULL, "Breakpoint.", NULL },
+
+ { NULL } /* Sentinel. */
+};
+
+static PyTypeObject breakpoint_stop_event_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /* ob_size */
+ "gdb.BreakpointStopEvent", /* tp_name */
+ sizeof (breakpoint_stop_event_object), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ bp_stop_evpy_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "GDB breakpoint stop event object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ breakpoint_stop_event_object_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0 /* tp_alloc */
+};
diff --git a/gdb/python/py-continueevent.c b/gdb/python/py-continueevent.c
new file mode 100644
index 0000000..f80d9ac
--- /dev/null
+++ b/gdb/python/py-continueevent.c
@@ -0,0 +1,138 @@
+/* Python interface to inferior continue events.
+
+ Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+static PyTypeObject continue_event_object_type;
+
+typedef struct
+{
+ event_object event;
+} continue_event_object;
+
+static void
+continue_evpy_dealloc (PyObject *self)
+{
+ self->ob_type->tp_free (self);
+}
+
+continue_event_object *
+create_continue_event_object ()
+{
+ continue_event_object *continue_event_obj;
+
+ continue_event_obj = PyObject_New (continue_event_object,
+&continue_event_object_type);
+
+ if (!continue_event_obj)
+ return NULL;
+
+ continue_event_obj->event.inferior_thread = find_thread_object
+(inferior_ptid);
+ Py_INCREF (continue_event_obj->event.inferior_thread);
+ continue_event_obj->event.event_type = (PyStringObject *)
+PyString_FromString ("continue");
+
+ return continue_event_obj;
+}
+
+/* Initialize the Python continue event code. */
+void
+gdbpy_initialize_continue_event (void)
+{
+ continue_event_object_type.tp_base = &event_object_type;
+ if (PyType_Ready (&continue_event_object_type) < 0)
+ return;
+
+ Py_INCREF (&continue_event_object_type);
+ PyModule_AddObject (gdb_module, "ContinueEvent", (PyObject *)
+&continue_event_object_type);
+}
+
+/* Callback that is used when a continue event occurs. This function
+ will create a new Python continue event object. */
+void
+emit_continue_event (ptid_t ptid)
+{
+ thread_object *inferior_thread;
+ PyObject *callback_list;
+ PyObject *args_tuple;
+ Py_ssize_t i;
+ continue_event_object *continue_event_obj;
+
+ inferior_thread = find_thread_object (inferior_ptid);
+
+ continue_event_obj = create_continue_event_object();
+
+ callback_list = (PyObject *)
+(inferior_thread->continue_eventregistry->callbacks);
+
+ args_tuple = PyTuple_New ((Py_ssize_t) 1);
+ PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *) continue_event_obj);
+
+ for (i = 0; i < PyList_Size (callback_list); i++)
+ {
+ PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple);
+ }
+}
+
+static PyTypeObject continue_event_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /* ob_size */
+ "gdb.ContinueEvent", /* tp_name */
+ sizeof (continue_event_object), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ continue_evpy_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "GDB continue event object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0 /* tp_alloc */
+};
diff --git a/gdb/python/py-event.c b/gdb/python/py-event.c
new file mode 100644
index 0000000..7394ded
--- /dev/null
+++ b/gdb/python/py-event.c
@@ -0,0 +1,130 @@
+/* Python interface to inferior events.
+
+ Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+event_object *
+create_event_object (const char *event_type)
+{
+ event_object *event_obj;
+
+ event_obj = PyObject_New (event_object, &event_object_type);
+ if (!event_obj)
+ return NULL;
+
+ event_obj->inferior_thread = find_thread_object (inferior_ptid);
+ Py_INCREF (event_obj->inferior_thread);
+ event_obj->event_type = (PyStringObject *) PyString_FromString (event_type);
+
+ return event_obj;
+}
+
+static void
+evpy_dealloc (PyObject *self)
+{
+ Py_DECREF (((event_object *) self)->inferior_thread);
+ self->ob_type->tp_free (self);
+}
+
+/* Python function to get the event's thread. */
+static PyObject *
+evpy_get_inferior_thread (PyObject *self, void *closure)
+{
+ event_object *event_obj = (event_object *) self;
+
+ Py_INCREF (event_obj->inferior_thread);
+
+ return (PyObject *) (event_obj->inferior_thread);
+}
+
+/* Python function to get the event's type. */
+static PyObject *
+evpy_get_event_type (PyObject *self, void *closure)
+{
+ event_object *event_obj = (event_object *) self;
+
+ Py_INCREF (event_obj->event_type);
+
+ return (PyObject *) (event_obj->event_type);
+}
+
+/* Initialize the Python event code. */
+void
+gdbpy_initialize_event (void)
+{
+ if (PyType_Ready (&event_object_type) < 0)
+ return;
+
+ Py_INCREF (&event_object_type);
+ PyModule_AddObject (gdb_module, "Event", (PyObject *) &event_object_type);
+}
+
+static PyGetSetDef event_object_getset[] =
+{
+ { "inferior_thread", evpy_get_inferior_thread, NULL,
+ "Inferior thread.", NULL },
+ { "event_type", evpy_get_event_type, NULL, "Event type.", NULL },
+
+ { NULL } /* Sentinel. */
+};
+
+PyTypeObject event_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /* ob_size */
+ "gdb.Event", /* tp_name */
+ sizeof (event_object), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ evpy_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ "GDB event object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ event_object_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0 /* tp_alloc */
+};
diff --git a/gdb/python/py-eventregistry.c b/gdb/python/py-eventregistry.c
new file mode 100644
index 0000000..c1aa7b4
--- /dev/null
+++ b/gdb/python/py-eventregistry.c
@@ -0,0 +1,155 @@
+/* Python interface to inferior thread event registries.
+
+ Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "command.h"
+#include "python-internal.h"
+
+static PyTypeObject eventregistry_object_type;
+
+/* Implementation of EventRegistry.connect () -> NULL */
+static PyObject *
+evregpy_connect (PyObject *self, PyObject *function)
+{
+ PyObject *func;
+ PyObject *callback_list = (PyObject *) (((eventregistry_object *)
+self)->callbacks);
+
+ if (!PyArg_ParseTuple (function, "O", &func))
+ return NULL;
+
+ if (!PyCallable_Check (func))
+ {
+ PyErr_SetString (PyExc_RuntimeError, "Function is not callable");
+ return NULL;
+ }
+
+ Py_INCREF (func);
+
+ PyList_Append (callback_list, func);
+
+ Py_RETURN_NONE;
+}
+
+/* Implementation of EventRegistry.disconnect () -> NULL */
+static PyObject *
+evregpy_disconnect (PyObject *self, PyObject *function)
+{
+ PyObject *func;
+ PyObject *callback_list = (PyObject *) (((eventregistry_object *)
+self)->callbacks);
+
+ if (!PyArg_ParseTuple (function, "O", &func))
+ return NULL;
+
+ if (!PyCallable_Check (func))
+ {
+ PyErr_SetString (PyExc_RuntimeError, "Function is not callable");
+ return NULL;
+ }
+
+ Py_INCREF (func);
+
+ PySequence_DelItem (callback_list, PySequence_Index (callback_list, func));
+
+ Py_RETURN_NONE;
+}
+
+eventregistry_object *
+create_eventregistry_object (void)
+{
+ eventregistry_object *eventregistry_obj;
+
+ eventregistry_obj = PyObject_New (eventregistry_object,
+&eventregistry_object_type);
+ if (!eventregistry_obj)
+ return NULL;
+
+ eventregistry_obj->callbacks = (PyListObject *) PyList_New (0);
+
+ return eventregistry_obj;
+}
+
+static void
+evregpy_dealloc (PyObject *self)
+{
+ Py_DECREF (((eventregistry_object *) self)->callbacks);
+ self->ob_type->tp_free (self);
+}
+
+/* Initialize the Python event registry code. */
+void
+gdbpy_initialize_eventregistry (void)
+{
+ if (PyType_Ready (&eventregistry_object_type) < 0)
+ return;
+
+ Py_INCREF (&eventregistry_object_type);
+ PyModule_AddObject (gdb_module, "EventRegistry", (PyObject *)
+&eventregistry_object_type);
+}
+
+static PyMethodDef eventregistry_object_methods[] =
+{
+ { "connect", evregpy_connect, METH_VARARGS, "Add function" },
+ { "disconnect", evregpy_disconnect, METH_VARARGS, "Remove function" },
+ { NULL } /* Sentinel. */
+};
+
+static PyTypeObject eventregistry_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /* ob_size */
+ "gdb.EventRegistry", /* tp_name */
+ sizeof (eventregistry_object), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ evregpy_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "GDB event registry object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ eventregistry_object_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0 /* tp_alloc */
+};
diff --git a/gdb/python/py-exitedevent.c b/gdb/python/py-exitedevent.c
new file mode 100644
index 0000000..d2a1d88
--- /dev/null
+++ b/gdb/python/py-exitedevent.c
@@ -0,0 +1,156 @@
+/* Python interface to inferior exit events.
+
+ Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+static PyTypeObject exited_event_object_type;
+
+typedef struct
+{
+ event_object event;
+ PyLongObject *exit_code;
+} exited_event_object;
+
+static void
+exit_evpy_dealloc (PyObject *self)
+{
+ Py_DECREF (((exited_event_object *) self)->exit_code);
+ self->ob_type->tp_free (self);
+}
+
+/* Python function to get the exited event's exit code. */
+static PyObject *
+exit_evpy_get_exit_code (PyObject *self, void *closure)
+{
+ exited_event_object *exited_event_obj = (exited_event_object *) self;
+
+ Py_INCREF (exited_event_obj->exit_code);
+
+ return (PyObject *) (exited_event_obj->exit_code);
+}
+
+exited_event_object *
+create_exited_event_object (thread_object *inferior_thread, long long
+int *exit_code)
+{
+ exited_event_object *exited_event_obj;
+
+ exited_event_obj = PyObject_New (exited_event_object,
+&exited_event_object_type);
+
+ if (!exited_event_obj)
+ return NULL;
+
+ exited_event_obj->event.inferior_thread = inferior_thread;
+ Py_INCREF (exited_event_obj->event.inferior_thread);
+ exited_event_obj->event.event_type = (PyStringObject *)
+PyString_FromString ("exit");
+ exited_event_obj->exit_code = (PyLongObject *) PyLong_FromLongLong
+(*exit_code);
+
+ return exited_event_obj;
+}
+
+/* Initialize the Python exited event code. */
+void gdbpy_initialize_exited_event (void)
+{
+ exited_event_object_type.tp_base = &event_object_type;
+ if (PyType_Ready (&exited_event_object_type) < 0)
+ return;
+
+ Py_INCREF (&exited_event_object_type);
+ PyModule_AddObject (gdb_module, "ExitedEvent", (PyObject *)
+&exited_event_object_type);
+}
+
+/* Callback that is used when an exit event occurs. This function
+ will create a new Python exited event object. */
+void
+emit_exited_event (thread_object *inferior_thread, long long int *exit_code)
+{
+ PyObject *callback_list;
+ PyObject *args_tuple;
+ Py_ssize_t i;
+ exited_event_object *exited_event_obj;
+
+ exited_event_obj = create_exited_event_object (inferior_thread, exit_code);
+
+ callback_list = (PyObject *)
+(inferior_thread->exited_eventregistry->callbacks);
+
+ args_tuple = PyTuple_New ((Py_ssize_t) 1);
+ PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *) exited_event_obj);
+
+ for (i = 0; i < PyList_Size (callback_list); i++)
+ {
+ PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple);
+ }
+}
+
+static PyGetSetDef exited_event_object_getset[] =
+{
+ { "exit_code", exit_evpy_get_exit_code, NULL, "Exit code.", NULL },
+
+ { NULL } /* Sentinel. */
+};
+
+static PyTypeObject exited_event_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /* ob_size */
+ "gdb.ExitedEvent", /* tp_name */
+ sizeof (exited_event_object), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ exit_evpy_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "GDB exited event object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ exited_event_object_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0 /* tp_alloc */
+};
diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c
index 3a0feab..9e182c4 100644
--- a/gdb/python/py-inferior.c
+++ b/gdb/python/py-inferior.c
@@ -26,6 +26,7 @@
#include "python-internal.h"
#include "arch-utils.h"
#include "language.h"
+#include "gdb_signals.h"
struct threadlist_entry {
thread_object *thread_obj;
@@ -73,6 +74,72 @@ static PyTypeObject membuf_object_type;
} \
} while (0)
+static void
+python_on_normal_stop (struct bpstats *bs, int print_frame)
+{
+ PyGILState_STATE state;
+ char *stop_signal;
+
+ if (!find_thread_ptid (inferior_ptid))
+ return;
+
+ stop_signal = (char *) target_signal_to_name (inferior_thread()->stop_signal);
+
+ state = PyGILState_Ensure ();
+
+ emit_stop_event (bs, stop_signal);
+
+ PyGILState_Release (state);
+}
+
+static void
+python_on_resume (ptid_t ptid)
+{
+ PyGILState_STATE state;
+
+ state = PyGILState_Ensure ();
+
+ emit_continue_event (ptid);
+
+ PyGILState_Release (state);
+}
+
+static void
+python_thread_exit (struct thread_info *tp, int ignore)
+{
+ PyGILState_STATE state;
+ LONGEST exitcode_val;
+ long long int *exit_code;
+ inferior_object *inf_obj;
+ thread_object *thread_obj;
+ struct threadlist_entry **entry;
+
+ inf_obj = (inferior_object *) find_inferior_object (PIDGET(tp->ptid));
+ if (!inf_obj)
+ return;
+
+ /* Find thread entry in its inferior's thread_list. */
+ for (entry = &inf_obj->threads; *entry != NULL; entry = &(*entry)->next)
+ if ((*entry)->thread_obj->thread == tp)
+ break;
+
+ if (!*entry)
+ return;
+
+ thread_obj = (*entry)->thread_obj;
+
+ state = PyGILState_Ensure ();
+
+ if (get_internalvar_integer (lookup_internalvar ("_exitcode"), &exitcode_val))
+ exit_code = (long long int *) &exitcode_val;
+
+ if (exit_code)
+ emit_exited_event (thread_obj, exit_code);
+
+ PyGILState_Release (state);
+}
+
+
/* Return a borrowed reference to the Python object of type Inferior
representing INFERIOR. If the object has already been created,
return it, otherwise, create it. Return NULL on failure. */
@@ -589,6 +656,9 @@ gdbpy_initialize_inferior (void)
observer_attach_new_thread (add_thread_object);
observer_attach_thread_exit (delete_thread_object);
+ observer_attach_normal_stop (python_on_normal_stop);
+ observer_attach_target_resumed (python_on_resume);
+ observer_attach_thread_exit (python_thread_exit);
if (PyType_Ready (&membuf_object_type) < 0)
return;
diff --git a/gdb/python/py-infthread.c b/gdb/python/py-infthread.c
index 86aba50..d3f448c 100644
--- a/gdb/python/py-infthread.c
+++ b/gdb/python/py-infthread.c
@@ -51,6 +51,12 @@ create_thread_object (struct thread_info *tp)
thread_obj->inf_obj = find_inferior_object (PIDGET (tp->ptid));
Py_INCREF (thread_obj->inf_obj);
+ thread_obj->stop_eventregistry = create_eventregistry_object ();
+ thread_obj->breakpoint_stop_eventregistry = create_eventregistry_object ();
+ thread_obj->signal_stop_eventregistry = create_eventregistry_object ();
+ thread_obj->continue_eventregistry = create_eventregistry_object ();
+ thread_obj->exited_eventregistry = create_eventregistry_object ();
+
return thread_obj;
}
static void
thpy_dealloc (PyObject *self)
{
Py_DECREF (((thread_object *) self)->inf_obj);
+ Py_DECREF (((thread_object *) self)->stop_eventregistry);
+ Py_DECREF (((thread_object *) self)->breakpoint_stop_eventregistry);
+ Py_DECREF (((thread_object *) self)->signal_stop_eventregistry);
+ Py_DECREF (((thread_object *) self)->continue_eventregistry);
+ Py_DECREF (((thread_object *) self)->exited_eventregistry);
+
self->ob_type->tp_free (self);
}
static PyObject *
+thpy_get_stop_eventregistry (PyObject *self, void *closure)
+{
+ thread_object *thread_obj = (thread_object *) self;
+
+ THPY_REQUIRE_VALID (thread_obj);
+
+ Py_INCREF (thread_obj->stop_eventregistry);
+
+ return (PyObject *) (thread_obj->stop_eventregistry);
+}
+
+static PyObject *
+thpy_get_breakpoint_stop_eventregistry (PyObject *self, void *closure)
+{
+ thread_object *thread_obj = (thread_object *) self;
+
+ THPY_REQUIRE_VALID (thread_obj);
+
+ Py_INCREF (thread_obj->breakpoint_stop_eventregistry);
+
+ return (PyObject *) (thread_obj->breakpoint_stop_eventregistry);
+}
+
+static PyObject *
+thpy_get_signal_stop_eventregistry (PyObject *self, void *closure)
+{
+ thread_object *thread_obj = (thread_object *) self;
+
+ THPY_REQUIRE_VALID (thread_obj);
+
+ Py_INCREF (thread_obj->signal_stop_eventregistry);
+
+ return (PyObject *) (thread_obj->signal_stop_eventregistry);
+}
+
+static PyObject *
+thpy_get_continue_eventregistry (PyObject *self, void *closure)
+{
+ thread_object *thread_obj = (thread_object *) self;
+
+ THPY_REQUIRE_VALID (thread_obj);
+
+ Py_INCREF (thread_obj->continue_eventregistry);
+
+ return (PyObject *) (thread_obj->continue_eventregistry);
+}
+
+static PyObject *
+thpy_get_exited_eventregistry (PyObject *self, void *closure)
+{
+ thread_object *thread_obj = (thread_object *) self;
+
+ THPY_REQUIRE_VALID (thread_obj);
+
+ Py_INCREF (thread_obj->exited_eventregistry);
+
+ return (PyObject *) (thread_obj->exited_eventregistry);
+}
+
+static PyObject *
thpy_get_num (PyObject *self, void *closure)
{
thread_object *thread_obj = (thread_object *) self;
@@ -204,6 +274,17 @@ static PyGetSetDef thread_object_getset[] =
{ "num", thpy_get_num, NULL, "ID of the thread, as assigned by GDB.", NULL },
{ "ptid", thpy_get_ptid, NULL, "ID of the thread, as assigned by the OS.",
NULL },
+ { "stop_eventregistry", thpy_get_stop_eventregistry, NULL,
+ "Stop event registry object of the thread.", NULL },
+ { "breakpoint_stop_eventregistry",
+ thpy_get_breakpoint_stop_eventregistry, NULL,
+ "Breakpoint stop event registry object of the thread.", NULL },
+ { "signal_stop_eventregistry", thpy_get_signal_stop_eventregistry,
+ NULL, "Signal stop event registry object of the thread.", NULL },
+ { "continue_eventregistry", thpy_get_continue_eventregistry, NULL,
+ "Continue event registry object of the thread.", NULL },
+ { "exited_eventregistry", thpy_get_exited_eventregistry, NULL,
+ "Exited event registry object of the thread.", NULL },
{ NULL }
};
diff --git a/gdb/python/py-signalstopevent.c b/gdb/python/py-signalstopevent.c
new file mode 100644
index 0000000..5ab8af7
--- /dev/null
+++ b/gdb/python/py-signalstopevent.c
@@ -0,0 +1,163 @@
+/* Python interface to inferior signal stop events.
+
+ Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+static PyTypeObject signal_stop_event_object_type;
+
+typedef struct
+{
+ stop_event_object stop_event;
+ PyStringObject *stop_signal;
+} signal_stop_event_object;
+
+static void
+sig_stop_evpy_dealloc (PyObject *self)
+{
+ Py_DECREF (((signal_stop_event_object *) self)->stop_signal);
+ self->ob_type->tp_free (self);
+}
+
+/* Python function to get the stop event's stop signal. */
+static PyObject *
+sig_stop_evpy_get_stop_signal (PyObject *self, void *closure)
+{
+ signal_stop_event_object *signal_stop_event_obj =
+(signal_stop_event_object *) self;
+
+ Py_INCREF (signal_stop_event_obj->stop_signal);
+
+ return (PyObject *) (signal_stop_event_obj->stop_signal);
+}
+
+signal_stop_event_object *
+create_signal_stop_event_object (const char *stop_signal)
+{
+ signal_stop_event_object *signal_stop_event_obj;
+
+ signal_stop_event_obj = PyObject_New (signal_stop_event_object,
+&signal_stop_event_object_type);
+ if (!signal_stop_event_obj)
+ return NULL;
+
+ signal_stop_event_obj->stop_event.event.inferior_thread =
+find_thread_object (inferior_ptid);
+ Py_INCREF (signal_stop_event_obj->stop_event.event.inferior_thread);
+ signal_stop_event_obj->stop_event.event.event_type = (PyStringObject
+*) PyString_FromString ("stop");
+ signal_stop_event_obj->stop_event.stop_reason = (PyStringObject *)
+PyString_FromString ("signal");
+ signal_stop_event_obj->stop_signal = (PyStringObject *)
+PyString_FromString (stop_signal);
+
+ return signal_stop_event_obj;
+}
+
+/* Initialize the Python stop event code. */
+void
+gdbpy_initialize_signal_stop_event (void)
+{
+ signal_stop_event_object_type.tp_base = &stop_event_object_type;
+ if (PyType_Ready (&signal_stop_event_object_type) < 0)
+ return;
+
+ Py_INCREF (&signal_stop_event_object_type);
+ PyModule_AddObject (gdb_module, "SignalStopEvent", (PyObject *)
+&signal_stop_event_object_type);
+}
+
+/* Callback that is used when a signal stop event occurs. This function
+ will create a new Python signal stop event object. */
+void
+emit_signal_stop_event (const char *stop_signal)
+{
+ thread_object *inferior_thread;
+ PyObject *callback_list;
+ PyObject *args_tuple;
+ Py_ssize_t i;
+ signal_stop_event_object *signal_stop_event_obj;
+
+ inferior_thread = find_thread_object (inferior_ptid);
+
+ signal_stop_event_obj = create_signal_stop_event_object (stop_signal);
+
+ callback_list = (PyObject *)
+(inferior_thread->signal_stop_eventregistry->callbacks);
+
+ args_tuple = PyTuple_New ((Py_ssize_t) 1);
+ PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *)
+signal_stop_event_obj);
+
+ for (i = 0; i < PyList_Size (callback_list); i++)
+ {
+ PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple);
+ }
+}
+
+static PyGetSetDef signal_stop_event_object_getset[] =
+{
+ { "stop_signal", sig_stop_evpy_get_stop_signal, NULL, "Stop signal.", NULL },
+
+ { NULL } /* Sentinel. */
+};
+
+static PyTypeObject signal_stop_event_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /* ob_size */
+ "gdb.SignalStopEvent", /* tp_name */
+ sizeof (signal_stop_event_object), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ sig_stop_evpy_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "GDB signal stop event object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ signal_stop_event_object_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0 /* tp_alloc */
+};
diff --git a/gdb/python/py-stopevent.c b/gdb/python/py-stopevent.c
new file mode 100644
index 0000000..069e441
--- /dev/null
+++ b/gdb/python/py-stopevent.c
@@ -0,0 +1,164 @@
+/* Python interface to inferior stop events.
+
+ Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+static void
+stop_evpy_dealloc (PyObject *self)
+{
+ Py_DECREF (((stop_event_object *) self)->stop_reason);
+ self->ob_type->tp_free (self);
+}
+
+/* Python function to get the stop event's stop reason. */
+static PyObject *
+stop_evpy_get_stop_reason (PyObject *self, void *closure)
+{
+ stop_event_object *stop_event_obj = (stop_event_object *) self;
+
+ Py_INCREF (stop_event_obj->stop_reason);
+
+ return (PyObject *) (stop_event_obj->stop_reason);
+}
+
+stop_event_object *
+create_stop_event_object (const char *stop_reason)
+{
+ stop_event_object *stop_event_obj;
+
+ stop_event_obj = PyObject_New (stop_event_object, &stop_event_object_type);
+ if (!stop_event_obj)
+ return NULL;
+
+ stop_event_obj->event.inferior_thread = find_thread_object (inferior_ptid);
+ Py_INCREF (stop_event_obj->event.inferior_thread);
+ stop_event_obj->event.event_type = (PyStringObject *)
+PyString_FromString ("stop");
+ stop_event_obj->stop_reason = (PyStringObject *) PyString_FromString
+(stop_reason);
+
+ return stop_event_obj;
+}
+
+/* Initialize the Python stop event code. */
+void
+gdbpy_initialize_stop_event (void)
+{
+ stop_event_object_type.tp_base = &event_object_type;
+ if (PyType_Ready (&stop_event_object_type) < 0)
+ return;
+
+ Py_INCREF (&stop_event_object_type);
+ PyModule_AddObject (gdb_module, "StopEvent", (PyObject *)
+&stop_event_object_type);
+}
+
+/* Callback that is used when a stop event occurs. This function
+ will create a new Python stop event object. */
+void
+emit_stop_event (struct bpstats *bs, const char *stop_signal)
+{
+ thread_object *inferior_thread;
+ PyObject *callback_list;
+ PyObject *args_tuple;
+ Py_ssize_t i;
+ stop_event_object *stop_event_obj = NULL; /* Appease GCC warning. */
+
+ inferior_thread = find_thread_object (inferior_ptid);
+
+ if (bs)
+ {
+ stop_event_obj = create_stop_event_object ("breakpoint");
+ emit_breakpoint_stop_event (bs);
+ }
+
+ /* Check if the signal is "Signal 0" or "Trace/breakpoint trap". */
+ if ((strcmp (stop_signal, "0") != 0) && (strcmp (stop_signal,
+"SIGTRAP") != 0))
+ {
+ stop_event_obj = create_stop_event_object ("signal");
+ emit_signal_stop_event (stop_signal);
+ }
+
+ if (!stop_event_obj)
+ stop_event_obj = create_stop_event_object ("unknown");
+
+ callback_list = (PyObject *) (inferior_thread->stop_eventregistry->callbacks);
+
+ args_tuple = PyTuple_New ((Py_ssize_t) 1);
+ PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *) stop_event_obj);
+
+ for (i = 0; i < PyList_Size (callback_list); i++)
+ {
+ PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple);
+ }
+
+}
+
+static PyGetSetDef stop_event_object_getset[] =
+{
+ { "stop_reason", stop_evpy_get_stop_reason, NULL, "Stop reason.", NULL },
+
+ { NULL } /* Sentinel. */
+};
+
+PyTypeObject stop_event_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /* ob_size */
+ "gdb.StopEvent", /* tp_name */
+ sizeof (stop_event_object), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ stop_evpy_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ "GDB stop event object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ stop_event_object_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0 /* tp_alloc */
+};
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 2b8d301..609892a 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -75,6 +75,7 @@ typedef int Py_ssize_t;
/* Also needed to parse enum var_types. */
#include "command.h"
+#include "breakpoint.h"
struct block;
struct value;
@@ -85,6 +86,31 @@ extern PyObject *gdb_module;
extern PyTypeObject value_object_type;
extern PyTypeObject block_object_type;
extern PyTypeObject symbol_object_type;
+extern PyTypeObject event_object_type;
+extern PyTypeObject stop_event_object_type;
+
+/* Used in python-breakpoint.c */
+typedef struct breakpoint_object breakpoint_object;
+
+struct breakpoint_object
+{
+ PyObject_HEAD
+
+ /* The breakpoint number according to gdb. */
+ int number;
+
+ /* The gdb breakpoint object, or NULL if the breakpoint has been
+ deleted. */
+ struct breakpoint *bp;
+};
+
+/* Used in python-eventregistry.c */
+typedef struct
+{
+ PyObject_HEAD
+
+ PyListObject *callbacks;
+} eventregistry_object;
typedef struct
{
@@ -92,11 +118,32 @@ typedef struct
/* The thread we represent. */
struct thread_info *thread;
+ eventregistry_object *stop_eventregistry;
+ eventregistry_object *breakpoint_stop_eventregistry;
+ eventregistry_object *signal_stop_eventregistry;
+ eventregistry_object *continue_eventregistry;
+ eventregistry_object *exited_eventregistry;
/* The Inferior object to which this thread belongs. */
PyObject *inf_obj;
} thread_object;
+/* Used in python-event.c */
+typedef struct
+{
+ PyObject_HEAD
+
+ thread_object *inferior_thread;
+ PyStringObject *event_type;
+} event_object;
+
+/* Used in python-stopevent.c */
+typedef struct
+{
+ event_object event;
+ PyStringObject *stop_reason;
+} stop_event_object;
+
extern struct cmd_list_element *set_python_list;
extern struct cmd_list_element *show_python_list;
@@ -136,6 +183,14 @@ PyObject *objfpy_get_printers (PyObject *, void *);
thread_object *create_thread_object (struct thread_info *tp);
thread_object *find_thread_object (ptid_t ptid);
PyObject *find_inferior_object (int pid);
+eventregistry_object *create_eventregistry_object (void);
+breakpoint_object *gdbpy_breakpoint_from_bpstats (struct bpstats *bs);
+void emit_stop_event (struct bpstats *bs, const char *stop_signal);
+void emit_breakpoint_stop_event (struct bpstats *bs);
+void emit_signal_stop_event (const char *stop_signal);
+void emit_continue_event (ptid_t ptid);
+void emit_exited_event (thread_object *inferior_thread,
+ long long int *exit_code);
struct block *block_object_to_block (PyObject *obj);
struct symbol *symbol_object_to_symbol (PyObject *obj);
@@ -162,6 +217,13 @@ void gdbpy_initialize_lazy_string (void);
void gdbpy_initialize_parameters (void);
void gdbpy_initialize_thread (void);
void gdbpy_initialize_inferior (void);
+void gdbpy_initialize_eventregistry (void);
+void gdbpy_initialize_event (void);
+void gdbpy_initialize_stop_event (void);
+void gdbpy_initialize_signal_stop_event (void);
+void gdbpy_initialize_breakpoint_stop_event (void);
+void gdbpy_initialize_continue_event (void);
+void gdbpy_initialize_exited_event (void);
struct cleanup *make_cleanup_py_decref (PyObject *py);
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 030b142..46f4a9e 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -965,6 +965,14 @@ Enables or disables printing of Python stack traces."),
gdbpy_initialize_inferior ();
gdbpy_initialize_events ();
+ gdbpy_initialize_eventregistry ();
+ gdbpy_initialize_event ();
+ gdbpy_initialize_stop_event ();
+ gdbpy_initialize_signal_stop_event ();
+ gdbpy_initialize_breakpoint_stop_event ();
+ gdbpy_initialize_continue_event ();
+ gdbpy_initialize_exited_event ();
+
PyRun_SimpleString ("import gdb");
PyRun_SimpleString ("gdb.pretty_printers = []");
On the 23rd of August 2009 Oguz Kayral submitted an initial patch to
implement GDB inferior notification events in Python. Since then the
patch has bit-rotted somewhat. I've reconstituted this patch
against current GDB head and attached it. I've not changed very much:
renamed the files, re-ordered the Makefile.in and made some minor code
changes so that it compiles.
Why am I doing this?
Firstly as a historical context. Oguz's patches were a series of
patches and also emails containing code in-line and not in patch format.
This patch unifies this (though I left out the examples, as they
cannot belong in the CVS tree at the moment). I'll reconstitute the
ChangeLogs when we submit this code upstream. Secondly, I am planning
on working on this patch/code: improving, adding and eventually
submitting it upstream. As the patch that Oguz wrote is substantial
enough to give a general thrust of the design intentions I thought it
would be a good idea to re-spark any conversations before I work on
this code. So if there any ideas, let's here them!
Cheers
Phil
--
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 65eb1fe..33cccd9 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -272,7 +272,12 @@ SUBDIR_PYTHON_OBS = \
py-auto-load.o \
py-block.o \
py-breakpoint.o \
+ py-breakpointstopevent.o \
py-cmd.o \
+ py-continueevent.o \
+ py-event.o \
+ py-eventregistry.o \
+ py-exitedevent.o \
py-frame.o \
py-function.o \
py-inferior.o \
@@ -282,17 +287,25 @@ SUBDIR_PYTHON_OBS = \
py-param.o \
py-prettyprint.o \
py-progspace.o \
+ py-signalstopevent.o \
+ py-stopevent.o \
py-symbol.o \
py-symtab.o \
py-type.o \
py-utils.o \
py-value.o
+
SUBDIR_PYTHON_SRCS = \
python/python.c \
python/py-auto-load.c \
python/py-block.c \
python/py-breakpoint.c \
+ python/py-breakpointstopevent.c \
python/py-cmd.c \
+ python/py-continueevent.c \
+ python/py-event.c \
+ python/py-eventregistry.c \
+ python/py-exitedevent.c \
python/py-frame.c \
python/py-function.c \
python/py-inferior.c \
@@ -302,6 +315,8 @@ SUBDIR_PYTHON_SRCS = \
python/py-param.c \
python/py-prettyprint.c \
python/py-progspace.c \
+ python/py-signalstopevent.c \
+ python/py-stopevent.c \
python/py-symbol.c \
python/py-symtab.c \
python/py-type.c \
@@ -2010,10 +2025,30 @@ py-breakpoint.o: $(srcdir)/python/py-breakpoint.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpoint.c
$(POSTCOMPILE)
+py-breakpointstopevent.o: $(srcdir)/python/py-breakpointstopevent.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpointstopevent.c
+ $(POSTCOMPILE)
+
py-cmd.o: $(srcdir)/python/py-cmd.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-cmd.c
$(POSTCOMPILE)
+py-continueevent.o: $(srcdir)/python/py-continueevent.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-continueevent.c
+ $(POSTCOMPILE)
+
+py-event.o: $(srcdir)/python/py-event.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-event.c
+ $(POSTCOMPILE)
+
+py-eventregistry.o: $(srcdir)/python/py-eventregistry.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-eventregistry.c
+ $(POSTCOMPILE)
+
+py-exitedevent.o: $(srcdir)/python/py-exitedevent.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-exitedevent.c
+ $(POSTCOMPILE)
+
py-frame.o: $(srcdir)/python/py-frame.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-frame.c
$(POSTCOMPILE)
@@ -2050,6 +2085,14 @@ py-progspace.o: $(srcdir)/python/py-progspace.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-progspace.c
$(POSTCOMPILE)
+py-signalstopevent.o: $(srcdir)/python/py-signalstopevent.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-signalstopevent.c
+ $(POSTCOMPILE)
+
+py-stopevent.o: $(srcdir)/python/py-stopevent.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-stopevent.c
+ $(POSTCOMPILE)
+
py-symbol.o: $(srcdir)/python/py-symbol.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-symbol.c
$(POSTCOMPILE)
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 14f0417..d00048a 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -29,9 +29,6 @@
#include "cli/cli-script.h"
#include "ada-lang.h"
-/* From breakpoint.c. */
-typedef struct breakpoint_object breakpoint_object;
-
static PyTypeObject breakpoint_object_type;
/* A dynamically allocated vector of breakpoint objects. Each
@@ -52,18 +49,6 @@ static int bppy_live;
constructor and the breakpoint-created hook function. */
static breakpoint_object *bppy_pending_object;
-struct breakpoint_object
-{
- PyObject_HEAD
-
- /* The breakpoint number according to gdb. */
- int number;
-
- /* The gdb breakpoint object, or NULL if the breakpoint has been
- deleted. */
- struct breakpoint *bp;
-};
-
/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python
exception if it is invalid. */
#define BPPY_REQUIRE_VALID(Breakpoint) \
@@ -626,6 +611,34 @@ bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
return result;
}
+/* Function to get the corresponding breakpoint object for the given
+ bpstats. */
+
+breakpoint_object *
+gdbpy_breakpoint_from_bpstats (struct bpstats *bs)
+{
+ int i, out = 0;
+ breakpoint_object *breakpoint = NULL;
+
+ if (bppy_live == 0)
+ return NULL;
+
+ for (i = 0; out < bppy_live; i++)
+ {
+ if (! bppy_breakpoints[i])
+ continue;
+
+ if (bs->breakpoint_at == bppy_breakpoints[i]->bp->loc)
+ breakpoint = bppy_breakpoints[i];
+
+ ++out;
+ }
+
+ return breakpoint;
+}
+
+
+
/* Static function to return a tuple holding all breakpoints. */
diff --git a/gdb/python/py-breakpointstopevent.c b/gdb/python/py-breakpointstopevent.c
new file mode 100644
index 0000000..b63df7b
--- /dev/null
+++ b/gdb/python/py-breakpointstopevent.c
@@ -0,0 +1,166 @@
+/* Python interface to inferior breakpoint stop events.
+
+ Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+static PyTypeObject breakpoint_stop_event_object_type;
+
+typedef struct
+{
+ stop_event_object stop_event;
+ breakpoint_object *breakpoint;
+} breakpoint_stop_event_object;
+
+static void
+bp_stop_evpy_dealloc (PyObject *self)
+{
+ Py_DECREF (((breakpoint_stop_event_object *) self)->breakpoint);
+ self->ob_type->tp_free (self);
+}
+
+/* Python function to get the stop event's breakpoint. */
+static PyObject *
+bp_stop_evpy_get_breakpoint (PyObject *self, void *closure)
+{
+ breakpoint_stop_event_object *breakpoint_stop_event_obj =
+(breakpoint_stop_event_object *) self;
+
+ Py_INCREF (breakpoint_stop_event_obj->breakpoint);
+
+ return (PyObject *) (breakpoint_stop_event_obj->breakpoint);
+}
+
+breakpoint_stop_event_object *
+create_breakpoint_stop_event_object (breakpoint_object *bp)
+{
+ breakpoint_stop_event_object *breakpoint_stop_event_obj;
+
+ breakpoint_stop_event_obj = PyObject_New
+(breakpoint_stop_event_object, &breakpoint_stop_event_object_type);
+ if (!breakpoint_stop_event_obj)
+ return NULL;
+
+ breakpoint_stop_event_obj->stop_event.event.inferior_thread =
+find_thread_object (inferior_ptid);
+ Py_INCREF (breakpoint_stop_event_obj->stop_event.event.inferior_thread);
+ breakpoint_stop_event_obj->stop_event.event.event_type =
+(PyStringObject *) PyString_FromString ("stop");
+ breakpoint_stop_event_obj->stop_event.stop_reason = (PyStringObject
+*) PyString_FromString ("breakpoint");
+ breakpoint_stop_event_obj->breakpoint = bp;
+ Py_INCREF (breakpoint_stop_event_obj->breakpoint);
+
+ return breakpoint_stop_event_obj;
+}
+
+/* Initialize the Python breakpoint stop event code. */
+void
+gdbpy_initialize_breakpoint_stop_event (void)
+{
+ breakpoint_stop_event_object_type.tp_base = &stop_event_object_type;
+ if (PyType_Ready (&breakpoint_stop_event_object_type) < 0)
+ return;
+
+ Py_INCREF (&breakpoint_stop_event_object_type);
+ PyModule_AddObject (gdb_module, "BreakpointStopEvent", (PyObject *)
+&breakpoint_stop_event_object_type);
+}
+
+/* Callback that is used when a stop event occurs. This function will
+create a new Python breakpoint stop event object. */
+void
+emit_breakpoint_stop_event (struct bpstats *bs)
+{
+ thread_object *inferior_thread;
+ PyObject *callback_list;
+ PyObject *args_tuple;
+ Py_ssize_t i;
+ breakpoint_object *breakpoint;
+ breakpoint_stop_event_object *breakpoint_stop_event_obj;
+
+ inferior_thread = find_thread_object (inferior_ptid);
+
+ breakpoint = gdbpy_breakpoint_from_bpstats (bs);
+
+ breakpoint_stop_event_obj = create_breakpoint_stop_event_object (breakpoint);
+
+ callback_list = (PyObject *)
+(inferior_thread->breakpoint_stop_eventregistry->callbacks);
+
+ args_tuple = PyTuple_New ((Py_ssize_t) 1);
+ PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *)
+breakpoint_stop_event_obj);
+
+ for (i = 0; i < PyList_Size (callback_list); i++)
+ {
+ PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple);
+ }
+}
+
+static PyGetSetDef breakpoint_stop_event_object_getset[] =
+{
+ { "breakpoint", bp_stop_evpy_get_breakpoint, NULL, "Breakpoint.", NULL },
+
+ { NULL } /* Sentinel. */
+};
+
+static PyTypeObject breakpoint_stop_event_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /* ob_size */
+ "gdb.BreakpointStopEvent", /* tp_name */
+ sizeof (breakpoint_stop_event_object), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ bp_stop_evpy_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "GDB breakpoint stop event object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ breakpoint_stop_event_object_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0 /* tp_alloc */
+};
diff --git a/gdb/python/py-continueevent.c b/gdb/python/py-continueevent.c
new file mode 100644
index 0000000..f80d9ac
--- /dev/null
+++ b/gdb/python/py-continueevent.c
@@ -0,0 +1,138 @@
+/* Python interface to inferior continue events.
+
+ Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+static PyTypeObject continue_event_object_type;
+
+typedef struct
+{
+ event_object event;
+} continue_event_object;
+
+static void
+continue_evpy_dealloc (PyObject *self)
+{
+ self->ob_type->tp_free (self);
+}
+
+continue_event_object *
+create_continue_event_object ()
+{
+ continue_event_object *continue_event_obj;
+
+ continue_event_obj = PyObject_New (continue_event_object,
+&continue_event_object_type);
+
+ if (!continue_event_obj)
+ return NULL;
+
+ continue_event_obj->event.inferior_thread = find_thread_object
+(inferior_ptid);
+ Py_INCREF (continue_event_obj->event.inferior_thread);
+ continue_event_obj->event.event_type = (PyStringObject *)
+PyString_FromString ("continue");
+
+ return continue_event_obj;
+}
+
+/* Initialize the Python continue event code. */
+void
+gdbpy_initialize_continue_event (void)
+{
+ continue_event_object_type.tp_base = &event_object_type;
+ if (PyType_Ready (&continue_event_object_type) < 0)
+ return;
+
+ Py_INCREF (&continue_event_object_type);
+ PyModule_AddObject (gdb_module, "ContinueEvent", (PyObject *)
+&continue_event_object_type);
+}
+
+/* Callback that is used when a continue event occurs. This function
+ will create a new Python continue event object. */
+void
+emit_continue_event (ptid_t ptid)
+{
+ thread_object *inferior_thread;
+ PyObject *callback_list;
+ PyObject *args_tuple;
+ Py_ssize_t i;
+ continue_event_object *continue_event_obj;
+
+ inferior_thread = find_thread_object (inferior_ptid);
+
+ continue_event_obj = create_continue_event_object();
+
+ callback_list = (PyObject *)
+(inferior_thread->continue_eventregistry->callbacks);
+
+ args_tuple = PyTuple_New ((Py_ssize_t) 1);
+ PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *) continue_event_obj);
+
+ for (i = 0; i < PyList_Size (callback_list); i++)
+ {
+ PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple);
+ }
+}
+
+static PyTypeObject continue_event_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /* ob_size */
+ "gdb.ContinueEvent", /* tp_name */
+ sizeof (continue_event_object), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ continue_evpy_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "GDB continue event object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0 /* tp_alloc */
+};
diff --git a/gdb/python/py-event.c b/gdb/python/py-event.c
new file mode 100644
index 0000000..7394ded
--- /dev/null
+++ b/gdb/python/py-event.c
@@ -0,0 +1,130 @@
+/* Python interface to inferior events.
+
+ Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+event_object *
+create_event_object (const char *event_type)
+{
+ event_object *event_obj;
+
+ event_obj = PyObject_New (event_object, &event_object_type);
+ if (!event_obj)
+ return NULL;
+
+ event_obj->inferior_thread = find_thread_object (inferior_ptid);
+ Py_INCREF (event_obj->inferior_thread);
+ event_obj->event_type = (PyStringObject *) PyString_FromString (event_type);
+
+ return event_obj;
+}
+
+static void
+evpy_dealloc (PyObject *self)
+{
+ Py_DECREF (((event_object *) self)->inferior_thread);
+ self->ob_type->tp_free (self);
+}
+
+/* Python function to get the event's thread. */
+static PyObject *
+evpy_get_inferior_thread (PyObject *self, void *closure)
+{
+ event_object *event_obj = (event_object *) self;
+
+ Py_INCREF (event_obj->inferior_thread);
+
+ return (PyObject *) (event_obj->inferior_thread);
+}
+
+/* Python function to get the event's type. */
+static PyObject *
+evpy_get_event_type (PyObject *self, void *closure)
+{
+ event_object *event_obj = (event_object *) self;
+
+ Py_INCREF (event_obj->event_type);
+
+ return (PyObject *) (event_obj->event_type);
+}
+
+/* Initialize the Python event code. */
+void
+gdbpy_initialize_event (void)
+{
+ if (PyType_Ready (&event_object_type) < 0)
+ return;
+
+ Py_INCREF (&event_object_type);
+ PyModule_AddObject (gdb_module, "Event", (PyObject *) &event_object_type);
+}
+
+static PyGetSetDef event_object_getset[] =
+{
+ { "inferior_thread", evpy_get_inferior_thread, NULL,
+ "Inferior thread.", NULL },
+ { "event_type", evpy_get_event_type, NULL, "Event type.", NULL },
+
+ { NULL } /* Sentinel. */
+};
+
+PyTypeObject event_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /* ob_size */
+ "gdb.Event", /* tp_name */
+ sizeof (event_object), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ evpy_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ "GDB event object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ event_object_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0 /* tp_alloc */
+};
diff --git a/gdb/python/py-eventregistry.c b/gdb/python/py-eventregistry.c
new file mode 100644
index 0000000..c1aa7b4
--- /dev/null
+++ b/gdb/python/py-eventregistry.c
@@ -0,0 +1,155 @@
+/* Python interface to inferior thread event registries.
+
+ Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "command.h"
+#include "python-internal.h"
+
+static PyTypeObject eventregistry_object_type;
+
+/* Implementation of EventRegistry.connect () -> NULL */
+static PyObject *
+evregpy_connect (PyObject *self, PyObject *function)
+{
+ PyObject *func;
+ PyObject *callback_list = (PyObject *) (((eventregistry_object *)
+self)->callbacks);
+
+ if (!PyArg_ParseTuple (function, "O", &func))
+ return NULL;
+
+ if (!PyCallable_Check (func))
+ {
+ PyErr_SetString (PyExc_RuntimeError, "Function is not callable");
+ return NULL;
+ }
+
+ Py_INCREF (func);
+
+ PyList_Append (callback_list, func);
+
+ Py_RETURN_NONE;
+}
+
+/* Implementation of EventRegistry.disconnect () -> NULL */
+static PyObject *
+evregpy_disconnect (PyObject *self, PyObject *function)
+{
+ PyObject *func;
+ PyObject *callback_list = (PyObject *) (((eventregistry_object *)
+self)->callbacks);
+
+ if (!PyArg_ParseTuple (function, "O", &func))
+ return NULL;
+
+ if (!PyCallable_Check (func))
+ {
+ PyErr_SetString (PyExc_RuntimeError, "Function is not callable");
+ return NULL;
+ }
+
+ Py_INCREF (func);
+
+ PySequence_DelItem (callback_list, PySequence_Index (callback_list, func));
+
+ Py_RETURN_NONE;
+}
+
+eventregistry_object *
+create_eventregistry_object (void)
+{
+ eventregistry_object *eventregistry_obj;
+
+ eventregistry_obj = PyObject_New (eventregistry_object,
+&eventregistry_object_type);
+ if (!eventregistry_obj)
+ return NULL;
+
+ eventregistry_obj->callbacks = (PyListObject *) PyList_New (0);
+
+ return eventregistry_obj;
+}
+
+static void
+evregpy_dealloc (PyObject *self)
+{
+ Py_DECREF (((eventregistry_object *) self)->callbacks);
+ self->ob_type->tp_free (self);
+}
+
+/* Initialize the Python event registry code. */
+void
+gdbpy_initialize_eventregistry (void)
+{
+ if (PyType_Ready (&eventregistry_object_type) < 0)
+ return;
+
+ Py_INCREF (&eventregistry_object_type);
+ PyModule_AddObject (gdb_module, "EventRegistry", (PyObject *)
+&eventregistry_object_type);
+}
+
+static PyMethodDef eventregistry_object_methods[] =
+{
+ { "connect", evregpy_connect, METH_VARARGS, "Add function" },
+ { "disconnect", evregpy_disconnect, METH_VARARGS, "Remove function" },
+ { NULL } /* Sentinel. */
+};
+
+static PyTypeObject eventregistry_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /* ob_size */
+ "gdb.EventRegistry", /* tp_name */
+ sizeof (eventregistry_object), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ evregpy_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "GDB event registry object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ eventregistry_object_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0 /* tp_alloc */
+};
diff --git a/gdb/python/py-exitedevent.c b/gdb/python/py-exitedevent.c
new file mode 100644
index 0000000..d2a1d88
--- /dev/null
+++ b/gdb/python/py-exitedevent.c
@@ -0,0 +1,156 @@
+/* Python interface to inferior exit events.
+
+ Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+static PyTypeObject exited_event_object_type;
+
+typedef struct
+{
+ event_object event;
+ PyLongObject *exit_code;
+} exited_event_object;
+
+static void
+exit_evpy_dealloc (PyObject *self)
+{
+ Py_DECREF (((exited_event_object *) self)->exit_code);
+ self->ob_type->tp_free (self);
+}
+
+/* Python function to get the exited event's exit code. */
+static PyObject *
+exit_evpy_get_exit_code (PyObject *self, void *closure)
+{
+ exited_event_object *exited_event_obj = (exited_event_object *) self;
+
+ Py_INCREF (exited_event_obj->exit_code);
+
+ return (PyObject *) (exited_event_obj->exit_code);
+}
+
+exited_event_object *
+create_exited_event_object (thread_object *inferior_thread, long long
+int *exit_code)
+{
+ exited_event_object *exited_event_obj;
+
+ exited_event_obj = PyObject_New (exited_event_object,
+&exited_event_object_type);
+
+ if (!exited_event_obj)
+ return NULL;
+
+ exited_event_obj->event.inferior_thread = inferior_thread;
+ Py_INCREF (exited_event_obj->event.inferior_thread);
+ exited_event_obj->event.event_type = (PyStringObject *)
+PyString_FromString ("exit");
+ exited_event_obj->exit_code = (PyLongObject *) PyLong_FromLongLong
+(*exit_code);
+
+ return exited_event_obj;
+}
+
+/* Initialize the Python exited event code. */
+void gdbpy_initialize_exited_event (void)
+{
+ exited_event_object_type.tp_base = &event_object_type;
+ if (PyType_Ready (&exited_event_object_type) < 0)
+ return;
+
+ Py_INCREF (&exited_event_object_type);
+ PyModule_AddObject (gdb_module, "ExitedEvent", (PyObject *)
+&exited_event_object_type);
+}
+
+/* Callback that is used when an exit event occurs. This function
+ will create a new Python exited event object. */
+void
+emit_exited_event (thread_object *inferior_thread, long long int *exit_code)
+{
+ PyObject *callback_list;
+ PyObject *args_tuple;
+ Py_ssize_t i;
+ exited_event_object *exited_event_obj;
+
+ exited_event_obj = create_exited_event_object (inferior_thread, exit_code);
+
+ callback_list = (PyObject *)
+(inferior_thread->exited_eventregistry->callbacks);
+
+ args_tuple = PyTuple_New ((Py_ssize_t) 1);
+ PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *) exited_event_obj);
+
+ for (i = 0; i < PyList_Size (callback_list); i++)
+ {
+ PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple);
+ }
+}
+
+static PyGetSetDef exited_event_object_getset[] =
+{
+ { "exit_code", exit_evpy_get_exit_code, NULL, "Exit code.", NULL },
+
+ { NULL } /* Sentinel. */
+};
+
+static PyTypeObject exited_event_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /* ob_size */
+ "gdb.ExitedEvent", /* tp_name */
+ sizeof (exited_event_object), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ exit_evpy_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "GDB exited event object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ exited_event_object_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0 /* tp_alloc */
+};
diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c
index 3a0feab..9e182c4 100644
--- a/gdb/python/py-inferior.c
+++ b/gdb/python/py-inferior.c
@@ -26,6 +26,7 @@
#include "python-internal.h"
#include "arch-utils.h"
#include "language.h"
+#include "gdb_signals.h"
struct threadlist_entry {
thread_object *thread_obj;
@@ -73,6 +74,72 @@ static PyTypeObject membuf_object_type;
} \
} while (0)
+static void
+python_on_normal_stop (struct bpstats *bs, int print_frame)
+{
+ PyGILState_STATE state;
+ char *stop_signal;
+
+ if (!find_thread_ptid (inferior_ptid))
+ return;
+
+ stop_signal = (char *) target_signal_to_name (inferior_thread()->stop_signal);
+
+ state = PyGILState_Ensure ();
+
+ emit_stop_event (bs, stop_signal);
+
+ PyGILState_Release (state);
+}
+
+static void
+python_on_resume (ptid_t ptid)
+{
+ PyGILState_STATE state;
+
+ state = PyGILState_Ensure ();
+
+ emit_continue_event (ptid);
+
+ PyGILState_Release (state);
+}
+
+static void
+python_thread_exit (struct thread_info *tp, int ignore)
+{
+ PyGILState_STATE state;
+ LONGEST exitcode_val;
+ long long int *exit_code;
+ inferior_object *inf_obj;
+ thread_object *thread_obj;
+ struct threadlist_entry **entry;
+
+ inf_obj = (inferior_object *) find_inferior_object (PIDGET(tp->ptid));
+ if (!inf_obj)
+ return;
+
+ /* Find thread entry in its inferior's thread_list. */
+ for (entry = &inf_obj->threads; *entry != NULL; entry = &(*entry)->next)
+ if ((*entry)->thread_obj->thread == tp)
+ break;
+
+ if (!*entry)
+ return;
+
+ thread_obj = (*entry)->thread_obj;
+
+ state = PyGILState_Ensure ();
+
+ if (get_internalvar_integer (lookup_internalvar ("_exitcode"), &exitcode_val))
+ exit_code = (long long int *) &exitcode_val;
+
+ if (exit_code)
+ emit_exited_event (thread_obj, exit_code);
+
+ PyGILState_Release (state);
+}
+
+
/* Return a borrowed reference to the Python object of type Inferior
representing INFERIOR. If the object has already been created,
return it, otherwise, create it. Return NULL on failure. */
@@ -589,6 +656,9 @@ gdbpy_initialize_inferior (void)
observer_attach_new_thread (add_thread_object);
observer_attach_thread_exit (delete_thread_object);
+ observer_attach_normal_stop (python_on_normal_stop);
+ observer_attach_target_resumed (python_on_resume);
+ observer_attach_thread_exit (python_thread_exit);
if (PyType_Ready (&membuf_object_type) < 0)
return;
diff --git a/gdb/python/py-infthread.c b/gdb/python/py-infthread.c
index 86aba50..d3f448c 100644
--- a/gdb/python/py-infthread.c
+++ b/gdb/python/py-infthread.c
@@ -51,6 +51,12 @@ create_thread_object (struct thread_info *tp)
thread_obj->inf_obj = find_inferior_object (PIDGET (tp->ptid));
Py_INCREF (thread_obj->inf_obj);
+ thread_obj->stop_eventregistry = create_eventregistry_object ();
+ thread_obj->breakpoint_stop_eventregistry = create_eventregistry_object ();
+ thread_obj->signal_stop_eventregistry = create_eventregistry_object ();
+ thread_obj->continue_eventregistry = create_eventregistry_object ();
+ thread_obj->exited_eventregistry = create_eventregistry_object ();
+
return thread_obj;
}
static void
thpy_dealloc (PyObject *self)
{
Py_DECREF (((thread_object *) self)->inf_obj);
+ Py_DECREF (((thread_object *) self)->stop_eventregistry);
+ Py_DECREF (((thread_object *) self)->breakpoint_stop_eventregistry);
+ Py_DECREF (((thread_object *) self)->signal_stop_eventregistry);
+ Py_DECREF (((thread_object *) self)->continue_eventregistry);
+ Py_DECREF (((thread_object *) self)->exited_eventregistry);
+
self->ob_type->tp_free (self);
}
static PyObject *
+thpy_get_stop_eventregistry (PyObject *self, void *closure)
+{
+ thread_object *thread_obj = (thread_object *) self;
+
+ THPY_REQUIRE_VALID (thread_obj);
+
+ Py_INCREF (thread_obj->stop_eventregistry);
+
+ return (PyObject *) (thread_obj->stop_eventregistry);
+}
+
+static PyObject *
+thpy_get_breakpoint_stop_eventregistry (PyObject *self, void *closure)
+{
+ thread_object *thread_obj = (thread_object *) self;
+
+ THPY_REQUIRE_VALID (thread_obj);
+
+ Py_INCREF (thread_obj->breakpoint_stop_eventregistry);
+
+ return (PyObject *) (thread_obj->breakpoint_stop_eventregistry);
+}
+
+static PyObject *
+thpy_get_signal_stop_eventregistry (PyObject *self, void *closure)
+{
+ thread_object *thread_obj = (thread_object *) self;
+
+ THPY_REQUIRE_VALID (thread_obj);
+
+ Py_INCREF (thread_obj->signal_stop_eventregistry);
+
+ return (PyObject *) (thread_obj->signal_stop_eventregistry);
+}
+
+static PyObject *
+thpy_get_continue_eventregistry (PyObject *self, void *closure)
+{
+ thread_object *thread_obj = (thread_object *) self;
+
+ THPY_REQUIRE_VALID (thread_obj);
+
+ Py_INCREF (thread_obj->continue_eventregistry);
+
+ return (PyObject *) (thread_obj->continue_eventregistry);
+}
+
+static PyObject *
+thpy_get_exited_eventregistry (PyObject *self, void *closure)
+{
+ thread_object *thread_obj = (thread_object *) self;
+
+ THPY_REQUIRE_VALID (thread_obj);
+
+ Py_INCREF (thread_obj->exited_eventregistry);
+
+ return (PyObject *) (thread_obj->exited_eventregistry);
+}
+
+static PyObject *
thpy_get_num (PyObject *self, void *closure)
{
thread_object *thread_obj = (thread_object *) self;
@@ -204,6 +274,17 @@ static PyGetSetDef thread_object_getset[] =
{ "num", thpy_get_num, NULL, "ID of the thread, as assigned by GDB.", NULL },
{ "ptid", thpy_get_ptid, NULL, "ID of the thread, as assigned by the OS.",
NULL },
+ { "stop_eventregistry", thpy_get_stop_eventregistry, NULL,
+ "Stop event registry object of the thread.", NULL },
+ { "breakpoint_stop_eventregistry",
+ thpy_get_breakpoint_stop_eventregistry, NULL,
+ "Breakpoint stop event registry object of the thread.", NULL },
+ { "signal_stop_eventregistry", thpy_get_signal_stop_eventregistry,
+ NULL, "Signal stop event registry object of the thread.", NULL },
+ { "continue_eventregistry", thpy_get_continue_eventregistry, NULL,
+ "Continue event registry object of the thread.", NULL },
+ { "exited_eventregistry", thpy_get_exited_eventregistry, NULL,
+ "Exited event registry object of the thread.", NULL },
{ NULL }
};
diff --git a/gdb/python/py-signalstopevent.c b/gdb/python/py-signalstopevent.c
new file mode 100644
index 0000000..5ab8af7
--- /dev/null
+++ b/gdb/python/py-signalstopevent.c
@@ -0,0 +1,163 @@
+/* Python interface to inferior signal stop events.
+
+ Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+static PyTypeObject signal_stop_event_object_type;
+
+typedef struct
+{
+ stop_event_object stop_event;
+ PyStringObject *stop_signal;
+} signal_stop_event_object;
+
+static void
+sig_stop_evpy_dealloc (PyObject *self)
+{
+ Py_DECREF (((signal_stop_event_object *) self)->stop_signal);
+ self->ob_type->tp_free (self);
+}
+
+/* Python function to get the stop event's stop signal. */
+static PyObject *
+sig_stop_evpy_get_stop_signal (PyObject *self, void *closure)
+{
+ signal_stop_event_object *signal_stop_event_obj =
+(signal_stop_event_object *) self;
+
+ Py_INCREF (signal_stop_event_obj->stop_signal);
+
+ return (PyObject *) (signal_stop_event_obj->stop_signal);
+}
+
+signal_stop_event_object *
+create_signal_stop_event_object (const char *stop_signal)
+{
+ signal_stop_event_object *signal_stop_event_obj;
+
+ signal_stop_event_obj = PyObject_New (signal_stop_event_object,
+&signal_stop_event_object_type);
+ if (!signal_stop_event_obj)
+ return NULL;
+
+ signal_stop_event_obj->stop_event.event.inferior_thread =
+find_thread_object (inferior_ptid);
+ Py_INCREF (signal_stop_event_obj->stop_event.event.inferior_thread);
+ signal_stop_event_obj->stop_event.event.event_type = (PyStringObject
+*) PyString_FromString ("stop");
+ signal_stop_event_obj->stop_event.stop_reason = (PyStringObject *)
+PyString_FromString ("signal");
+ signal_stop_event_obj->stop_signal = (PyStringObject *)
+PyString_FromString (stop_signal);
+
+ return signal_stop_event_obj;
+}
+
+/* Initialize the Python stop event code. */
+void
+gdbpy_initialize_signal_stop_event (void)
+{
+ signal_stop_event_object_type.tp_base = &stop_event_object_type;
+ if (PyType_Ready (&signal_stop_event_object_type) < 0)
+ return;
+
+ Py_INCREF (&signal_stop_event_object_type);
+ PyModule_AddObject (gdb_module, "SignalStopEvent", (PyObject *)
+&signal_stop_event_object_type);
+}
+
+/* Callback that is used when a signal stop event occurs. This function
+ will create a new Python signal stop event object. */
+void
+emit_signal_stop_event (const char *stop_signal)
+{
+ thread_object *inferior_thread;
+ PyObject *callback_list;
+ PyObject *args_tuple;
+ Py_ssize_t i;
+ signal_stop_event_object *signal_stop_event_obj;
+
+ inferior_thread = find_thread_object (inferior_ptid);
+
+ signal_stop_event_obj = create_signal_stop_event_object (stop_signal);
+
+ callback_list = (PyObject *)
+(inferior_thread->signal_stop_eventregistry->callbacks);
+
+ args_tuple = PyTuple_New ((Py_ssize_t) 1);
+ PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *)
+signal_stop_event_obj);
+
+ for (i = 0; i < PyList_Size (callback_list); i++)
+ {
+ PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple);
+ }
+}
+
+static PyGetSetDef signal_stop_event_object_getset[] =
+{
+ { "stop_signal", sig_stop_evpy_get_stop_signal, NULL, "Stop signal.", NULL },
+
+ { NULL } /* Sentinel. */
+};
+
+static PyTypeObject signal_stop_event_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /* ob_size */
+ "gdb.SignalStopEvent", /* tp_name */
+ sizeof (signal_stop_event_object), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ sig_stop_evpy_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "GDB signal stop event object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ signal_stop_event_object_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0 /* tp_alloc */
+};
diff --git a/gdb/python/py-stopevent.c b/gdb/python/py-stopevent.c
new file mode 100644
index 0000000..069e441
--- /dev/null
+++ b/gdb/python/py-stopevent.c
@@ -0,0 +1,164 @@
+/* Python interface to inferior stop events.
+
+ Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+static void
+stop_evpy_dealloc (PyObject *self)
+{
+ Py_DECREF (((stop_event_object *) self)->stop_reason);
+ self->ob_type->tp_free (self);
+}
+
+/* Python function to get the stop event's stop reason. */
+static PyObject *
+stop_evpy_get_stop_reason (PyObject *self, void *closure)
+{
+ stop_event_object *stop_event_obj = (stop_event_object *) self;
+
+ Py_INCREF (stop_event_obj->stop_reason);
+
+ return (PyObject *) (stop_event_obj->stop_reason);
+}
+
+stop_event_object *
+create_stop_event_object (const char *stop_reason)
+{
+ stop_event_object *stop_event_obj;
+
+ stop_event_obj = PyObject_New (stop_event_object, &stop_event_object_type);
+ if (!stop_event_obj)
+ return NULL;
+
+ stop_event_obj->event.inferior_thread = find_thread_object (inferior_ptid);
+ Py_INCREF (stop_event_obj->event.inferior_thread);
+ stop_event_obj->event.event_type = (PyStringObject *)
+PyString_FromString ("stop");
+ stop_event_obj->stop_reason = (PyStringObject *) PyString_FromString
+(stop_reason);
+
+ return stop_event_obj;
+}
+
+/* Initialize the Python stop event code. */
+void
+gdbpy_initialize_stop_event (void)
+{
+ stop_event_object_type.tp_base = &event_object_type;
+ if (PyType_Ready (&stop_event_object_type) < 0)
+ return;
+
+ Py_INCREF (&stop_event_object_type);
+ PyModule_AddObject (gdb_module, "StopEvent", (PyObject *)
+&stop_event_object_type);
+}
+
+/* Callback that is used when a stop event occurs. This function
+ will create a new Python stop event object. */
+void
+emit_stop_event (struct bpstats *bs, const char *stop_signal)
+{
+ thread_object *inferior_thread;
+ PyObject *callback_list;
+ PyObject *args_tuple;
+ Py_ssize_t i;
+ stop_event_object *stop_event_obj = NULL; /* Appease GCC warning. */
+
+ inferior_thread = find_thread_object (inferior_ptid);
+
+ if (bs)
+ {
+ stop_event_obj = create_stop_event_object ("breakpoint");
+ emit_breakpoint_stop_event (bs);
+ }
+
+ /* Check if the signal is "Signal 0" or "Trace/breakpoint trap". */
+ if ((strcmp (stop_signal, "0") != 0) && (strcmp (stop_signal,
+"SIGTRAP") != 0))
+ {
+ stop_event_obj = create_stop_event_object ("signal");
+ emit_signal_stop_event (stop_signal);
+ }
+
+ if (!stop_event_obj)
+ stop_event_obj = create_stop_event_object ("unknown");
+
+ callback_list = (PyObject *) (inferior_thread->stop_eventregistry->callbacks);
+
+ args_tuple = PyTuple_New ((Py_ssize_t) 1);
+ PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *) stop_event_obj);
+
+ for (i = 0; i < PyList_Size (callback_list); i++)
+ {
+ PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple);
+ }
+
+}
+
+static PyGetSetDef stop_event_object_getset[] =
+{
+ { "stop_reason", stop_evpy_get_stop_reason, NULL, "Stop reason.", NULL },
+
+ { NULL } /* Sentinel. */
+};
+
+PyTypeObject stop_event_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /* ob_size */
+ "gdb.StopEvent", /* tp_name */
+ sizeof (stop_event_object), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ stop_evpy_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ "GDB stop event object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ stop_event_object_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0 /* tp_alloc */
+};
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 2b8d301..609892a 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -75,6 +75,7 @@ typedef int Py_ssize_t;
/* Also needed to parse enum var_types. */
#include "command.h"
+#include "breakpoint.h"
struct block;
struct value;
@@ -85,6 +86,31 @@ extern PyObject *gdb_module;
extern PyTypeObject value_object_type;
extern PyTypeObject block_object_type;
extern PyTypeObject symbol_object_type;
+extern PyTypeObject event_object_type;
+extern PyTypeObject stop_event_object_type;
+
+/* Used in python-breakpoint.c */
+typedef struct breakpoint_object breakpoint_object;
+
+struct breakpoint_object
+{
+ PyObject_HEAD
+
+ /* The breakpoint number according to gdb. */
+ int number;
+
+ /* The gdb breakpoint object, or NULL if the breakpoint has been
+ deleted. */
+ struct breakpoint *bp;
+};
+
+/* Used in python-eventregistry.c */
+typedef struct
+{
+ PyObject_HEAD
+
+ PyListObject *callbacks;
+} eventregistry_object;
typedef struct
{
@@ -92,11 +118,32 @@ typedef struct
/* The thread we represent. */
struct thread_info *thread;
+ eventregistry_object *stop_eventregistry;
+ eventregistry_object *breakpoint_stop_eventregistry;
+ eventregistry_object *signal_stop_eventregistry;
+ eventregistry_object *continue_eventregistry;
+ eventregistry_object *exited_eventregistry;
/* The Inferior object to which this thread belongs. */
PyObject *inf_obj;
} thread_object;
+/* Used in python-event.c */
+typedef struct
+{
+ PyObject_HEAD
+
+ thread_object *inferior_thread;
+ PyStringObject *event_type;
+} event_object;
+
+/* Used in python-stopevent.c */
+typedef struct
+{
+ event_object event;
+ PyStringObject *stop_reason;
+} stop_event_object;
+
extern struct cmd_list_element *set_python_list;
extern struct cmd_list_element *show_python_list;
@@ -136,6 +183,14 @@ PyObject *objfpy_get_printers (PyObject *, void *);
thread_object *create_thread_object (struct thread_info *tp);
thread_object *find_thread_object (ptid_t ptid);
PyObject *find_inferior_object (int pid);
+eventregistry_object *create_eventregistry_object (void);
+breakpoint_object *gdbpy_breakpoint_from_bpstats (struct bpstats *bs);
+void emit_stop_event (struct bpstats *bs, const char *stop_signal);
+void emit_breakpoint_stop_event (struct bpstats *bs);
+void emit_signal_stop_event (const char *stop_signal);
+void emit_continue_event (ptid_t ptid);
+void emit_exited_event (thread_object *inferior_thread,
+ long long int *exit_code);
struct block *block_object_to_block (PyObject *obj);
struct symbol *symbol_object_to_symbol (PyObject *obj);
@@ -162,6 +217,13 @@ void gdbpy_initialize_lazy_string (void);
void gdbpy_initialize_parameters (void);
void gdbpy_initialize_thread (void);
void gdbpy_initialize_inferior (void);
+void gdbpy_initialize_eventregistry (void);
+void gdbpy_initialize_event (void);
+void gdbpy_initialize_stop_event (void);
+void gdbpy_initialize_signal_stop_event (void);
+void gdbpy_initialize_breakpoint_stop_event (void);
+void gdbpy_initialize_continue_event (void);
+void gdbpy_initialize_exited_event (void);
struct cleanup *make_cleanup_py_decref (PyObject *py);
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 030b142..46f4a9e 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -965,6 +965,14 @@ Enables or disables printing of Python stack traces."),
gdbpy_initialize_inferior ();
gdbpy_initialize_events ();
+ gdbpy_initialize_eventregistry ();
+ gdbpy_initialize_event ();
+ gdbpy_initialize_stop_event ();
+ gdbpy_initialize_signal_stop_event ();
+ gdbpy_initialize_breakpoint_stop_event ();
+ gdbpy_initialize_continue_event ();
+ gdbpy_initialize_exited_event ();
+
PyRun_SimpleString ("import gdb");
PyRun_SimpleString ("gdb.pretty_printers = []");