This is the mail archive of the archer@sourceware.org mailing list for the Archer project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Python inferior control


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 = []");
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]