[patch] Support inferior events in python

sami wagiaalla
2011-01-04T15:54:31Z

[-- Attachment #1: Type: text/plain, Size: 607 bytes --]

This patch is base on the work done by Oguz Kayral in the summer of
2009. Tom Tromey and Phil Muldoon also provided a lot of help and
guidance on this.

It adds to the python API the module 'gdb.events'. The events module
contains references to event registries that one can add observers to.
Namely,
events.breakpoint
events.signal
events.cont
events.exited

I have also taken the example that Oguz provided and turned that into a
test case.

This has been tested on Fedora 13 X8664 with gcc 4.4.4-f13

A documentation patch will follow soon.

Thanks in advance for the review.

Sami

[-- Attachment #2: oguz-python-events.patch --]
[-- Type: text/x-patch, Size: 59618 bytes --]

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 002f3d2..7e80dd4 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,31 @@
+2010-12-22 Sami Wagiaalla <swagiaal@redhat.com>
+ Oguz Kayral <oguzkayral@gmail.com>
+
+ * python/py-inferior.c (python_on_normal_stop): New function.
+ (python_on_resume): New function.
+ (python_inferior_exit): New function.
+ (gdbpy_initialize_inferior): Add normal_stop, target_resumed, and
+ inferior_exit observers.
+ * python/py-eventregistry.c: New file.
+ * python/py-event.c: New file.
+ * python/py-events.c: New file.
+ * python/py-continueevent.c: New file.
+ * python/py-breakpointevent.c : New file.
+ * python/py-signalevent.c : New file.
+ * python/py-exetiedevent.c : New file.
+ * python/py-breakpoint.c (gdbpy_breakpoint_from_bpstats): New function.
+ Move struct breakpoint_object from here...
+ * python/python-internal.h: ... to here.
+ * python/py-event.h: New file.
+ * python/py-events.h: New file.
+ * Makefile.in (SUBDIR_PYTHON_OBS): Add py-breakpointstopevent.o,
+ py-continueevent.o, py-event.o, py-eventregistry.o, py-events.o,
+ py-exitedevent.o, py-signalstopevent.o, and py-stopevent.o.
+ (SUBDIR_PYTHON_SRCS): Add py-breakpointstopevent.c,
+ py-continueevent.c, py-event.c, py-eventregistry.c, py-events.c,
+ py-exitedevent.c, py-signalstopevent.c, and py-stopevent.c.
+ Add build rules for all the above.
+
2010-12-14 Ken Werner <ken.werner@de.ibm.com>

* valops.c (value_one): Use get_array_bounds to compute the number
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ff10039..c291ee2 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -273,7 +273,13 @@ SUBDIR_PYTHON_OBS = \
py-auto-load.o \
py-block.o \
py-breakpoint.o \
+ py-breakpointevent.o \
py-cmd.o \
+ py-continueevent.o \
+ py-event.o \
+ py-eventregistry.o \
+ py-events.o \
+ py-exitedevent.o \
py-frame.o \
py-function.o \
py-inferior.o \
@@ -283,17 +289,26 @@ SUBDIR_PYTHON_OBS = \
py-param.o \
py-prettyprint.o \
py-progspace.o \
+ py-signalevent.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-breakpointevent.c \
python/py-cmd.c \
+ python/py-continueevent.c \
+ python/py-event.c \
+ python/py-eventregistry.c \
+ python/py-events.c \
+ python/py-exitedevent.c \
python/py-frame.c \
python/py-function.c \
python/py-inferior.c \
@@ -303,6 +318,8 @@ SUBDIR_PYTHON_SRCS = \
python/py-param.c \
python/py-prettyprint.c \
python/py-progspace.c \
+ python/py-signalevent.c \
+ python/py-stopevent.c \
python/py-symbol.c \
python/py-symtab.c \
python/py-type.c \
@@ -1996,10 +2013,34 @@ py-breakpoint.o: $(srcdir)/python/py-breakpoint.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpoint.c
$(POSTCOMPILE)

+py-breakpointevent.o: $(srcdir)/python/py-breakpointevent.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpointevent.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-events.o: $(srcdir)/python/py-events.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-events.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)
@@ -2036,6 +2077,14 @@ py-progspace.o: $(srcdir)/python/py-progspace.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-progspace.c
$(POSTCOMPILE)

+py-signalevent.o: $(srcdir)/python/py-signalevent.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-signalevent.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 88d9930..f85a99b 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;

/* Number of live breakpoints. */
@@ -283,6 +280,15 @@ bppy_set_task (PyObject *self, PyObject *newvalue, void *closure)
return 0;
}

+/* Function to get the corresponding breakpoint object for the given
+ bpstats. */
+
+breakpoint_object *
+gdbpy_breakpoint_from_bpstats (struct bpstats *bs)
+{
+ return (breakpoint_object *) bs->breakpoint_at->py_bp_object;
+}
+
/* Python function which deletes the underlying GDB breakpoint. This
triggers the breakpoint_deleted observer which will call
gdbpy_breakpoint_deleted; that function cleans up the Python
diff --git a/gdb/python/py-breakpointevent.c b/gdb/python/py-breakpointevent.c
new file mode 100644
index 0000000..5e68ec0
--- /dev/null
+++ b/gdb/python/py-breakpointevent.c
@@ -0,0 +1,65 @@
+/* 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 "py-stopevent.h"
+
+static PyTypeObject breakpoint_event_object_type;
+
+static void
+breakpoint_evpy_dealloc (PyObject *self)
+{
+ Py_DECREF (((breakpoint_event_object *) self)->breakpoint);
+ stop_evpy_dealloc (self);
+}
+
+/* Create and initialize a BreakpointEvent object. */
+
+breakpoint_event_object *
+create_breakpoint_event_object (struct bpstats *bs, thread_object *stopped_thread)
+{
+ breakpoint_event_object *breakpoint_event_obj =
+ (breakpoint_event_object *)
+ create_stop_event_object (&breakpoint_event_object_type,
+ stopped_thread);
+
+ if (!breakpoint_event_obj)
+ goto fail;
+
+ breakpoint_event_obj->breakpoint = gdbpy_breakpoint_from_bpstats (bs);
+ Py_INCREF (breakpoint_event_obj->breakpoint);
+
+ if (evpy_add_attribute ((event_object *) breakpoint_event_obj,
+ "breakpoint",
+ (PyObject *) breakpoint_event_obj->breakpoint) < 0)
+ goto fail;
+
+ return breakpoint_event_obj;
+
+ fail:
+ Py_XDECREF (breakpoint_event_obj);
+ Py_XDECREF (breakpoint_event_obj->breakpoint);
+ return NULL;
+}
+
+GDBPY_NEW_EVENT_TYPE (breakpoint,
+ "gdb.BreakpointEvent",
+ "BreakpointEvent",
+ "GDB breakpoint stop event object",
+ stop_event_object_type,
+ static);
diff --git a/gdb/python/py-continueevent.c b/gdb/python/py-continueevent.c
new file mode 100644
index 0000000..9c702b6
--- /dev/null
+++ b/gdb/python/py-continueevent.c
@@ -0,0 +1,65 @@
+/* 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 "py-event.h"
+
+static PyTypeObject continue_event_object_type;
+
+typedef struct
+{
+ event_object event;
+} continue_event_object;
+
+static void
+continue_evpy_dealloc (PyObject *self)
+{
+ evpy_dealloc (self);
+}
+
+continue_event_object *
+create_continue_event_object ()
+{
+ return (continue_event_object *)
+ create_event_object (&continue_event_object_type);
+}
+
+/* Callback function which notifies observers when a continue event occurs.
+ This function will create a new Python continue event object.
+ Return -1 if emit fails. */
+
+int
+emit_continue_event (ptid_t ptid)
+{
+ event_object *event;
+ if (evregpy_get_nlisteners (gdb_py_events.cont) == 0)
+ return 0;
+
+ event = (event_object *) create_continue_event_object ();
+ if (event)
+ return evpy_emit_event (event,
+ gdb_py_events.cont);
+ return -1;
+}
+
+GDBPY_NEW_EVENT_TYPE (continue,
+ "gdb.ContinueEvent",
+ "ContinueEvent",
+ "GDB continue event object",
+ event_object_type,
+ static);
diff --git a/gdb/python/py-event.c b/gdb/python/py-event.c
new file mode 100644
index 0000000..cd9af34
--- /dev/null
+++ b/gdb/python/py-event.c
@@ -0,0 +1,179 @@
+/* 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 "py-event.h"
+
+void
+evpy_dealloc (PyObject *self)
+{
+ Py_XDECREF (((event_object *) self)->dict);
+ self->ob_type->tp_free (self);
+}
+
+event_object *
+create_event_object (PyTypeObject *py_type)
+{
+ event_object *event_obj;
+
+ event_obj = PyObject_New (event_object, py_type);
+ if (!event_obj)
+ goto fail;
+
+ event_obj->dict = PyDict_New ();
+ if (!event_obj->dict)
+ goto fail;
+
+ return event_obj;
+
+ fail:
+ Py_XDECREF (event_obj);
+ Py_XDECREF (event_obj->dict);
+ return NULL;
+}
+
+/* Add the attribute ATTR to the event object EVENT. In
+ python this attribute will be accessible by the name NAME.
+ returns 0 if the operation succeeds and -1 otherwise. */
+
+int
+evpy_add_attribute (event_object *event, char *name, PyObject *attr)
+{
+ return PyObject_SetAttrString ((PyObject *) event, name, attr);
+}
+
+/* Initialize the Python event code. */
+
+void
+gdbpy_initialize_event (void)
+{
+ gdbpy_initialize_event_generic (&event_object_type,
+ "Event");
+}
+
+/* Initialize the given event type. If BASE is not NULL it will
+ be set as the types base.
+ Returns 0 if initialization was successful -1 otherwise. */
+
+int
+gdbpy_initialize_event_generic (PyTypeObject *type,
+ char *name)
+{
+ if (PyType_Ready (type) < 0)
+ goto fail;
+
+ Py_INCREF (type);
+ if (PyModule_AddObject (gdb_module, name, (PyObject *) type) < 0)
+ goto fail;
+
+ return 0;
+
+ fail:
+ Py_XDECREF (type);
+ return -1;
+}
+
+
+/* Notify the list of listens that the given EVENT has occurred.
+ returns 0 if emit is successful -1 otherwise. */
+
+int
+evpy_emit_event (event_object *event,
+ eventregistry_object *registry)
+{
+ PyObject *callback_list, *event_obj = (PyObject *) event;
+ PyObject *callback_list_copy = NULL;
+ Py_ssize_t i;
+
+ callback_list = (PyObject *) registry->callbacks;
+
+ /* Create a copy of call back list and use that for
+ notifying listeners to avoid skipping callbacks
+ in the case of a callback being disconnected during
+ a notification. */
+ callback_list_copy = copy_py_list (callback_list);
+ if (!callback_list_copy)
+ goto fail;
+
+ for (i = 0; i < PyList_Size (callback_list_copy); i++)
+ {
+ PyObject *func = PyList_GetItem (callback_list_copy, i);
+
+ if (func == NULL)
+ goto fail;
+
+ if (!PyObject_CallFunctionObjArgs (func, event_obj, NULL))
+ {
+ /* Print the trace here, but keep going -- we want to try to
+ call all of the callbacks even if one is broken. */
+ gdbpy_print_stack ();
+ }
+ }
+
+ Py_XDECREF (callback_list_copy);
+ Py_XDECREF (event_obj);
+ return 0;
+
+ fail:
+ gdbpy_print_stack ();
+ Py_XDECREF (callback_list_copy);
+ Py_XDECREF (event_obj);
+ return -1;
+}
+
+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 */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ offsetof (event_object, dict), /* tp_dictoffset */
+ 0, /* tp_init */
+ 0 /* tp_alloc */
+};
diff --git a/gdb/python/py-event.h b/gdb/python/py-event.h
new file mode 100644
index 0000000..e46f1fe
--- /dev/null
+++ b/gdb/python/py-event.h
@@ -0,0 +1,119 @@
+/* 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/>. */
+
+#ifndef GDB_PY_EVENT_H
+#define GDB_PY_EVENT_H
+
+#include "defs.h"
+#include "py-events.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+/* This macro creates the following functions:
+
+ gdbpy_initialize_{NAME}_event
+ Used to add the newly created event type to the gdb module.
+
+ and the python type data structure for the event:
+
+ struct PyTypeObject {NAME}_event_object_type
+
+ NAME is the name of the event.
+ PY_PATH is a string representing the module and python name of
+ the event.
+ PY_NAME a string representing what the event should be called in
+ python.
+ DOC Python documentation for the new event type
+ BASE the base event for this event usually just event_object_type.
+ QUAL qualification for the create event usually 'static'
+*/
+
+#define GDBPY_NEW_EVENT_TYPE(name, py_path, py_name, doc, base, qual) \
+\
+ qual PyTypeObject name##_event_object_type = \
+ { \
+ PyObject_HEAD_INIT (NULL) \
+ 0, /* ob_size */ \
+ py_path, /* tp_name */ \
+ sizeof (name##_event_object), /* tp_basicsize */ \
+ 0, /* tp_itemsize */ \
+ name##_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 */ \
+ doc, /* 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 */ \
+ &base, /* tp_base */ \
+ 0, /* tp_dict */ \
+ 0, /* tp_descr_get */ \
+ 0, /* tp_descr_set */ \
+ 0, /* tp_dictoffset */ \
+ 0, /* tp_init */ \
+ 0 /* tp_alloc */ \
+ }; \
+\
+void \
+gdbpy_initialize_##name##_event (void) \
+{ \
+ gdbpy_initialize_event_generic (&name##_event_object_type, \
+ py_name); \
+}
+
+typedef struct
+{
+ PyObject_HEAD
+
+ PyObject *dict;
+} event_object;
+
+extern int emit_stop_event (struct bpstats *bs, const char *stop_signal);
+extern int emit_continue_event (ptid_t ptid);
+extern int emit_exited_event (LONGEST *exit_code);
+
+extern int evpy_emit_event (event_object *event,
+ eventregistry_object *registry);
+extern event_object * create_event_object (PyTypeObject *py_type);
+extern void evpy_dealloc (PyObject *self);
+extern int evpy_add_attribute (event_object *event,
+ char *name, PyObject *attr);
+int gdbpy_initialize_event_generic (PyTypeObject *type, char *name);
+
+
+#endif /* GDB_PY_EVENT_H */
diff --git a/gdb/python/py-eventregistry.c b/gdb/python/py-eventregistry.c
new file mode 100644
index 0000000..9cdc19b
--- /dev/null
+++ b/gdb/python/py-eventregistry.c
@@ -0,0 +1,169 @@
+/* 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 "py-events.h"
+
+static PyTypeObject eventregistry_object_type;
+
+/* Implementation of EventRegistry.connect () -> NULL.
+ Add FUNCTION to the list of listeners. */
+
+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;
+ }
+
+ PyList_Append (callback_list, func);
+
+ Py_RETURN_NONE;
+}
+
+/* Implementation of EventRegistry.disconnect () -> NULL.
+ Remove FUNCTION to the list of listeners. */
+
+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;
+ }
+
+ PySequence_DelItem (callback_list, PySequence_Index (callback_list, func));
+
+ Py_RETURN_NONE;
+}
+
+/* Create a new event registry. This function uses PyObject_New
+ and therefore returns a new reference that callers must handle. */
+
+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);
+}
+
+/* Retern the number of listeners currently connected to this
+ registry. */
+
+int
+evregpy_get_nlisteners (eventregistry_object *registry)
+{
+ return PyList_Size ((PyObject *) registry->callbacks);
+}
+
+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-events.c b/gdb/python/py-events.c
new file mode 100644
index 0000000..5881851
--- /dev/null
+++ b/gdb/python/py-events.c
@@ -0,0 +1,76 @@
+/* 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 "py-events.h"
+
+/* Initialize python events. */
+
+static int
+add_new_registry (eventregistry_object **registryp, char *name)
+{
+ *registryp = create_eventregistry_object ();
+ if(*registryp == NULL)
+ goto fail;
+
+ if (PyModule_AddObject (gdb_py_events.module,
+ name,
+ (PyObject *)(*registryp)) < 0)
+ goto fail;
+
+ return 0;
+
+ fail:
+ Py_XDECREF (*registryp);
+ return -1;
+}
+
+void
+gdbpy_initialize_py_events ()
+{
+
+ gdb_py_events.module = Py_InitModule ("events", NULL);
+ if (!gdb_py_events.module)
+ goto fail;
+
+ if (add_new_registry (&gdb_py_events.stop, "stop") < 0)
+ goto fail;
+
+ if (add_new_registry (&gdb_py_events.breakpoint, "breakpoint") < 0)
+ goto fail;
+
+ if (add_new_registry (&gdb_py_events.cont, "cont") < 0)
+ goto fail;
+
+ if (add_new_registry (&gdb_py_events.exited, "exited") < 0)
+ goto fail;
+
+ if (add_new_registry (&gdb_py_events.signal, "signal") < 0)
+ goto fail;
+
+ Py_INCREF (gdb_py_events.module);
+ if(PyModule_AddObject (gdb_module,
+ "events",
+ (PyObject *) gdb_py_events.module) < 0)
+ goto fail;
+
+ return;
+
+ fail:
+ gdbpy_print_stack ();
+}
diff --git a/gdb/python/py-events.h b/gdb/python/py-events.h
new file mode 100644
index 0000000..57e3f07
--- /dev/null
+++ b/gdb/python/py-events.h
@@ -0,0 +1,60 @@
+/* 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/>. */
+
+#ifndef GDB_PY_EVENTS_H
+#define GDB_PY_EVENTS_H
+
+#include "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+
+/* Stores a list of objects to be notified when the event for which this
+ registry tracks occurs. */
+
+typedef struct
+{
+ PyObject_HEAD
+
+ PyListObject *callbacks;
+} eventregistry_object;
+
+/* Struct holding references to event registries both in python and c.
+ This is meant to be a singleton. */
+
+typedef struct
+{
+ eventregistry_object *stop;
+ eventregistry_object *breakpoint;
+ eventregistry_object *signal;
+ eventregistry_object *cont;
+ eventregistry_object *exited;
+
+ PyObject *module;
+
+} events_object;
+
+/* Python events singleton. */
+events_object gdb_py_events;
+
+extern eventregistry_object *create_eventregistry_object (void);
+extern int evregpy_get_nlisteners (eventregistry_object *registry);
+
+#endif /* GDB_PY_EVENTS_H */
diff --git a/gdb/python/py-exitedevent.c b/gdb/python/py-exitedevent.c
new file mode 100644
index 0000000..6d1dcb6
--- /dev/null
+++ b/gdb/python/py-exitedevent.c
@@ -0,0 +1,88 @@
+/* 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 "py-event.h"
+
+static PyTypeObject exited_event_object_type;
+
+typedef struct
+{
+ event_object event;
+ PyLongObject *exit_code;
+} exited_event_object;
+
+static void
+exited_evpy_dealloc (PyObject *self)
+{
+ Py_DECREF (((exited_event_object *) self)->exit_code);
+ evpy_dealloc (self);
+}
+
+exited_event_object *
+create_exited_event_object (LONGEST *exit_code)
+{
+ exited_event_object *exited_event;
+
+ exited_event = (exited_event_object *)
+ create_event_object (&exited_event_object_type);
+
+ if (!exited_event)
+ goto fail;
+
+ exited_event->exit_code = (PyLongObject *) PyLong_FromLongLong (* exit_code);
+ if (evpy_add_attribute ((event_object *) exited_event,
+ "exit_code",
+ (PyObject *)exited_event->exit_code) < 0)
+ goto fail;
+
+ return exited_event;
+
+ fail:
+ Py_XDECREF (exited_event);
+ Py_XDECREF (exited_event->exit_code);
+ return NULL;
+}
+
+/* Callback that is used when an exit event occurs. This function
+ will create a new Python exited event object. */
+
+int
+emit_exited_event (LONGEST *exit_code)
+{
+ event_object *event;
+ if (evregpy_get_nlisteners (gdb_py_events.exited) == 0)
+ return 0;
+
+ event = (event_object *) create_exited_event_object (exit_code);
+
+ if (event)
+ return evpy_emit_event ((event_object *)
+ event,
+ gdb_py_events.exited);
+
+ return -1;
+}
+
+
+GDBPY_NEW_EVENT_TYPE (exited,
+ "gdb.ExitedEvent",
+ "ExitedEvent",
+ "GDB exited event object",
+ event_object_type,
+ static);
diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c
index 6382dab..681bcd1 100644
--- a/gdb/python/py-inferior.c
+++ b/gdb/python/py-inferior.c
@@ -26,6 +26,9 @@
#include "python-internal.h"
#include "arch-utils.h"
#include "language.h"
+#include "gdb_signals.h"
+#include "py-event.h"
+#include "py-stopevent.h"

struct threadlist_entry {
thread_object *thread_obj;
@@ -73,6 +76,57 @@ static PyTypeObject membuf_object_type;
} \
} while (0)

+static void
+python_on_normal_stop (struct bpstats *bs, int print_frame)
+{
+ struct cleanup *cleanup;
+ char *stop_signal;
+
+ if (!find_thread_ptid (inferior_ptid))
+ return;
+
+ stop_signal = (char *) target_signal_to_name (inferior_thread ()->suspend.stop_signal);
+
+ cleanup = ensure_python_env (get_current_arch (), current_language);
+
+ if (emit_stop_event (bs, stop_signal) < 0)
+ gdbpy_print_stack ();
+
+ do_cleanups (cleanup);
+}
+
+static void
+python_on_resume (ptid_t ptid)
+{
+ struct cleanup *cleanup;
+
+ cleanup = ensure_python_env (get_current_arch (), current_language);
+
+ if (emit_continue_event (ptid) < 0)
+ gdbpy_print_stack ();
+
+ do_cleanups (cleanup);
+}
+
+static void
+python_inferior_exit (struct inferior *inf)
+{
+ struct cleanup *cleanup;
+ LONGEST exitcode_val;
+ LONGEST *exit_code;
+
+ cleanup = ensure_python_env (get_current_arch (), current_language);
+
+ if (get_internalvar_integer (lookup_internalvar ("_exitcode"), &exitcode_val))
+ exit_code = &exitcode_val;
+
+ if (exit_code
+ && emit_exited_event (exit_code) < 0)
+ gdbpy_print_stack ();
+
+ do_cleanups (cleanup);
+}
+
/* 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. */
@@ -108,8 +162,8 @@ inferior_to_inferior_object (struct inferior *inferior)

/* Finds the Python Inferior object for the given PID. Returns a
borrowed reference, or NULL if PID does not match any inferior
- obect.
- */
+ object. */
+
PyObject *
find_inferior_object (int pid)
{
@@ -590,6 +644,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_inferior_exit (python_inferior_exit);

if (PyType_Ready (&membuf_object_type) < 0)
return;
diff --git a/gdb/python/py-signalevent.c b/gdb/python/py-signalevent.c
new file mode 100644
index 0000000..af5566f
--- /dev/null
+++ b/gdb/python/py-signalevent.c
@@ -0,0 +1,64 @@
+/* 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 "py-stopevent.h"
+
+static PyTypeObject signal_event_object_type;
+
+static void
+signal_evpy_dealloc (PyObject *self)
+{
+ Py_DECREF (((signal_event_object *) self)->stop_signal);
+ stop_evpy_dealloc (self);
+}
+
+signal_event_object *
+create_signal_event_object (const char *stop_signal,
+ thread_object *stopped_thread)
+{
+ signal_event_object *signal_event_obj =
+ (signal_event_object *)
+ create_stop_event_object (&signal_event_object_type,
+ (thread_object *) stopped_thread);
+
+ if (!signal_event_obj)
+ goto fail;
+
+ signal_event_obj->stop_signal =
+ (PyStringObject *) PyString_FromString (stop_signal);
+
+ if (evpy_add_attribute ((event_object *) signal_event_obj,
+ "stop_signal",
+ (PyObject *) signal_event_obj->stop_signal) < 0)
+ goto fail;
+
+ return signal_event_obj;
+
+ fail:
+ Py_XDECREF (signal_event_obj);
+ Py_XDECREF (signal_event_obj->stop_signal);
+ return NULL;
+}
+
+GDBPY_NEW_EVENT_TYPE (signal,
+ "gdb.SignalEvent",
+ "SignalEvent",
+ "GDB signal event object",
+ stop_event_object_type,
+ static);
diff --git a/gdb/python/py-stopevent.c b/gdb/python/py-stopevent.c
new file mode 100644
index 0000000..7d4971e
--- /dev/null
+++ b/gdb/python/py-stopevent.c
@@ -0,0 +1,135 @@
+/* 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 "py-stopevent.h"
+
+void
+stop_evpy_dealloc (PyObject *self)
+{
+ Py_XDECREF (((stop_event_object *) self)->inferior_thread);
+ evpy_dealloc (self);
+}
+
+stop_event_object *
+create_stop_event_object (PyTypeObject *py_type, thread_object *thread)
+{
+ stop_event_object *stop_event_obj =
+ (stop_event_object *) create_event_object (py_type);
+
+ if (!stop_event_obj)
+ goto fail;
+
+ stop_event_obj->inferior_thread = (PyObject *) thread;
+
+ if (evpy_add_attribute ((event_object *) stop_event_obj,
+ "inferior_thread",
+ stop_event_obj->inferior_thread) < 0)
+ goto fail;
+
+
+ return stop_event_obj;
+
+ fail:
+ Py_XDECREF (stop_event_obj);
+ Py_XDECREF (stop_event_obj->inferior_thread);
+ return NULL;
+
+}
+
+/* Callback observers when a stop event occurs. This function will create a new
+ Python stop event object. If only a specific thread is stopped the thread
+ object of the event will be set to that thread. Otherwise, if all threads
+ are stopped thread object will be set to None.
+ return 0 if the event was created and emitted successfully otherwise
+ returns -1. */
+
+int
+emit_stop_event (struct bpstats *bs, const char *stop_signal)
+{
+ thread_object *stopped_thread;
+ stop_event_object *stop_event_obj = NULL; /* Appease GCC warning. */
+ eventregistry_object *registry = NULL;
+
+ /* Stop events can either be thread specific or process wide. If gdb is
+ running in non-stop mode then the event is thread specific, otherwise
+ it is process wide. */
+ if (non_stop)
+ stopped_thread = find_thread_object (inferior_ptid);
+ else
+ stopped_thread = (thread_object *) Py_None;
+
+ if (bs && bs->breakpoint_at
+ && bs->breakpoint_at->type == bp_breakpoint)
+ {
+ if (evregpy_get_nlisteners (gdb_py_events.breakpoint) == 0)
+ return 0;
+
+ stop_event_obj =
+ (stop_event_object *)
+ create_breakpoint_event_object (bs, stopped_thread);
+ if (!stop_event_obj)
+ goto fail;
+
+ registry = gdb_py_events.breakpoint;
+ }
+
+ /* Check if the signal is "Signal 0" or "Trace/breakpoint trap". */
+ if ((strcmp (stop_signal, "0") != 0)
+ && (strcmp (stop_signal, "SIGTRAP") != 0))
+ {
+ if (evregpy_get_nlisteners (gdb_py_events.signal) == 0)
+ return 0;
+
+ stop_event_obj =
+ (stop_event_object *)
+ create_signal_event_object (stop_signal, stopped_thread);
+ if (!stop_event_obj)
+ goto fail;
+
+ registry = gdb_py_events.signal;
+ }
+
+ /* If all fails emit an unknown stop event. All event types should
+ be known and this should eventually be unused. */
+ if (!stop_event_obj)
+ {
+ if (evregpy_get_nlisteners (gdb_py_events.stop) == 0)
+ return 0;
+
+ stop_event_obj = create_stop_event_object (&stop_event_object_type,
+ (thread_object *) stopped_thread);
+ if (!stop_event_obj)
+ goto fail;
+
+ registry = gdb_py_events.stop;
+ }
+
+ return evpy_emit_event ((event_object *) stop_event_obj,
+ registry);
+
+ fail:
+ return -1;
+}
+
+GDBPY_NEW_EVENT_TYPE (stop,
+ "gdb.StopEvent",
+ "StopEvent",
+ "GDB stop event object",
+ event_object_type,
+ /*no qual*/);
diff --git a/gdb/python/py-stopevent.h b/gdb/python/py-stopevent.h
new file mode 100644
index 0000000..2d73d36
--- /dev/null
+++ b/gdb/python/py-stopevent.h
@@ -0,0 +1,58 @@
+/* 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/>. */
+
+#ifndef GDB_PY_STOPEVENT_H
+#define GDB_PY_STOPEVENT_H
+
+#include "py-event.h"
+
+typedef struct
+{
+ PyObject *inferior_thread;
+ event_object event;
+} stop_event_object;
+
+typedef struct
+{
+ stop_event_object stop_event;
+ breakpoint_object *breakpoint;
+} breakpoint_event_object;
+
+typedef struct
+{
+ stop_event_object stop_event;
+ PyStringObject *stop_signal;
+} signal_event_object;
+
+extern stop_event_object * create_stop_event_object (PyTypeObject *py_type,
+ thread_object *thread);
+extern void stop_evpy_dealloc (PyObject *self);
+
+extern int emit_stop_event (struct bpstats *bs,
+ const char *stop_signal);
+
+extern breakpoint_event_object *
+create_breakpoint_event_object (struct bpstats *bs,
+ thread_object *stopped_thread);
+
+extern signal_event_object *
+create_signal_event_object (const char *stop_signal,
+ thread_object *stopped_thread);
+
+#endif /* GDB_PY_STOPEVENT_H */
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 30d7533..a9f9f1f 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -79,6 +79,7 @@ typedef int Py_ssize_t;

/* Also needed to parse enum var_types. */
#include "command.h"
+#include "breakpoint.h"

#include "exceptions.h"

@@ -86,11 +87,18 @@ struct block;
struct value;
struct language_defn;
struct program_space;
+struct bpstats;

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 events_object_type;
+extern PyTypeObject stop_event_object_type;
+
+/* Defined in py-breakpoint.c */
+typedef struct breakpoint_object breakpoint_object;

typedef struct
{
@@ -141,6 +149,8 @@ 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);
+PyObject *inferior_to_inferior_object (struct inferior *inferior);
+breakpoint_object *gdbpy_breakpoint_from_bpstats (struct bpstats *bs);

struct block *block_object_to_block (PyObject *obj);
struct symbol *symbol_object_to_symbol (PyObject *obj);
@@ -167,12 +177,22 @@ 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_py_events (void);
+void gdbpy_initialize_stop_event (void);
+void gdbpy_initialize_signal_event (void);
+void gdbpy_initialize_breakpoint_event (void);
+void gdbpy_initialize_continue_event (void);
+void gdbpy_initialize_exited_event (void);

struct cleanup *make_cleanup_py_decref (PyObject *py);

struct cleanup *ensure_python_env (struct gdbarch *gdbarch,
const struct language_defn *language);

+PyObject *copy_py_list (PyObject *list);
+
extern struct gdbarch *python_gdbarch;
extern const struct language_defn *python_language;

diff --git a/gdb/python/python.c b/gdb/python/python.c
index d009be9..da226ad 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -162,6 +162,28 @@ compute_python_string (struct command_line *l)
return script;
}

+/* Returns a a copy of the give LIST.
+ Creates a new reference which must be handled by the caller. */
+
+PyObject *
+copy_py_list (PyObject *list)
+{
+ int i;
+
+ PyObject *new_list = PyList_New (0);
+ if (!new_list)
+ return NULL;
+
+ for (i = 0; i < PyList_Size (list); i++)
+ if (PyList_Append (new_list, PyList_GET_ITEM (list, i)) < 0)
+ {
+ Py_DECREF (new_list);
+ return NULL;
+ }
+
+ return new_list;
+}
+
/* Take a command line structure representing a 'python' command, and
evaluate its body using the Python interpreter. */

@@ -1001,6 +1023,15 @@ Enables or disables printing of Python stack traces."),
gdbpy_initialize_inferior ();
gdbpy_initialize_events ();

+ gdbpy_initialize_eventregistry ();
+ gdbpy_initialize_py_events ();
+ gdbpy_initialize_event ();
+ gdbpy_initialize_stop_event ();
+ gdbpy_initialize_signal_event ();
+ gdbpy_initialize_breakpoint_event ();
+ gdbpy_initialize_continue_event ();
+ gdbpy_initialize_exited_event ();
+
PyRun_SimpleString ("import gdb");
PyRun_SimpleString ("gdb.pretty_printers = []");

diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 0417538..2e9f64b 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2010-12-23 Sami Wagiaalla <swagiaal@redhat.com>
+
+ * gdb.python/py-events-threads.c: New file.
+ * gdb.python/py-events-threads.exp: New file.
+ * gdb.python/py-events.py: New file.
+ * gdb.python/py-events.exp: New file.
+ * gdb.python/py-events.c: New file.
+
2010-12-12 Stan Shebs <stan@codesourcery.com>

* gdb.trace/tsv.exp: Test print command on trace state variables.
diff --git a/gdb/testsuite/gdb.python/py-events-threads.c b/gdb/testsuite/gdb.python/py-events-threads.c
new file mode 100644
index 0000000..63e27f9
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-events-threads.c
@@ -0,0 +1,54 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2010 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <pthread.h>
+#include <unistd.h>
+
+pthread_t thread2_id;
+pthread_t thread3_id;
+
+void* thread3 (void* d)
+{
+ int count3 = 0;
+ count3++;
+
+ int *bad;
+ *bad = 1;
+
+ return NULL;
+}
+
+void* thread2 (void* d)
+{
+ int count2 = 0;
+ count2++;
+ return NULL;
+}
+
+int main (){
+
+ pthread_create (&thread2_id, NULL, thread2, NULL);
+ pthread_create (&thread3_id, NULL, thread3, NULL);
+
+ int count1 = 0; // stop1
+ count1++;
+
+ pthread_join (thread3_id, NULL);
+ return 12;
+}
diff --git a/gdb/testsuite/gdb.python/py-events-threads.exp b/gdb/testsuite/gdb.python/py-events-threads.exp
new file mode 100644
index 0000000..ed50d61
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-events-threads.exp
@@ -0,0 +1,89 @@
+# Copyright (C) 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite. It tests Python-based
+# pretty-printing for the CLI.
+
+# Skip all tests if Python scripting is not enabled.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+load_lib gdb-python.exp
+
+set testfile "py-events-threads"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+set pyfile ${srcdir}/${subdir}/py-events.py
+
+gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug nowarnings}
+clean_restart $testfile
+
+if { [skip_python_tests] } { continue }
+
+gdb_test_no_output "python execfile ('${pyfile}')" ""
+
+gdb_test "Test_Events" "Event testers registered."
+gdb_test_no_output "set non-stop on"
+gdb_test_no_output "set target-async on"
+
+gdb_breakpoint "main"
+gdb_breakpoint "thread2"
+gdb_breakpoint "thread3"
+
+send_gdb "run\n"
+gdb_expect {
+ -re "event type: stop.*
+.*stop reason: breakpoint.*
+.*breakpoint number: 1.*
+.*thread num: 1.*" {
+ pass "reached breakpoint 1"
+ }
+ timeout {
+ fail "did not reach breakpoint 1"
+ }
+}
+
+send_gdb "next\n"
+gdb_expect {
+ -re "event type: stop.*
+.*stop reason: breakpoint.*
+.*breakpoint number: 2.*
+.*thread num: 2.*" {
+ pass "reached breakpoint 2"
+ }
+ timeout {
+ fail "did not reach breakpoint 2"
+ }
+}
+
+send_gdb "next\n"
+gdb_expect {
+ -re "event type: stop.*
+.*stop reason: breakpoint.*
+.*breakpoint number: 3.*
+.*thread num: 3.*" {
+ pass "reached breakpoint 3"
+ }
+ timeout {
+ fail "did not reach breakpoint 3"
+ }
+}
+
+gdb_test "continue -a" ".*event type: stop.*
+.*stop reason: signal.*
+.*stop signal: SIGSEGV.*
+.*thread num: 3.*"
diff --git a/gdb/testsuite/gdb.python/py-events.c b/gdb/testsuite/gdb.python/py-events.c
new file mode 100644
index 0000000..1a5f2de
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-events.c
@@ -0,0 +1,29 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2010 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+int second(){
+ return 12;
+}
+
+int first(){
+ return second();
+}
+
+int main (){
+ return first();
+}
diff --git a/gdb/testsuite/gdb.python/py-events.exp b/gdb/testsuite/gdb.python/py-events.exp
new file mode 100644
index 0000000..52feb31
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-events.exp
@@ -0,0 +1,59 @@
+# Copyright (C) 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite. It tests Python-based
+# pretty-printing for the CLI.
+
+# Skip all tests if Python scripting is not enabled.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+load_lib gdb-python.exp
+
+set testfile "py-events"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+set pyfile ${srcdir}/${subdir}/${testfile}.py
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
+ return -1
+}
+
+if { [skip_python_tests] } { continue }
+
+gdb_test_no_output "python execfile ('${pyfile}')" ""
+
+if ![runto_main ] then {
+ fail "Can't run to main"
+ return -1
+}
+
+gdb_test "Test_Events" "Event testers registered."
+
+gdb_breakpoint "first"
+
+# Test continue event and breakpoint stop event
+gdb_test "continue" ".*event type: continue.*
+.*event type: stop.*
+.*stop reason: breakpoint.*
+.*breakpoint number: 2.*
+all threads stopped"
+
+#test exited event.
+gdb_test "continue" ".*event type: continue.*
+.*event type: exit.*
+.*exit code: 12.*"
diff --git a/gdb/testsuite/gdb.python/py-events.py b/gdb/testsuite/gdb.python/py-events.py
new file mode 100644
index 0000000..a12732a
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-events.py
@@ -0,0 +1,62 @@
+# Copyright (C) 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite. It tests python pretty
+# printers.
+import gdb
+
+def signal_stop_handler (event):
+ if (isinstance (event, gdb.StopEvent)):
+ print "event type: stop"
+ if (isinstance (event, gdb.SignalEvent)):
+ print "stop reason: signal"
+ print "stop signal: %s" % (event.stop_signal)
+ if ( event.inferior_thread is not None) :
+ print "thread num: %s" % (event.inferior_thread.num);
+
+def breakpoint_stop_handler (event):
+ if (isinstance (event, gdb.StopEvent)):
+ print "event type: stop"
+ if (isinstance (event, gdb.BreakpointEvent)):
+ print "stop reason: breakpoint"
+ print "breakpoint number: %s" % (event.breakpoint.number)
+ if ( event.inferior_thread is not None) :
+ print "thread num: %s" % (event.inferior_thread.num);
+ else:
+ print "all threads stopped"
+
+def exit_handler (event):
+ if (isinstance (event, gdb.ExitedEvent)):
+ print "event type: exit"
+ print "exit code: %d" % (event.exit_code)
+
+def continue_handler (event):
+ if (isinstance (event, gdb.ContinueEvent)):
+ print "event type: continue"
+
+class test_events (gdb.Command):
+ """Test events."""
+
+ def __init__ (self):
+ gdb.Command.__init__ (self, "test_events", gdb.COMMAND_STACK)
+
+ def invoke (self, arg, from_tty):
+ gdb.events.signal.connect (signal_stop_handler)
+ gdb.events.breakpoint.connect (breakpoint_stop_handler)
+ gdb.events.exited.connect (exit_handler)
+ gdb.events.cont.connect (continue_handler)
+ print "Event testers registered."
+
+test_events ()