From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 2178 invoked by alias); 13 Aug 2010 14:54:47 -0000 Mailing-List: contact archer-help@sourceware.org; run by ezmlm Sender: Precedence: bulk List-Post: List-Help: List-Subscribe: List-Id: Received: (qmail 2140 invoked by uid 22791); 13 Aug 2010 14:54:40 -0000 X-SWARE-Spam-Status: No, hits=-4.1 required=5.0 tests=AWL,BAYES_50,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,TW_HP,T_FILL_THIS_FORM_SHORT,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Message-ID: <4C655CA0.8010205@redhat.com> Date: Fri, 13 Aug 2010 14:54:00 -0000 From: Phil Muldoon User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.7) Gecko/20100720 Fedora/3.1.1-1.fc13 Thunderbird/3.1.1 MIME-Version: 1.0 To: archer@sourceware.org, oguzkayral@gmail.com Subject: Python inferior control Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-SW-Source: 2010-q3/txt/msg00110.txt.bz2 Hi, On the 23rd of August 2009 Oguz Kayral submitted an initial patch to implement GDB inferior notification events in Python. Since then the patch has bit-rotted somewhat. I've reconstituted this patch against current GDB head and attached it. I've not changed very much: renamed the files, re-ordered the Makefile.in and made some minor code changes so that it compiles. Why am I doing this? Firstly as a historical context. Oguz's patches were a series of patches and also emails containing code in-line and not in patch format. This patch unifies this (though I left out the examples, as they cannot belong in the CVS tree at the moment). I'll reconstitute the ChangeLogs when we submit this code upstream. Secondly, I am planning on working on this patch/code: improving, adding and eventually submitting it upstream. As the patch that Oguz wrote is substantial enough to give a general thrust of the design intentions I thought it would be a good idea to re-spark any conversations before I work on this code. So if there any ideas, let's here them! Cheers Phil -- diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 65eb1fe..33cccd9 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -272,7 +272,12 @@ SUBDIR_PYTHON_OBS = \ py-auto-load.o \ py-block.o \ py-breakpoint.o \ + py-breakpointstopevent.o \ py-cmd.o \ + py-continueevent.o \ + py-event.o \ + py-eventregistry.o \ + py-exitedevent.o \ py-frame.o \ py-function.o \ py-inferior.o \ @@ -282,17 +287,25 @@ SUBDIR_PYTHON_OBS = \ py-param.o \ py-prettyprint.o \ py-progspace.o \ + py-signalstopevent.o \ + py-stopevent.o \ py-symbol.o \ py-symtab.o \ py-type.o \ py-utils.o \ py-value.o + SUBDIR_PYTHON_SRCS = \ python/python.c \ python/py-auto-load.c \ python/py-block.c \ python/py-breakpoint.c \ + python/py-breakpointstopevent.c \ python/py-cmd.c \ + python/py-continueevent.c \ + python/py-event.c \ + python/py-eventregistry.c \ + python/py-exitedevent.c \ python/py-frame.c \ python/py-function.c \ python/py-inferior.c \ @@ -302,6 +315,8 @@ SUBDIR_PYTHON_SRCS = \ python/py-param.c \ python/py-prettyprint.c \ python/py-progspace.c \ + python/py-signalstopevent.c \ + python/py-stopevent.c \ python/py-symbol.c \ python/py-symtab.c \ python/py-type.c \ @@ -2010,10 +2025,30 @@ py-breakpoint.o: $(srcdir)/python/py-breakpoint.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpoint.c $(POSTCOMPILE) +py-breakpointstopevent.o: $(srcdir)/python/py-breakpointstopevent.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpointstopevent.c + $(POSTCOMPILE) + py-cmd.o: $(srcdir)/python/py-cmd.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-cmd.c $(POSTCOMPILE) +py-continueevent.o: $(srcdir)/python/py-continueevent.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-continueevent.c + $(POSTCOMPILE) + +py-event.o: $(srcdir)/python/py-event.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-event.c + $(POSTCOMPILE) + +py-eventregistry.o: $(srcdir)/python/py-eventregistry.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-eventregistry.c + $(POSTCOMPILE) + +py-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) @@ -2050,6 +2085,14 @@ py-progspace.o: $(srcdir)/python/py-progspace.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-progspace.c $(POSTCOMPILE) +py-signalstopevent.o: $(srcdir)/python/py-signalstopevent.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-signalstopevent.c + $(POSTCOMPILE) + +py-stopevent.o: $(srcdir)/python/py-stopevent.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-stopevent.c + $(POSTCOMPILE) + py-symbol.o: $(srcdir)/python/py-symbol.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-symbol.c $(POSTCOMPILE) diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c index 14f0417..d00048a 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; /* A dynamically allocated vector of breakpoint objects. Each @@ -52,18 +49,6 @@ static int bppy_live; constructor and the breakpoint-created hook function. */ static breakpoint_object *bppy_pending_object; -struct breakpoint_object -{ - PyObject_HEAD - - /* The breakpoint number according to gdb. */ - int number; - - /* The gdb breakpoint object, or NULL if the breakpoint has been - deleted. */ - struct breakpoint *bp; -}; - /* Require that BREAKPOINT be a valid breakpoint ID; throw a Python exception if it is invalid. */ #define BPPY_REQUIRE_VALID(Breakpoint) \ @@ -626,6 +611,34 @@ bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs) return result; } +/* Function to get the corresponding breakpoint object for the given + bpstats. */ + +breakpoint_object * +gdbpy_breakpoint_from_bpstats (struct bpstats *bs) +{ + int i, out = 0; + breakpoint_object *breakpoint = NULL; + + if (bppy_live == 0) + return NULL; + + for (i = 0; out < bppy_live; i++) + { + if (! bppy_breakpoints[i]) + continue; + + if (bs->breakpoint_at == bppy_breakpoints[i]->bp->loc) + breakpoint = bppy_breakpoints[i]; + + ++out; + } + + return breakpoint; +} + + + /* Static function to return a tuple holding all breakpoints. */ diff --git a/gdb/python/py-breakpointstopevent.c b/gdb/python/py-breakpointstopevent.c new file mode 100644 index 0000000..b63df7b --- /dev/null +++ b/gdb/python/py-breakpointstopevent.c @@ -0,0 +1,166 @@ +/* Python interface to inferior breakpoint stop events. + + Copyright (C) 2009, 2010 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "command.h" +#include "python-internal.h" +#include "inferior.h" + +static PyTypeObject breakpoint_stop_event_object_type; + +typedef struct +{ + stop_event_object stop_event; + breakpoint_object *breakpoint; +} breakpoint_stop_event_object; + +static void +bp_stop_evpy_dealloc (PyObject *self) +{ + Py_DECREF (((breakpoint_stop_event_object *) self)->breakpoint); + self->ob_type->tp_free (self); +} + +/* Python function to get the stop event's breakpoint. */ +static PyObject * +bp_stop_evpy_get_breakpoint (PyObject *self, void *closure) +{ + breakpoint_stop_event_object *breakpoint_stop_event_obj = +(breakpoint_stop_event_object *) self; + + Py_INCREF (breakpoint_stop_event_obj->breakpoint); + + return (PyObject *) (breakpoint_stop_event_obj->breakpoint); +} + +breakpoint_stop_event_object * +create_breakpoint_stop_event_object (breakpoint_object *bp) +{ + breakpoint_stop_event_object *breakpoint_stop_event_obj; + + breakpoint_stop_event_obj = PyObject_New +(breakpoint_stop_event_object, &breakpoint_stop_event_object_type); + if (!breakpoint_stop_event_obj) + return NULL; + + breakpoint_stop_event_obj->stop_event.event.inferior_thread = +find_thread_object (inferior_ptid); + Py_INCREF (breakpoint_stop_event_obj->stop_event.event.inferior_thread); + breakpoint_stop_event_obj->stop_event.event.event_type = +(PyStringObject *) PyString_FromString ("stop"); + breakpoint_stop_event_obj->stop_event.stop_reason = (PyStringObject +*) PyString_FromString ("breakpoint"); + breakpoint_stop_event_obj->breakpoint = bp; + Py_INCREF (breakpoint_stop_event_obj->breakpoint); + + return breakpoint_stop_event_obj; +} + +/* Initialize the Python breakpoint stop event code. */ +void +gdbpy_initialize_breakpoint_stop_event (void) +{ + breakpoint_stop_event_object_type.tp_base = &stop_event_object_type; + if (PyType_Ready (&breakpoint_stop_event_object_type) < 0) + return; + + Py_INCREF (&breakpoint_stop_event_object_type); + PyModule_AddObject (gdb_module, "BreakpointStopEvent", (PyObject *) +&breakpoint_stop_event_object_type); +} + +/* Callback that is used when a stop event occurs. This function will +create a new Python breakpoint stop event object. */ +void +emit_breakpoint_stop_event (struct bpstats *bs) +{ + thread_object *inferior_thread; + PyObject *callback_list; + PyObject *args_tuple; + Py_ssize_t i; + breakpoint_object *breakpoint; + breakpoint_stop_event_object *breakpoint_stop_event_obj; + + inferior_thread = find_thread_object (inferior_ptid); + + breakpoint = gdbpy_breakpoint_from_bpstats (bs); + + breakpoint_stop_event_obj = create_breakpoint_stop_event_object (breakpoint); + + callback_list = (PyObject *) +(inferior_thread->breakpoint_stop_eventregistry->callbacks); + + args_tuple = PyTuple_New ((Py_ssize_t) 1); + PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *) +breakpoint_stop_event_obj); + + for (i = 0; i < PyList_Size (callback_list); i++) + { + PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple); + } +} + +static PyGetSetDef breakpoint_stop_event_object_getset[] = +{ + { "breakpoint", bp_stop_evpy_get_breakpoint, NULL, "Breakpoint.", NULL }, + + { NULL } /* Sentinel. */ +}; + +static PyTypeObject breakpoint_stop_event_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /* ob_size */ + "gdb.BreakpointStopEvent", /* tp_name */ + sizeof (breakpoint_stop_event_object), /* tp_basicsize */ + 0, /* tp_itemsize */ + bp_stop_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, /* tp_flags */ + "GDB breakpoint stop 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 */ + breakpoint_stop_event_object_getset, /* 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-continueevent.c b/gdb/python/py-continueevent.c new file mode 100644 index 0000000..f80d9ac --- /dev/null +++ b/gdb/python/py-continueevent.c @@ -0,0 +1,138 @@ +/* Python interface to inferior continue events. + + Copyright (C) 2009, 2010 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "command.h" +#include "python-internal.h" +#include "inferior.h" + +static PyTypeObject continue_event_object_type; + +typedef struct +{ + event_object event; +} continue_event_object; + +static void +continue_evpy_dealloc (PyObject *self) +{ + self->ob_type->tp_free (self); +} + +continue_event_object * +create_continue_event_object () +{ + continue_event_object *continue_event_obj; + + continue_event_obj = PyObject_New (continue_event_object, +&continue_event_object_type); + + if (!continue_event_obj) + return NULL; + + continue_event_obj->event.inferior_thread = find_thread_object +(inferior_ptid); + Py_INCREF (continue_event_obj->event.inferior_thread); + continue_event_obj->event.event_type = (PyStringObject *) +PyString_FromString ("continue"); + + return continue_event_obj; +} + +/* Initialize the Python continue event code. */ +void +gdbpy_initialize_continue_event (void) +{ + continue_event_object_type.tp_base = &event_object_type; + if (PyType_Ready (&continue_event_object_type) < 0) + return; + + Py_INCREF (&continue_event_object_type); + PyModule_AddObject (gdb_module, "ContinueEvent", (PyObject *) +&continue_event_object_type); +} + +/* Callback that is used when a continue event occurs. This function + will create a new Python continue event object. */ +void +emit_continue_event (ptid_t ptid) +{ + thread_object *inferior_thread; + PyObject *callback_list; + PyObject *args_tuple; + Py_ssize_t i; + continue_event_object *continue_event_obj; + + inferior_thread = find_thread_object (inferior_ptid); + + continue_event_obj = create_continue_event_object(); + + callback_list = (PyObject *) +(inferior_thread->continue_eventregistry->callbacks); + + args_tuple = PyTuple_New ((Py_ssize_t) 1); + PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *) continue_event_obj); + + for (i = 0; i < PyList_Size (callback_list); i++) + { + PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple); + } +} + +static PyTypeObject continue_event_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /* ob_size */ + "gdb.ContinueEvent", /* tp_name */ + sizeof (continue_event_object), /* tp_basicsize */ + 0, /* tp_itemsize */ + continue_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, /* tp_flags */ + "GDB continue 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 */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0 /* tp_alloc */ +}; diff --git a/gdb/python/py-event.c b/gdb/python/py-event.c new file mode 100644 index 0000000..7394ded --- /dev/null +++ b/gdb/python/py-event.c @@ -0,0 +1,130 @@ +/* Python interface to inferior events. + + Copyright (C) 2009, 2010 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "command.h" +#include "python-internal.h" +#include "inferior.h" + +event_object * +create_event_object (const char *event_type) +{ + event_object *event_obj; + + event_obj = PyObject_New (event_object, &event_object_type); + if (!event_obj) + return NULL; + + event_obj->inferior_thread = find_thread_object (inferior_ptid); + Py_INCREF (event_obj->inferior_thread); + event_obj->event_type = (PyStringObject *) PyString_FromString (event_type); + + return event_obj; +} + +static void +evpy_dealloc (PyObject *self) +{ + Py_DECREF (((event_object *) self)->inferior_thread); + self->ob_type->tp_free (self); +} + +/* Python function to get the event's thread. */ +static PyObject * +evpy_get_inferior_thread (PyObject *self, void *closure) +{ + event_object *event_obj = (event_object *) self; + + Py_INCREF (event_obj->inferior_thread); + + return (PyObject *) (event_obj->inferior_thread); +} + +/* Python function to get the event's type. */ +static PyObject * +evpy_get_event_type (PyObject *self, void *closure) +{ + event_object *event_obj = (event_object *) self; + + Py_INCREF (event_obj->event_type); + + return (PyObject *) (event_obj->event_type); +} + +/* Initialize the Python event code. */ +void +gdbpy_initialize_event (void) +{ + if (PyType_Ready (&event_object_type) < 0) + return; + + Py_INCREF (&event_object_type); + PyModule_AddObject (gdb_module, "Event", (PyObject *) &event_object_type); +} + +static PyGetSetDef event_object_getset[] = +{ + { "inferior_thread", evpy_get_inferior_thread, NULL, + "Inferior thread.", NULL }, + { "event_type", evpy_get_event_type, NULL, "Event type.", NULL }, + + { NULL } /* Sentinel. */ +}; + +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 */ + event_object_getset, /* 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-eventregistry.c b/gdb/python/py-eventregistry.c new file mode 100644 index 0000000..c1aa7b4 --- /dev/null +++ b/gdb/python/py-eventregistry.c @@ -0,0 +1,155 @@ +/* Python interface to inferior thread event registries. + + Copyright (C) 2009, 2010 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "command.h" +#include "python-internal.h" + +static PyTypeObject eventregistry_object_type; + +/* Implementation of EventRegistry.connect () -> NULL */ +static PyObject * +evregpy_connect (PyObject *self, PyObject *function) +{ + PyObject *func; + PyObject *callback_list = (PyObject *) (((eventregistry_object *) +self)->callbacks); + + if (!PyArg_ParseTuple (function, "O", &func)) + return NULL; + + if (!PyCallable_Check (func)) + { + PyErr_SetString (PyExc_RuntimeError, "Function is not callable"); + return NULL; + } + + Py_INCREF (func); + + PyList_Append (callback_list, func); + + Py_RETURN_NONE; +} + +/* Implementation of EventRegistry.disconnect () -> NULL */ +static PyObject * +evregpy_disconnect (PyObject *self, PyObject *function) +{ + PyObject *func; + PyObject *callback_list = (PyObject *) (((eventregistry_object *) +self)->callbacks); + + if (!PyArg_ParseTuple (function, "O", &func)) + return NULL; + + if (!PyCallable_Check (func)) + { + PyErr_SetString (PyExc_RuntimeError, "Function is not callable"); + return NULL; + } + + Py_INCREF (func); + + PySequence_DelItem (callback_list, PySequence_Index (callback_list, func)); + + Py_RETURN_NONE; +} + +eventregistry_object * +create_eventregistry_object (void) +{ + eventregistry_object *eventregistry_obj; + + eventregistry_obj = PyObject_New (eventregistry_object, +&eventregistry_object_type); + if (!eventregistry_obj) + return NULL; + + eventregistry_obj->callbacks = (PyListObject *) PyList_New (0); + + return eventregistry_obj; +} + +static void +evregpy_dealloc (PyObject *self) +{ + Py_DECREF (((eventregistry_object *) self)->callbacks); + self->ob_type->tp_free (self); +} + +/* Initialize the Python event registry code. */ +void +gdbpy_initialize_eventregistry (void) +{ + if (PyType_Ready (&eventregistry_object_type) < 0) + return; + + Py_INCREF (&eventregistry_object_type); + PyModule_AddObject (gdb_module, "EventRegistry", (PyObject *) +&eventregistry_object_type); +} + +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-exitedevent.c b/gdb/python/py-exitedevent.c new file mode 100644 index 0000000..d2a1d88 --- /dev/null +++ b/gdb/python/py-exitedevent.c @@ -0,0 +1,156 @@ +/* Python interface to inferior exit events. + + Copyright (C) 2009, 2010 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "command.h" +#include "python-internal.h" +#include "inferior.h" + +static PyTypeObject exited_event_object_type; + +typedef struct +{ + event_object event; + PyLongObject *exit_code; +} exited_event_object; + +static void +exit_evpy_dealloc (PyObject *self) +{ + Py_DECREF (((exited_event_object *) self)->exit_code); + self->ob_type->tp_free (self); +} + +/* Python function to get the exited event's exit code. */ +static PyObject * +exit_evpy_get_exit_code (PyObject *self, void *closure) +{ + exited_event_object *exited_event_obj = (exited_event_object *) self; + + Py_INCREF (exited_event_obj->exit_code); + + return (PyObject *) (exited_event_obj->exit_code); +} + +exited_event_object * +create_exited_event_object (thread_object *inferior_thread, long long +int *exit_code) +{ + exited_event_object *exited_event_obj; + + exited_event_obj = PyObject_New (exited_event_object, +&exited_event_object_type); + + if (!exited_event_obj) + return NULL; + + exited_event_obj->event.inferior_thread = inferior_thread; + Py_INCREF (exited_event_obj->event.inferior_thread); + exited_event_obj->event.event_type = (PyStringObject *) +PyString_FromString ("exit"); + exited_event_obj->exit_code = (PyLongObject *) PyLong_FromLongLong +(*exit_code); + + return exited_event_obj; +} + +/* Initialize the Python exited event code. */ +void gdbpy_initialize_exited_event (void) +{ + exited_event_object_type.tp_base = &event_object_type; + if (PyType_Ready (&exited_event_object_type) < 0) + return; + + Py_INCREF (&exited_event_object_type); + PyModule_AddObject (gdb_module, "ExitedEvent", (PyObject *) +&exited_event_object_type); +} + +/* Callback that is used when an exit event occurs. This function + will create a new Python exited event object. */ +void +emit_exited_event (thread_object *inferior_thread, long long int *exit_code) +{ + PyObject *callback_list; + PyObject *args_tuple; + Py_ssize_t i; + exited_event_object *exited_event_obj; + + exited_event_obj = create_exited_event_object (inferior_thread, exit_code); + + callback_list = (PyObject *) +(inferior_thread->exited_eventregistry->callbacks); + + args_tuple = PyTuple_New ((Py_ssize_t) 1); + PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *) exited_event_obj); + + for (i = 0; i < PyList_Size (callback_list); i++) + { + PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple); + } +} + +static PyGetSetDef exited_event_object_getset[] = +{ + { "exit_code", exit_evpy_get_exit_code, NULL, "Exit code.", NULL }, + + { NULL } /* Sentinel. */ +}; + +static PyTypeObject exited_event_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /* ob_size */ + "gdb.ExitedEvent", /* tp_name */ + sizeof (exited_event_object), /* tp_basicsize */ + 0, /* tp_itemsize */ + exit_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, /* tp_flags */ + "GDB exited 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 */ + exited_event_object_getset, /* 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-inferior.c b/gdb/python/py-inferior.c index 3a0feab..9e182c4 100644 --- a/gdb/python/py-inferior.c +++ b/gdb/python/py-inferior.c @@ -26,6 +26,7 @@ #include "python-internal.h" #include "arch-utils.h" #include "language.h" +#include "gdb_signals.h" struct threadlist_entry { thread_object *thread_obj; @@ -73,6 +74,72 @@ static PyTypeObject membuf_object_type; } \ } while (0) +static void +python_on_normal_stop (struct bpstats *bs, int print_frame) +{ + PyGILState_STATE state; + char *stop_signal; + + if (!find_thread_ptid (inferior_ptid)) + return; + + stop_signal = (char *) target_signal_to_name (inferior_thread()->stop_signal); + + state = PyGILState_Ensure (); + + emit_stop_event (bs, stop_signal); + + PyGILState_Release (state); +} + +static void +python_on_resume (ptid_t ptid) +{ + PyGILState_STATE state; + + state = PyGILState_Ensure (); + + emit_continue_event (ptid); + + PyGILState_Release (state); +} + +static void +python_thread_exit (struct thread_info *tp, int ignore) +{ + PyGILState_STATE state; + LONGEST exitcode_val; + long long int *exit_code; + inferior_object *inf_obj; + thread_object *thread_obj; + struct threadlist_entry **entry; + + inf_obj = (inferior_object *) find_inferior_object (PIDGET(tp->ptid)); + if (!inf_obj) + return; + + /* Find thread entry in its inferior's thread_list. */ + for (entry = &inf_obj->threads; *entry != NULL; entry = &(*entry)->next) + if ((*entry)->thread_obj->thread == tp) + break; + + if (!*entry) + return; + + thread_obj = (*entry)->thread_obj; + + state = PyGILState_Ensure (); + + if (get_internalvar_integer (lookup_internalvar ("_exitcode"), &exitcode_val)) + exit_code = (long long int *) &exitcode_val; + + if (exit_code) + emit_exited_event (thread_obj, exit_code); + + PyGILState_Release (state); +} + + /* 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. */ @@ -589,6 +656,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_thread_exit (python_thread_exit); if (PyType_Ready (&membuf_object_type) < 0) return; diff --git a/gdb/python/py-infthread.c b/gdb/python/py-infthread.c index 86aba50..d3f448c 100644 --- a/gdb/python/py-infthread.c +++ b/gdb/python/py-infthread.c @@ -51,6 +51,12 @@ create_thread_object (struct thread_info *tp) thread_obj->inf_obj = find_inferior_object (PIDGET (tp->ptid)); Py_INCREF (thread_obj->inf_obj); + thread_obj->stop_eventregistry = create_eventregistry_object (); + thread_obj->breakpoint_stop_eventregistry = create_eventregistry_object (); + thread_obj->signal_stop_eventregistry = create_eventregistry_object (); + thread_obj->continue_eventregistry = create_eventregistry_object (); + thread_obj->exited_eventregistry = create_eventregistry_object (); + return thread_obj; } static void thpy_dealloc (PyObject *self) { Py_DECREF (((thread_object *) self)->inf_obj); + Py_DECREF (((thread_object *) self)->stop_eventregistry); + Py_DECREF (((thread_object *) self)->breakpoint_stop_eventregistry); + Py_DECREF (((thread_object *) self)->signal_stop_eventregistry); + Py_DECREF (((thread_object *) self)->continue_eventregistry); + Py_DECREF (((thread_object *) self)->exited_eventregistry); + self->ob_type->tp_free (self); } static PyObject * +thpy_get_stop_eventregistry (PyObject *self, void *closure) +{ + thread_object *thread_obj = (thread_object *) self; + + THPY_REQUIRE_VALID (thread_obj); + + Py_INCREF (thread_obj->stop_eventregistry); + + return (PyObject *) (thread_obj->stop_eventregistry); +} + +static PyObject * +thpy_get_breakpoint_stop_eventregistry (PyObject *self, void *closure) +{ + thread_object *thread_obj = (thread_object *) self; + + THPY_REQUIRE_VALID (thread_obj); + + Py_INCREF (thread_obj->breakpoint_stop_eventregistry); + + return (PyObject *) (thread_obj->breakpoint_stop_eventregistry); +} + +static PyObject * +thpy_get_signal_stop_eventregistry (PyObject *self, void *closure) +{ + thread_object *thread_obj = (thread_object *) self; + + THPY_REQUIRE_VALID (thread_obj); + + Py_INCREF (thread_obj->signal_stop_eventregistry); + + return (PyObject *) (thread_obj->signal_stop_eventregistry); +} + +static PyObject * +thpy_get_continue_eventregistry (PyObject *self, void *closure) +{ + thread_object *thread_obj = (thread_object *) self; + + THPY_REQUIRE_VALID (thread_obj); + + Py_INCREF (thread_obj->continue_eventregistry); + + return (PyObject *) (thread_obj->continue_eventregistry); +} + +static PyObject * +thpy_get_exited_eventregistry (PyObject *self, void *closure) +{ + thread_object *thread_obj = (thread_object *) self; + + THPY_REQUIRE_VALID (thread_obj); + + Py_INCREF (thread_obj->exited_eventregistry); + + return (PyObject *) (thread_obj->exited_eventregistry); +} + +static PyObject * thpy_get_num (PyObject *self, void *closure) { thread_object *thread_obj = (thread_object *) self; @@ -204,6 +274,17 @@ static PyGetSetDef thread_object_getset[] = { "num", thpy_get_num, NULL, "ID of the thread, as assigned by GDB.", NULL }, { "ptid", thpy_get_ptid, NULL, "ID of the thread, as assigned by the OS.", NULL }, + { "stop_eventregistry", thpy_get_stop_eventregistry, NULL, + "Stop event registry object of the thread.", NULL }, + { "breakpoint_stop_eventregistry", + thpy_get_breakpoint_stop_eventregistry, NULL, + "Breakpoint stop event registry object of the thread.", NULL }, + { "signal_stop_eventregistry", thpy_get_signal_stop_eventregistry, + NULL, "Signal stop event registry object of the thread.", NULL }, + { "continue_eventregistry", thpy_get_continue_eventregistry, NULL, + "Continue event registry object of the thread.", NULL }, + { "exited_eventregistry", thpy_get_exited_eventregistry, NULL, + "Exited event registry object of the thread.", NULL }, { NULL } }; diff --git a/gdb/python/py-signalstopevent.c b/gdb/python/py-signalstopevent.c new file mode 100644 index 0000000..5ab8af7 --- /dev/null +++ b/gdb/python/py-signalstopevent.c @@ -0,0 +1,163 @@ +/* Python interface to inferior signal stop events. + + Copyright (C) 2009, 2010 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "command.h" +#include "python-internal.h" +#include "inferior.h" + +static PyTypeObject signal_stop_event_object_type; + +typedef struct +{ + stop_event_object stop_event; + PyStringObject *stop_signal; +} signal_stop_event_object; + +static void +sig_stop_evpy_dealloc (PyObject *self) +{ + Py_DECREF (((signal_stop_event_object *) self)->stop_signal); + self->ob_type->tp_free (self); +} + +/* Python function to get the stop event's stop signal. */ +static PyObject * +sig_stop_evpy_get_stop_signal (PyObject *self, void *closure) +{ + signal_stop_event_object *signal_stop_event_obj = +(signal_stop_event_object *) self; + + Py_INCREF (signal_stop_event_obj->stop_signal); + + return (PyObject *) (signal_stop_event_obj->stop_signal); +} + +signal_stop_event_object * +create_signal_stop_event_object (const char *stop_signal) +{ + signal_stop_event_object *signal_stop_event_obj; + + signal_stop_event_obj = PyObject_New (signal_stop_event_object, +&signal_stop_event_object_type); + if (!signal_stop_event_obj) + return NULL; + + signal_stop_event_obj->stop_event.event.inferior_thread = +find_thread_object (inferior_ptid); + Py_INCREF (signal_stop_event_obj->stop_event.event.inferior_thread); + signal_stop_event_obj->stop_event.event.event_type = (PyStringObject +*) PyString_FromString ("stop"); + signal_stop_event_obj->stop_event.stop_reason = (PyStringObject *) +PyString_FromString ("signal"); + signal_stop_event_obj->stop_signal = (PyStringObject *) +PyString_FromString (stop_signal); + + return signal_stop_event_obj; +} + +/* Initialize the Python stop event code. */ +void +gdbpy_initialize_signal_stop_event (void) +{ + signal_stop_event_object_type.tp_base = &stop_event_object_type; + if (PyType_Ready (&signal_stop_event_object_type) < 0) + return; + + Py_INCREF (&signal_stop_event_object_type); + PyModule_AddObject (gdb_module, "SignalStopEvent", (PyObject *) +&signal_stop_event_object_type); +} + +/* Callback that is used when a signal stop event occurs. This function + will create a new Python signal stop event object. */ +void +emit_signal_stop_event (const char *stop_signal) +{ + thread_object *inferior_thread; + PyObject *callback_list; + PyObject *args_tuple; + Py_ssize_t i; + signal_stop_event_object *signal_stop_event_obj; + + inferior_thread = find_thread_object (inferior_ptid); + + signal_stop_event_obj = create_signal_stop_event_object (stop_signal); + + callback_list = (PyObject *) +(inferior_thread->signal_stop_eventregistry->callbacks); + + args_tuple = PyTuple_New ((Py_ssize_t) 1); + PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *) +signal_stop_event_obj); + + for (i = 0; i < PyList_Size (callback_list); i++) + { + PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple); + } +} + +static PyGetSetDef signal_stop_event_object_getset[] = +{ + { "stop_signal", sig_stop_evpy_get_stop_signal, NULL, "Stop signal.", NULL }, + + { NULL } /* Sentinel. */ +}; + +static PyTypeObject signal_stop_event_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /* ob_size */ + "gdb.SignalStopEvent", /* tp_name */ + sizeof (signal_stop_event_object), /* tp_basicsize */ + 0, /* tp_itemsize */ + sig_stop_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, /* tp_flags */ + "GDB signal stop 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 */ + signal_stop_event_object_getset, /* 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-stopevent.c b/gdb/python/py-stopevent.c new file mode 100644 index 0000000..069e441 --- /dev/null +++ b/gdb/python/py-stopevent.c @@ -0,0 +1,164 @@ +/* Python interface to inferior stop events. + + Copyright (C) 2009, 2010 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "command.h" +#include "python-internal.h" +#include "inferior.h" + +static void +stop_evpy_dealloc (PyObject *self) +{ + Py_DECREF (((stop_event_object *) self)->stop_reason); + self->ob_type->tp_free (self); +} + +/* Python function to get the stop event's stop reason. */ +static PyObject * +stop_evpy_get_stop_reason (PyObject *self, void *closure) +{ + stop_event_object *stop_event_obj = (stop_event_object *) self; + + Py_INCREF (stop_event_obj->stop_reason); + + return (PyObject *) (stop_event_obj->stop_reason); +} + +stop_event_object * +create_stop_event_object (const char *stop_reason) +{ + stop_event_object *stop_event_obj; + + stop_event_obj = PyObject_New (stop_event_object, &stop_event_object_type); + if (!stop_event_obj) + return NULL; + + stop_event_obj->event.inferior_thread = find_thread_object (inferior_ptid); + Py_INCREF (stop_event_obj->event.inferior_thread); + stop_event_obj->event.event_type = (PyStringObject *) +PyString_FromString ("stop"); + stop_event_obj->stop_reason = (PyStringObject *) PyString_FromString +(stop_reason); + + return stop_event_obj; +} + +/* Initialize the Python stop event code. */ +void +gdbpy_initialize_stop_event (void) +{ + stop_event_object_type.tp_base = &event_object_type; + if (PyType_Ready (&stop_event_object_type) < 0) + return; + + Py_INCREF (&stop_event_object_type); + PyModule_AddObject (gdb_module, "StopEvent", (PyObject *) +&stop_event_object_type); +} + +/* Callback that is used when a stop event occurs. This function + will create a new Python stop event object. */ +void +emit_stop_event (struct bpstats *bs, const char *stop_signal) +{ + thread_object *inferior_thread; + PyObject *callback_list; + PyObject *args_tuple; + Py_ssize_t i; + stop_event_object *stop_event_obj = NULL; /* Appease GCC warning. */ + + inferior_thread = find_thread_object (inferior_ptid); + + if (bs) + { + stop_event_obj = create_stop_event_object ("breakpoint"); + emit_breakpoint_stop_event (bs); + } + + /* Check if the signal is "Signal 0" or "Trace/breakpoint trap". */ + if ((strcmp (stop_signal, "0") != 0) && (strcmp (stop_signal, +"SIGTRAP") != 0)) + { + stop_event_obj = create_stop_event_object ("signal"); + emit_signal_stop_event (stop_signal); + } + + if (!stop_event_obj) + stop_event_obj = create_stop_event_object ("unknown"); + + callback_list = (PyObject *) (inferior_thread->stop_eventregistry->callbacks); + + args_tuple = PyTuple_New ((Py_ssize_t) 1); + PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *) stop_event_obj); + + for (i = 0; i < PyList_Size (callback_list); i++) + { + PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple); + } + +} + +static PyGetSetDef stop_event_object_getset[] = +{ + { "stop_reason", stop_evpy_get_stop_reason, NULL, "Stop reason.", NULL }, + + { NULL } /* Sentinel. */ +}; + +PyTypeObject stop_event_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /* ob_size */ + "gdb.StopEvent", /* tp_name */ + sizeof (stop_event_object), /* tp_basicsize */ + 0, /* tp_itemsize */ + stop_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 stop 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 */ + stop_event_object_getset, /* 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/python-internal.h b/gdb/python/python-internal.h index 2b8d301..609892a 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -75,6 +75,7 @@ typedef int Py_ssize_t; /* Also needed to parse enum var_types. */ #include "command.h" +#include "breakpoint.h" struct block; struct value; @@ -85,6 +86,31 @@ 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 stop_event_object_type; + +/* Used in python-breakpoint.c */ +typedef struct breakpoint_object breakpoint_object; + +struct breakpoint_object +{ + PyObject_HEAD + + /* The breakpoint number according to gdb. */ + int number; + + /* The gdb breakpoint object, or NULL if the breakpoint has been + deleted. */ + struct breakpoint *bp; +}; + +/* Used in python-eventregistry.c */ +typedef struct +{ + PyObject_HEAD + + PyListObject *callbacks; +} eventregistry_object; typedef struct { @@ -92,11 +118,32 @@ typedef struct /* The thread we represent. */ struct thread_info *thread; + eventregistry_object *stop_eventregistry; + eventregistry_object *breakpoint_stop_eventregistry; + eventregistry_object *signal_stop_eventregistry; + eventregistry_object *continue_eventregistry; + eventregistry_object *exited_eventregistry; /* The Inferior object to which this thread belongs. */ PyObject *inf_obj; } thread_object; +/* Used in python-event.c */ +typedef struct +{ + PyObject_HEAD + + thread_object *inferior_thread; + PyStringObject *event_type; +} event_object; + +/* Used in python-stopevent.c */ +typedef struct +{ + event_object event; + PyStringObject *stop_reason; +} stop_event_object; + extern struct cmd_list_element *set_python_list; extern struct cmd_list_element *show_python_list; @@ -136,6 +183,14 @@ 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); +eventregistry_object *create_eventregistry_object (void); +breakpoint_object *gdbpy_breakpoint_from_bpstats (struct bpstats *bs); +void emit_stop_event (struct bpstats *bs, const char *stop_signal); +void emit_breakpoint_stop_event (struct bpstats *bs); +void emit_signal_stop_event (const char *stop_signal); +void emit_continue_event (ptid_t ptid); +void emit_exited_event (thread_object *inferior_thread, + long long int *exit_code); struct block *block_object_to_block (PyObject *obj); struct symbol *symbol_object_to_symbol (PyObject *obj); @@ -162,6 +217,13 @@ 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_stop_event (void); +void gdbpy_initialize_signal_stop_event (void); +void gdbpy_initialize_breakpoint_stop_event (void); +void gdbpy_initialize_continue_event (void); +void gdbpy_initialize_exited_event (void); struct cleanup *make_cleanup_py_decref (PyObject *py); diff --git a/gdb/python/python.c b/gdb/python/python.c index 030b142..46f4a9e 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -965,6 +965,14 @@ Enables or disables printing of Python stack traces."), gdbpy_initialize_inferior (); gdbpy_initialize_events (); + gdbpy_initialize_eventregistry (); + gdbpy_initialize_event (); + gdbpy_initialize_stop_event (); + gdbpy_initialize_signal_stop_event (); + gdbpy_initialize_breakpoint_stop_event (); + gdbpy_initialize_continue_event (); + gdbpy_initialize_exited_event (); + PyRun_SimpleString ("import gdb"); PyRun_SimpleString ("gdb.pretty_printers = []");