This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [patch] Support inferior events in python
- From: sami wagiaalla <swagiaal at redhat dot com>
- To: Eli Zaretskii <eliz at gnu dot org>
- Cc: tromey at redhat dot com, gdb-patches at sourceware dot org
- Date: Thu, 03 Feb 2011 14:45:17 -0500
- Subject: Re: [patch] Support inferior events in python
- References: <4D2342A2.7060102@redhat.com> <m3d3oczb0t.fsf@fleche.redhat.com> <4D34AF3F.4090006@redhat.com> <m37he0g95v.fsf@fleche.redhat.com> <4D39FFFD.80304@redhat.com> <m3zkqldnlw.fsf@fleche.redhat.com> <4D49C69A.20401@redhat.com> <m3d3naf7bg.fsf@fleche.redhat.com> <4D4ADA8A.40507@redhat.com> <83sjw5asa7.fsf@gnu.org>
Made requested modifications and some other formatting fixes.
Thanks for the review.
On 02/03/2011 01:26 PM, Eli Zaretskii wrote:
Date: Thu, 03 Feb 2011 11:40:42 -0500
From: sami wagiaalla<swagiaal@redhat.com>
CC: gdb-patches@sourceware.org
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -40,6 +40,14 @@
** gdb.parameter("directories") is now available.
+ ** Python Support for Inferior events.
+ Python scripts can add observers to be notified of events
+ occurring the in process being debugged.
+ The following events are currently supported:
+ - gdb.events.cont Continue event.
+ - gdb.events.exited Inferior exited event.
+ - gdb.events.stop Signal received, and Breakpoint hit events.
+
OK for this part.
+* Events In Python:: Listening for events from GDB.
^^^
"@value{GDBN}" instead of a literal "GDB".
+GDB provides a general event facility so that Python code can be
^^^
Ditto.
+In order to be notified of an event, you must register an event handler
+with an event registry. An @dfn{event registry} is an object in the
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^
Please use @dfn when you first use the new term. In this case, in the
previous sentence.
+@defmethod EventRegistry connect callable
+Add the given callable object to the registry. This object will be called
+when an event corresponding to this registry occurs.
"callable" should have the @var markup.
+@defmethod EventRegistry disconnect callable
+Remove the given object from the registry. Once removed the object will no
^^^
Same here. And please add the missing comma after "removed".
Also, isn't it better to use "object" as the argument instead of
"callable"? How about this:
@defmethod EventRegistry connect object
Add the given callable @var{object} to the registry. This object will
be called when an event corresponding to this registry occurs.
@end defmethod
+registry @code{events.exited}. Once connected @code{exit_handler} receives
^^
A missing comma.
+notifications of exited events. The argument @dfn{event} in this example is
Hmm... "receives notifications" is not really true, is it? It gets
called when exit events happen, right?
+@item events.cont
+Emits @code{gdb.ThreadEvent}
Please add a period at the end of this sentence.
+Some events can be thread specific when GDB is running in non-stop mode. When
^^^
"@value{GDBN}"
+represented in python these events all extend @code{gdb.ThreadEvent}. Note,
^^^^^^
Should be "Python", right? And please add a comma after it.
+Emits @code{gdb.ContinueEvent} which extends @code{gdb.ThreadEvent}
A period at the end, please.
+Emits @code{gdb.StopEvent} which extends @code{gdb.ThreadEvent}
Likewise.
+Indicates that the inferior has stopped. All events emitted by this registry
+extend StopEvent. As a child of @code{gdb.ThreadEvent} @code{gdb.StopEvent}
+will indicate the stopped thread when gdb is running in non-stop mode. Refer
+to @code{gdb.ThreadEvent} above for more details.
This paragraph needs two spaces after each sentence, not one.
Also, a comma is missing here:
+extend StopEvent. As a child of @code{gdb.ThreadEvent} @code{gdb.StopEvent}
^^^
And you need to use "@value{GDBN}" again here:
+will indicate the stopped thread when gdb is running in non-stop mode. Refer
^^^
+Emits @code{gdb.SignalEvent} which extends @code{gdb.StopEvent}
Period.
+Also emits @code{gdb.BreakpointEvent} which extends @code{gdb.StopEvent}
Period.
+@end table
This "@end table" is misplaced, it should have been after this:
+@table @code
+@defivar SignalEvent stop_signal
+A string representing the signal received by the inferior. A list of possible
+signal values can be obtained by running the command @code{info signals} in
+the @value{GDBN} command prompt.
+@end defivar
OK with those changes.
Thanks.
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 002f3d2..423965f 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,32 @@
+2011-01-21 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-evtregistry.c: New file.
+ * python/py-threadevent.c : New file.
+ * python/py-event.c: New file.
+ * python/py-evts.c: New file.
+ * python/py-continueevent.c: New file.
+ * python/py-bpevent.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..f8e6cbb 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -272,8 +272,14 @@ SUBDIR_PYTHON_OBS = \
python.o \
py-auto-load.o \
py-block.o \
+ py-bpevent.o \
py-breakpoint.o \
py-cmd.o \
+ py-continueevent.o \
+ py-event.o \
+ py-evtregistry.o \
+ py-evts.o \
+ py-exitedevent.o \
py-frame.o \
py-function.o \
py-inferior.o \
@@ -283,17 +289,27 @@ 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-threadevent.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-bpevent.c \
python/py-breakpoint.c \
python/py-cmd.c \
+ python/py-continueevent.c \
+ python/py-event.c \
+ python/py-evtregistry.c \
+ python/py-evts.c \
+ python/py-exitedevent.c \
python/py-frame.c \
python/py-function.c \
python/py-inferior.c \
@@ -303,8 +319,11 @@ 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-threadevent.c \
python/py-type.c \
python/py-utils.c \
python/py-value.c
@@ -1992,6 +2011,10 @@ py-block.o: $(srcdir)/python/py-block.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-block.c
$(POSTCOMPILE)
+py-bpevent.o: $(srcdir)/python/py-bpevent.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-bpevent.c
+ $(POSTCOMPILE)
+
py-breakpoint.o: $(srcdir)/python/py-breakpoint.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpoint.c
$(POSTCOMPILE)
@@ -2000,6 +2023,26 @@ 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-evtregistry.o: $(srcdir)/python/py-evtregistry.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-evtregistry.c
+ $(POSTCOMPILE)
+
+py-evts.o: $(srcdir)/python/py-evts.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-evts.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 +2079,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)
@@ -2044,6 +2095,10 @@ py-symtab.o: $(srcdir)/python/py-symtab.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-symtab.c
$(POSTCOMPILE)
+py-threadevent.o: $(srcdir)/python/py-threadevent.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-threadevent.c
+ $(POSTCOMPILE)
+
py-type.o: $(srcdir)/python/py-type.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-type.c
$(POSTCOMPILE)
diff --git a/gdb/NEWS b/gdb/NEWS
index 559609b..d5bae34 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -40,6 +40,14 @@
** gdb.parameter("directories") is now available.
+ ** Python Support for Inferior events.
+ Python scripts can add observers to be notified of events
+ occurring the in process being debugged.
+ The following events are currently supported:
+ - gdb.events.cont Continue event.
+ - gdb.events.exited Inferior exited event.
+ - gdb.events.stop Signal received, and Breakpoint hit events.
+
* C++ Improvements:
** GDB now puts template parameters in scope when debugging in an
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index dc9630a..4ac0560 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -20700,6 +20700,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
* Selecting Pretty-Printers:: How GDB chooses a pretty-printer.
* Writing a Pretty-Printer:: Writing a Pretty-Printer.
* Inferiors In Python:: Python representation of inferiors (processes)
+* Events In Python:: Listening for events from @value{GDBN}.
* Threads In Python:: Accessing inferior threads from Python.
* Commands In Python:: Implementing new commands in Python.
* Parameters In Python:: Adding new @value{GDBN} parameters.
@@ -21792,7 +21793,7 @@ my_library.so:
@node Inferiors In Python
@subsubsection Inferiors In Python
-@cindex inferiors in python
+@cindex inferiors in Python
@findex gdb.Inferior
Programs which are being run under @value{GDBN} are called inferiors
@@ -21863,6 +21864,123 @@ the pattern could not be found.
@end defmethod
@end table
+@node Events In Python
+@subsubsection Events In Python
+@cindex inferior events in Python
+
+@value{GDBN} provides a general event facility so that Python code can be
+notified of various state changes, particularly changes that occur in
+the inferior.
+
+An @dfn{event} is just an object that describes some state change. The
+type of the object and its attributes will vary depending on the details
+of the change. All the existing events are described below.
+
+In order to be notified of an event, you must register an event handler
+with an @dfn{event registry}. An event registry is an object in the
+@code{gdb.events} module which dispatches particular events. A registry
+provides methods to register and unregister event handlers:
+
+@table @code
+@defmethod EventRegistry connect object
+Add the given callable @var{object} to the registry. This object will be
+called when an event corresponding to this registry occurs.
+@end defmethod
+
+@defmethod EventRegistry disconnect object
+Remove the given @var{object} from the registry. Once removed, the object
+will no longer receive notifications of events.
+@end defmethod
+@end table
+
+Here is an example:
+
+@smallexample
+def exit_handler (event):
+ print "event type: exit"
+ print "exit code: %d" % (event.exit_code)
+
+gdb.events.exited.connect (exit_handler)
+@end smallexample
+
+In the above example we connect our handler @code{exit_handler} to the
+registry @code{events.exited}. Once connected, @code{exit_handler} gets
+called when the inferior exits. The argument @dfn{event} in this example is
+of type @code{gdb.ExitedEvent}. As you can see in the example the
+@code{ExitedEvent} object has an attribute which indicates the exit code of
+the inferior.
+
+The following is a listing of the event registries that are available and
+details of the events they emit:
+
+@table @code
+
+@item events.cont
+Emits @code{gdb.ThreadEvent}.
+
+Some events can be thread specific when @value{GDBN} is running in non-stop
+mode. When represented in Python, these events all extend
+@code{gdb.ThreadEvent}. Note, this event is not emitted directly; instead,
+events which are emitted by this or other modules might extend this event.
+Examples of these events are @code{gdb.BreakpointEvent} and
+@code{gdb.ContinueEvent}.
+
+@table @code
+@defivar ThreadEvent inferior_thread
+In non-stop mode this attribute will be set to the specific thread which was
+involved in the emitted event. Otherwise, it will be set to @code{None}.
+@end defivar
+@end table
+
+Emits @code{gdb.ContinueEvent} which extends @code{gdb.ThreadEvent}.
+
+This event indicates that the inferior has been continued after a stop. For
+inherited attribute refer to @code{gdb.ThreadEvent} above.
+
+@item events.exited
+Emits @code{events.ExitedEvent} which indicates that the inferior has exited.
+@code{events.ExitedEvent} has one attribute:
+@table @code
+@defivar ExitedEvent exit_code
+An integer representing the exit code which the inferior has returned.
+@end defivar
+@end table
+
+@item events.stop
+Emits @code{gdb.StopEvent} which extends @code{gdb.ThreadEvent}.
+
+Indicates that the inferior has stopped. All events emitted by this registry
+extend StopEvent. As a child of @code{gdb.ThreadEvent}, @code{gdb.StopEvent}
+will indicate the stopped thread when @value{GDBN} is running in non-stop
+mode. Refer to @code{gdb.ThreadEvent} above for more details.
+
+Emits @code{gdb.SignalEvent} which extends @code{gdb.StopEvent}.
+
+This event indicates that the inferior or one of its threads has received as
+signal. @code{gdb.SignalEvent} has the following attributes:
+
+@table @code
+@defivar SignalEvent stop_signal
+A string representing the signal received by the inferior. A list of possible
+signal values can be obtained by running the command @code{info signals} in
+the @value{GDBN} command prompt.
+@end defivar
+@end table
+
+Also emits @code{gdb.BreakpointEvent} which extends @code{gdb.StopEvent}.
+
+@code{gdb.BreakpointEvent} event indicates that a breakpoint has been hit, and
+has the following attributes:
+
+@table @code
+@defivar BreakpointEvent breakpoint
+A reference to the breakpoint that was hit of type @code{gdb.Breakpoint}.
+@xref{Breakpoints In Python}, for details of the @code{gdb.Breakpoint} object.
+@end defivar
+@end table
+
+@end table
+
@node Threads In Python
@subsubsection Threads In Python
@cindex threads in python
diff --git a/gdb/python/py-bpevent.c b/gdb/python/py-bpevent.c
new file mode 100644
index 0000000..c7f7965
--- /dev/null
+++ b/gdb/python/py-bpevent.c
@@ -0,0 +1,52 @@
+/* Python interface to inferior breakpoint stop events.
+
+ Copyright (C) 2009, 2010, 2011 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;
+
+/* Create and initialize a BreakpointEvent object. */
+
+PyObject *
+create_breakpoint_event_object (PyObject *breakpoint)
+{
+ PyObject *breakpoint_event_obj =
+ create_stop_event_object (&breakpoint_event_object_type);
+
+ if (!breakpoint_event_obj)
+ goto fail;
+
+ if (evpy_add_attribute (breakpoint_event_obj,
+ "breakpoint",
+ breakpoint) < 0)
+ goto fail;
+
+ return breakpoint_event_obj;
+
+ fail:
+ Py_XDECREF (breakpoint_event_obj);
+ 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-breakpoint.c b/gdb/python/py-breakpoint.c
index 88d9930..35203e4 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. */
+
+PyObject *
+gdbpy_breakpoint_from_bpstats (struct bpstats *bs)
+{
+ return (PyObject *) 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-continueevent.c b/gdb/python/py-continueevent.c
new file mode 100644
index 0000000..1338ba6
--- /dev/null
+++ b/gdb/python/py-continueevent.c
@@ -0,0 +1,53 @@
+/* Python interface to inferior continue events.
+
+ Copyright (C) 2009, 2010, 2011 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;
+
+PyObject *
+create_continue_event_object (void)
+{
+ return create_thread_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)
+{
+ PyObject *event;
+
+ if (evregpy_no_listeners_p (gdb_py_events.cont))
+ return 0;
+
+ event = 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",
+ thread_event_object_type,
+ static);
diff --git a/gdb/python/py-event.c b/gdb/python/py-event.c
new file mode 100644
index 0000000..88f8db6
--- /dev/null
+++ b/gdb/python/py-event.c
@@ -0,0 +1,175 @@
+/* Python interface to inferior events.
+
+ Copyright (C) 2009, 2010, 2011 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);
+}
+
+PyObject *
+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 (PyObject*) event_obj;
+
+ fail:
+ Py_XDECREF (event_obj);
+ 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 (PyObject *event, char *name, PyObject *attr)
+{
+ return PyObject_SetAttrString (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 (PyObject *event,
+ eventregistry_object *registry)
+{
+ PyObject *callback_list_copy = NULL;
+ Py_ssize_t i;
+
+ /* 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 = PySequence_List (registry->callbacks);
+ 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, 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);
+ return 0;
+
+ fail:
+ gdbpy_print_stack ();
+ Py_XDECREF (callback_list_copy);
+ Py_XDECREF (event);
+ 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..bc95521
--- /dev/null
+++ b/gdb/python/py-event.h
@@ -0,0 +1,121 @@
+/* Python interface to inferior events.
+
+ Copyright (C) 2009, 2010, 2011 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 (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 */ \
+ 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_continue_event (ptid_t ptid);
+extern int emit_exited_event (LONGEST exit_code);
+
+extern int evpy_emit_event (PyObject *event,
+ eventregistry_object *registry);
+
+extern PyObject *create_event_object (PyTypeObject *py_type);
+extern PyObject *create_thread_event_object (PyTypeObject *py_type);
+
+extern void evpy_dealloc (PyObject *self);
+extern int evpy_add_attribute (PyObject *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-events.h b/gdb/python/py-events.h
new file mode 100644
index 0000000..6d4dae5
--- /dev/null
+++ b/gdb/python/py-events.h
@@ -0,0 +1,59 @@
+/* Python interface to inferior events.
+
+ Copyright (C) 2009, 2010, 2011 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"
+
+extern PyTypeObject thread_event_object_type;
+
+/* Stores a list of objects to be notified when the event for which this
+ registry tracks occurs. */
+
+typedef struct
+{
+ PyObject_HEAD
+
+ PyObject *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 *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_no_listeners_p (eventregistry_object *registry);
+
+#endif /* GDB_PY_EVENTS_H */
diff --git a/gdb/python/py-evtregistry.c b/gdb/python/py-evtregistry.c
new file mode 100644
index 0000000..e1b4346
--- /dev/null
+++ b/gdb/python/py-evtregistry.c
@@ -0,0 +1,170 @@
+/* Python interface to inferior thread event registries.
+
+ Copyright (C) 2009, 2010, 2011 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 = (((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;
+ }
+
+ if (PyList_Append (callback_list, func) < 0)
+ return NULL;
+
+ Py_RETURN_NONE;
+}
+
+/* Implementation of EventRegistry.disconnect () -> NULL.
+ Remove FUNCTION from the list of listeners. */
+
+static PyObject *
+evregpy_disconnect (PyObject *self, PyObject *function)
+{
+ PyObject *func;
+ int index;
+ PyObject *callback_list = (((eventregistry_object *) self)->callbacks);
+
+ if (!PyArg_ParseTuple (function, "O", &func))
+ return NULL;
+
+ index = PySequence_Index (callback_list, func);
+ if (index < 0)
+ Py_RETURN_NONE;
+
+ if (PySequence_DelItem (callback_list, index) < 0)
+ return NULL;
+
+ 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 = PyList_New (0);
+ if (!eventregistry_obj->callbacks)
+ return NULL;
+
+ return eventregistry_obj;
+}
+
+static void
+evregpy_dealloc (PyObject *self)
+{
+ Py_XDECREF (((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_no_listeners_p (eventregistry_object *registry)
+{
+ return PyList_Size (registry->callbacks) == 0;
+}
+
+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-evts.c b/gdb/python/py-evts.c
new file mode 100644
index 0000000..446b934
--- /dev/null
+++ b/gdb/python/py-evts.c
@@ -0,0 +1,71 @@
+/* Python interface to inferior events.
+
+ Copyright (C) 2009, 2010, 2011 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.cont, "cont") < 0)
+ goto fail;
+
+ if (add_new_registry (&gdb_py_events.exited, "exited") < 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-exitedevent.c b/gdb/python/py-exitedevent.c
new file mode 100644
index 0000000..457a4fe
--- /dev/null
+++ b/gdb/python/py-exitedevent.c
@@ -0,0 +1,71 @@
+/* Python interface to inferior exit events.
+
+ Copyright (C) 2009, 2010, 2011 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;
+
+PyObject *
+create_exited_event_object (LONGEST exit_code)
+{
+ PyObject *exited_event;
+
+ exited_event = create_event_object (&exited_event_object_type);
+
+ if (!exited_event)
+ goto fail;
+
+ if (evpy_add_attribute (exited_event,
+ "exit_code",
+ PyLong_FromLongLong (exit_code)) < 0)
+ goto fail;
+
+ return exited_event;
+
+ fail:
+ Py_XDECREF (exited_event);
+ 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)
+{
+ PyObject *event;
+
+ if (evregpy_no_listeners_p (gdb_py_events.exited))
+ return 0;
+
+ event = create_exited_event_object (exit_code);
+
+ if (event)
+ return evpy_emit_event (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..ef05dca 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,59 @@ static PyTypeObject membuf_object_type;
} \
} while (0)
+static void
+python_on_normal_stop (struct bpstats *bs, int print_frame)
+{
+ struct cleanup *cleanup;
+ enum target_signal stop_signal;
+
+ if (!find_thread_ptid (inferior_ptid))
+ return;
+
+ stop_signal = 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 exit_code = -1;
+ ptid_t ptidp;
+ struct target_waitstatus status;
+
+ cleanup = ensure_python_env (get_current_arch (), current_language);
+
+ get_last_target_status (&ptidp, &status);
+
+ exit_code = status.value.integer;
+
+ if (exit_code >= 0
+ && 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 +164,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 +646,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..3d7ce32
--- /dev/null
+++ b/gdb/python/py-signalevent.c
@@ -0,0 +1,53 @@
+/* Python interface to inferior signal stop events.
+
+ Copyright (C) 2009, 2010, 2011 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;
+
+PyObject *
+create_signal_event_object (enum target_signal stop_signal)
+{
+ const char *signal_name;
+ PyObject *signal_event_obj =
+ create_stop_event_object (&signal_event_object_type);
+
+ if (!signal_event_obj)
+ goto fail;
+
+ signal_name = target_signal_to_name (stop_signal);
+
+ if (evpy_add_attribute (signal_event_obj,
+ "stop_signal",
+ PyString_FromString (signal_name)) < 0)
+ goto fail;
+
+ return signal_event_obj;
+
+ fail:
+ Py_XDECREF (signal_event_obj);
+ 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..514dfb3
--- /dev/null
+++ b/gdb/python/py-stopevent.c
@@ -0,0 +1,95 @@
+/* Python interface to inferior stop events.
+
+ Copyright (C) 2009, 2010, 2011 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"
+
+PyObject *
+create_stop_event_object (PyTypeObject *py_type)
+{
+ PyObject *stop_event_obj = create_thread_event_object (py_type);
+
+ if (!stop_event_obj)
+ goto fail;
+
+ return stop_event_obj;
+
+ fail:
+ Py_XDECREF (stop_event_obj);
+ 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, enum target_signal stop_signal)
+{
+ PyObject *stop_event_obj = NULL; /* Appease GCC warning. */
+
+ if (evregpy_no_listeners_p (gdb_py_events.stop))
+ return 0;
+
+ if (bs && bs->breakpoint_at
+ && bs->breakpoint_at->type == bp_breakpoint)
+ {
+ PyObject *breakpoint = gdbpy_breakpoint_from_bpstats (bs);
+ if (breakpoint != NULL)
+ {
+ stop_event_obj =
+ create_breakpoint_event_object (breakpoint);
+ if (!stop_event_obj)
+ goto fail;
+ }
+ }
+
+ /* Check if the signal is "Signal 0" or "Trace/breakpoint trap". */
+ if (stop_signal != TARGET_SIGNAL_0
+ && stop_signal != TARGET_SIGNAL_TRAP)
+ {
+ stop_event_obj =
+ create_signal_event_object (stop_signal);
+ if (!stop_event_obj)
+ goto fail;
+ }
+
+ /* If all fails emit an unknown stop event. All event types should
+ be known and this should eventually be unused. */
+ if (!stop_event_obj)
+ {
+ stop_event_obj = create_stop_event_object (&stop_event_object_type);
+ if (!stop_event_obj)
+ goto fail;
+ }
+
+ return evpy_emit_event (stop_event_obj, gdb_py_events.stop);
+
+ fail:
+ return -1;
+}
+
+GDBPY_NEW_EVENT_TYPE (stop,
+ "gdb.StopEvent",
+ "StopEvent",
+ "GDB stop event object",
+ thread_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..690cbbd
--- /dev/null
+++ b/gdb/python/py-stopevent.h
@@ -0,0 +1,37 @@
+/* Python interface to inferior events.
+
+ Copyright (C) 2009, 2010, 2011 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"
+
+extern PyObject *create_stop_event_object (PyTypeObject *py_type);
+extern void stop_evpy_dealloc (PyObject *self);
+
+extern int emit_stop_event (struct bpstats *bs,
+ enum target_signal stop_signal);
+
+extern PyObject *
+create_breakpoint_event_object (PyObject *breakpoint);
+
+extern PyObject *
+create_signal_event_object (enum target_signal stop_signal);
+
+#endif /* GDB_PY_STOPEVENT_H */
diff --git a/gdb/python/py-threadevent.c b/gdb/python/py-threadevent.c
new file mode 100644
index 0000000..1123706
--- /dev/null
+++ b/gdb/python/py-threadevent.c
@@ -0,0 +1,71 @@
+/* Copyright (C) 2009, 2010, 2011 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"
+
+/* thread 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.
+ This function returns the currently stopped thread in non-stop mode and
+ Py_None otherwise. */
+
+static PyObject *
+get_event_thread (void)
+{
+ PyObject *thread = NULL;
+
+ if (non_stop)
+ thread = (PyObject *) find_thread_object (inferior_ptid);
+ else
+ thread = Py_None;
+
+ if (!thread)
+ return NULL;
+
+ Py_INCREF (thread);
+
+ return thread;
+}
+
+PyObject *
+create_thread_event_object (PyTypeObject *py_type)
+{
+ PyObject *thread_event_obj = create_event_object (py_type);
+ PyObject *thread = get_event_thread();
+
+ if (!thread_event_obj || !thread)
+ goto fail;
+
+ if (evpy_add_attribute (thread_event_obj,
+ "inferior_thread",
+ thread) < 0)
+ goto fail;
+
+ return thread_event_obj;
+
+ fail:
+ Py_XDECREF (thread_event_obj);
+ return NULL;
+
+}
+
+GDBPY_NEW_EVENT_TYPE (thread,
+ "gdb.ThreadEvent",
+ "ThreadEvent",
+ "GDB thread event object",
+ event_object_type,
+ /*no qual*/);
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 30d7533..8fcdca2 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);
+PyObject *gdbpy_breakpoint_from_bpstats (struct bpstats *bs);
struct block *block_object_to_block (PyObject *obj);
struct symbol *symbol_object_to_symbol (PyObject *obj);
@@ -167,6 +177,15 @@ 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);
+void gdbpy_initialize_thread_event (void);
struct cleanup *make_cleanup_py_decref (PyObject *py);
diff --git a/gdb/python/python.c b/gdb/python/python.c
index d009be9..46eed8b 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1001,6 +1001,16 @@ 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 ();
+ gdbpy_initialize_thread_event ();
+
PyRun_SimpleString ("import gdb");
PyRun_SimpleString ("gdb.pretty_printers = []");
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 0417538..f285c8c 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2011-01-21 Sami Wagiaalla <swagiaal@redhat.com>
+
+ * gdb.python/py-evthreads.c: New file.
+ * gdb.python/py-evthreads.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.c b/gdb/testsuite/gdb.python/py-events.c
new file mode 100644
index 0000000..ceb697e
--- /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, 2011 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..e5d6daf
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-events.exp
@@ -0,0 +1,59 @@
+# Copyright (C) 2010, 2011 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..9f05b9f
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-events.py
@@ -0,0 +1,64 @@
+# Copyright (C) 2010, 2011 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"
+ if ( event.inferior_thread is not None) :
+ print "thread num: %s" % (event.inferior_thread.num);
+
+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.stop.connect (signal_stop_handler)
+ gdb.events.stop.connect (breakpoint_stop_handler)
+ gdb.events.exited.connect (exit_handler)
+ gdb.events.cont.connect (continue_handler)
+ print "Event testers registered."
+
+test_events ()
diff --git a/gdb/testsuite/gdb.python/py-evthreads.c b/gdb/testsuite/gdb.python/py-evthreads.c
new file mode 100644
index 0000000..1464ce6
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-evthreads.c
@@ -0,0 +1,55 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2010, 2011 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 (thread2_id, NULL);
+ pthread_join (thread3_id, NULL);
+ return 12;
+}
diff --git a/gdb/testsuite/gdb.python/py-evthreads.exp b/gdb/testsuite/gdb.python/py-evthreads.exp
new file mode 100644
index 0000000..6ea7eb4
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-evthreads.exp
@@ -0,0 +1,119 @@
+# Copyright (C) 2010, 2011 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-evthreads"
+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"
+ }
+}
+
+send_gdb "continue&\n"
+gdb_expect {
+ -re ".*event type: continue.*
+.*thread num: 1.*" {
+ pass "continue thread 1"
+ }
+ timeout {
+ fail "continue thread 1 failed"
+ }
+}
+
+gdb_test "thread 2" ".*Switching to thread 2.*"
+send_gdb "continue&\n"
+gdb_expect {
+ -re ".*event type: continue.*
+.*thread num: 2.*" {
+ pass "continue thread 2"
+ }
+ timeout {
+ fail "continue thread 2 failed"
+ }
+}
+
+send_gdb "continue -a\n"
+gdb_expect {
+ -re ".*stop reason: signal.*
+.*stop signal: SIGSEGV.*
+.*thread num: 3.*" {
+ pass "thread 3 was signalled"
+ }
+ timeout {
+ fail "thread 3 was not signalled"
+ }
+}