2011-03-14 Phil Muldoon <pmuldoon@redhat.com>

* gdb.texinfo (Breakpoints In Python): Add description and
              example
	      of Python stop function operation.

2010-03-14  Phil Muldoon  <pmuldoon@redhat.com>

	    * gdb.python/py-breakpoint.exp: Add Python stop operations
              tests.

2011-03-14  Phil Muldoon  <pmuldoon@redhat.com>

	    * python/python.h: Declare gdbpy_should_stop and
	    gdbpy_breakpoint_has_py_cond.
	    * python/python.c: Add python.h to includes.  Remove
	    python.h from
	    HAVE_PYTHON definition
	    (gdbpy_should_stop): New dummy function.
	    (gdbpy_breakpoint_has_py_cond): New dummy function.
	    * python/py-breakpoint.c (bppy_init): Rewrite to allow
	    sub-classing capabilities.
	    (gdbpy_should_stop): New function.
	    (gdbpy_breakpoint_has_py_cond): New function.
	    (local_setattro): New function.
	    * breakpoint.c (condition_command): Add check for Python
	    'stop'
	    operation.
	    (bpstat_check_breakpoint_conditions): Execute Python
	    'stop'
	    operation function as part of stop/continue tests.
This commit is contained in:
Phil Muldoon 2011-03-14 16:09:55 +00:00
parent 34e77a920a
commit 7371cf6d8d
9 changed files with 312 additions and 20 deletions

View file

@ -28,6 +28,8 @@
#include "observer.h"
#include "cli/cli-script.h"
#include "ada-lang.h"
#include "arch-utils.h"
#include "language.h"
static PyTypeObject breakpoint_object_type;
@ -38,6 +40,9 @@ static int bppy_live;
constructor and the breakpoint-created hook function. */
static breakpoint_object *bppy_pending_object;
/* Function that is called when a Python condition is evaluated. */
static char * const stop_func = "stop";
struct breakpoint_object
{
PyObject_HEAD
@ -590,10 +595,9 @@ bppy_get_ignore_count (PyObject *self, void *closure)
}
/* Python function to create a new breakpoint. */
static PyObject *
bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
static int
bppy_init (PyObject *self, PyObject *args, PyObject *kwargs)
{
PyObject *result;
static char *keywords[] = { "spec", "type", "wp_class", "internal", NULL };
char *spec;
int type = bp_breakpoint;
@ -604,19 +608,16 @@ bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
if (! PyArg_ParseTupleAndKeywords (args, kwargs, "s|iiO", keywords,
&spec, &type, &access_type, &internal))
return NULL;
return -1;
if (internal)
{
internal_bp = PyObject_IsTrue (internal);
if (internal_bp == -1)
return NULL;
return -1;
}
result = subtype->tp_alloc (subtype, 0);
if (! result)
return NULL;
bppy_pending_object = (breakpoint_object *) result;
bppy_pending_object = (breakpoint_object *) self;
bppy_pending_object->number = -1;
bppy_pending_object->bp = NULL;
@ -653,14 +654,14 @@ bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
}
if (except.reason < 0)
{
subtype->tp_free (result);
return PyErr_Format (except.reason == RETURN_QUIT
? PyExc_KeyboardInterrupt : PyExc_RuntimeError,
"%s", except.message);
PyErr_Format (except.reason == RETURN_QUIT
? PyExc_KeyboardInterrupt : PyExc_RuntimeError,
"%s", except.message);
return -1;
}
BPPY_REQUIRE_VALID ((breakpoint_object *) result);
return result;
BPPY_SET_REQUIRE_VALID ((breakpoint_object *) self);
return 0;
}
@ -711,6 +712,69 @@ gdbpy_breakpoints (PyObject *self, PyObject *args)
return PyList_AsTuple (list);
}
/* Call the "stop" method (if implemented) in the breakpoint
class. If the method returns True, the inferior will be
stopped at the breakpoint. Otherwise the inferior will be
allowed to continue. */
int
gdbpy_should_stop (struct breakpoint_object *bp_obj)
{
int stop = 1;
PyObject *py_bp = (PyObject *) bp_obj;
struct breakpoint *b = bp_obj->bp;
struct gdbarch *garch = b->gdbarch ? b->gdbarch : get_current_arch ();
struct cleanup *cleanup = ensure_python_env (garch, current_language);
if (PyObject_HasAttrString (py_bp, stop_func))
{
PyObject *result = PyObject_CallMethod (py_bp, stop_func, NULL);
if (result)
{
int evaluate = PyObject_IsTrue (result);
if (evaluate == -1)
gdbpy_print_stack ();
/* If the "stop" function returns False that means
the Python breakpoint wants GDB to continue. */
if (! evaluate)
stop = 0;
Py_DECREF (result);
}
else
gdbpy_print_stack ();
}
do_cleanups (cleanup);
return stop;
}
/* Checks if the "stop" method exists in this breakpoint.
Used by condition_command to ensure mutual exclusion of breakpoint
conditions. */
int
gdbpy_breakpoint_has_py_cond (struct breakpoint_object *bp_obj)
{
int has_func = 0;
PyObject *py_bp = (PyObject *) bp_obj;
struct gdbarch *garch = bp_obj->bp->gdbarch ? bp_obj->bp->gdbarch :
get_current_arch ();
struct cleanup *cleanup = ensure_python_env (garch, current_language);
if (py_bp == NULL)
return 0;
has_func = PyObject_HasAttrString (py_bp, stop_func);
do_cleanups (cleanup);
return has_func;
}
/* Event callback functions. */
@ -797,7 +861,6 @@ gdbpy_initialize_breakpoints (void)
{
int i;
breakpoint_object_type.tp_new = bppy_new;
if (PyType_Ready (&breakpoint_object_type) < 0)
return;
@ -832,6 +895,37 @@ gdbpy_initialize_breakpoints (void)
/* Helper function that overrides this Python object's
PyObject_GenericSetAttr to allow extra validation of the attribute
being set. */
static int
local_setattro (PyObject *self, PyObject *name, PyObject *v)
{
breakpoint_object *obj = (breakpoint_object *) self;
char *attr = python_string_to_host_string (name);
if (attr == NULL)
return -1;
/* If the attribute trying to be set is the "stop" method,
but we already have a condition set in the CLI, disallow this
operation. */
if (strcmp (attr, stop_func) == 0 && obj->bp->cond_string)
{
xfree (attr);
PyErr_SetString (PyExc_RuntimeError,
_("Cannot set 'stop' method. There is an " \
"existing GDB condition attached to the " \
"breakpoint."));
return -1;
}
xfree (attr);
return PyObject_GenericSetAttr ((PyObject *)self, name, v);
}
static PyGetSetDef breakpoint_object_getset[] = {
{ "enabled", bppy_get_enabled, bppy_set_enabled,
"Boolean telling whether the breakpoint is enabled.", NULL },
@ -901,9 +995,9 @@ static PyTypeObject breakpoint_object_type =
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
(setattrofunc)local_setattro, /*tp_setattro */
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
"GDB breakpoint object", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
@ -913,5 +1007,13 @@ static PyTypeObject breakpoint_object_type =
0, /* tp_iternext */
breakpoint_object_methods, /* tp_methods */
0, /* tp_members */
breakpoint_object_getset /* tp_getset */
breakpoint_object_getset, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
bppy_init, /* tp_init */
0, /* tp_alloc */
PyType_GenericNew /* tp_new */
};