From: Hui Zhu Date: Sat, 5 Feb 2011 05:27:23 +0000 (+0000) Subject: Add the file that prev commit forget. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c17a9e46882cb057d7e1d150ac9974425dc55e03;p=binutils-gdb.git Add the file that prev commit forget. --- diff --git a/gdb/NEWS b/gdb/NEWS index 234fb7be382..2e7c3e3b3ee 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -70,6 +70,14 @@ - 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 index 00000000000..c7f79654a16 --- /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 . */ + +#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 index 00000000000..1338ba6b2b4 --- /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 . */ + +#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 00000000000..88f8db63859 --- /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 . */ + +#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 00000000000..bc955210a3a --- /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 . */ + +#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 00000000000..6d4dae57c09 --- /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 . */ + +#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 00000000000..e1b4346c6b0 --- /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 . */ + +#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 00000000000..446b93411f3 --- /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 . */ + +#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 00000000000..457a4fe73eb --- /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 . */ + +#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 index 00000000000..3d7ce3229a3 --- /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 . */ + +#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 00000000000..122fe6bec38 --- /dev/null +++ b/gdb/python/py-stopevent.c @@ -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 . */ + +#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 index 00000000000..690cbbd05f7 --- /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 . */ + +#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 00000000000..7963412e085 --- /dev/null +++ b/gdb/python/py-threadevent.c @@ -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 . */ + +#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 index 00000000000..ceb697ea279 --- /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 . +*/ + +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 00000000000..e5d6daf44fe --- /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 . + +# 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 00000000000..9f05b9f03c1 --- /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 . + +# 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 00000000000..1464ce6a48e --- /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 . +*/ + +#include +#include +#include + +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 00000000000..6ea7eb40a4b --- /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 . + +# 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" + } +}