Add the file that prev commit forget.
authorHui Zhu <teawater@gmail.com>
Sat, 5 Feb 2011 05:27:23 +0000 (05:27 +0000)
committerHui Zhu <teawater@gmail.com>
Sat, 5 Feb 2011 05:27:23 +0000 (05:27 +0000)
18 files changed:
gdb/NEWS
gdb/python/py-bpevent.c [new file with mode: 0644]
gdb/python/py-continueevent.c [new file with mode: 0644]
gdb/python/py-event.c [new file with mode: 0644]
gdb/python/py-event.h [new file with mode: 0644]
gdb/python/py-events.h [new file with mode: 0644]
gdb/python/py-evtregistry.c [new file with mode: 0644]
gdb/python/py-evts.c [new file with mode: 0644]
gdb/python/py-exitedevent.c [new file with mode: 0644]
gdb/python/py-signalevent.c [new file with mode: 0644]
gdb/python/py-stopevent.c [new file with mode: 0644]
gdb/python/py-stopevent.h [new file with mode: 0644]
gdb/python/py-threadevent.c [new file with mode: 0644]
gdb/testsuite/gdb.python/py-events.c [new file with mode: 0644]
gdb/testsuite/gdb.python/py-events.exp [new file with mode: 0644]
gdb/testsuite/gdb.python/py-events.py [new file with mode: 0644]
gdb/testsuite/gdb.python/py-evthreads.c [new file with mode: 0644]
gdb/testsuite/gdb.python/py-evthreads.exp [new file with mode: 0644]

index 234fb7be382305f7a456f521da6d4f07d9ddd44c..2e7c3e3b3ee46cf9b92475cbcc14b43b40e879ce 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
      - gdb.events.exited Inferior exited event.
      - gdb.events.stop Signal received, and Breakpoint hit events.
 
+  ** 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/python/py-bpevent.c b/gdb/python/py-bpevent.c
new file mode 100644 (file)
index 0000000..c7f7965
--- /dev/null
@@ -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-continueevent.c b/gdb/python/py-continueevent.c
new file mode 100644 (file)
index 0000000..1338ba6
--- /dev/null
@@ -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 (file)
index 0000000..88f8db6
--- /dev/null
@@ -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 (file)
index 0000000..bc95521
--- /dev/null
@@ -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 (file)
index 0000000..6d4dae5
--- /dev/null
@@ -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 (file)
index 0000000..e1b4346
--- /dev/null
@@ -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 (file)
index 0000000..446b934
--- /dev/null
@@ -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 (file)
index 0000000..457a4fe
--- /dev/null
@@ -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-signalevent.c b/gdb/python/py-signalevent.c
new file mode 100644 (file)
index 0000000..3d7ce32
--- /dev/null
@@ -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 (file)
index 0000000..122fe6b
--- /dev/null
@@ -0,0 +1,92 @@
+/* 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->py_bp_object)
+    {
+      stop_event_obj = create_breakpoint_event_object ((PyObject *) bs
+                                                       ->breakpoint_at
+                                                       ->py_bp_object);
+      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 (file)
index 0000000..690cbbd
--- /dev/null
@@ -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 (file)
index 0000000..7963412
--- /dev/null
@@ -0,0 +1,78 @@
+/* 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)
+    {
+      PyErr_SetString (PyExc_RuntimeError, "Could not find event thread");
+      return NULL;
+    }
+
+  Py_INCREF (thread);
+
+  return thread;
+}
+
+PyObject *
+create_thread_event_object (PyTypeObject *py_type)
+{
+  PyObject *thread = NULL;
+  PyObject *thread_event_obj = NULL;
+
+  thread_event_obj = create_event_object (py_type);
+  if (!thread_event_obj)
+    goto fail;
+
+  thread = get_event_thread ();
+  if (!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/testsuite/gdb.python/py-events.c b/gdb/testsuite/gdb.python/py-events.c
new file mode 100644 (file)
index 0000000..ceb697e
--- /dev/null
@@ -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 (file)
index 0000000..e5d6daf
--- /dev/null
@@ -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 (file)
index 0000000..9f05b9f
--- /dev/null
@@ -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 (file)
index 0000000..1464ce6
--- /dev/null
@@ -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 (file)
index 0000000..6ea7eb4
--- /dev/null
@@ -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"
+       }
+}