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 + Oguz Kayral + + * 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 * 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 . */ + +#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 . */ + +#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 . */ + +#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 . */ + +#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 . */ + +#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 . */ + +#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 . */ + +#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 . */ + +#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 . */ + +#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 . */ + +#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 . */ + +#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 . */ + +#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 + + * 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 * 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 . +*/ + +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 . + +# 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 . + +# 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 . +*/ + +#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 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 . + +# 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" + } +}