X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fpython%2Fpy-breakpoint.c;h=89ace99f25f63203564a3619b65beca8762a6b46;hb=eab09350a37d669c13aaccf621c9e22b7776a3be;hp=fb96b54251661f1d4f33f9a96605cba0af643443;hpb=d59b6f6c38a3e9c229dae40bd6c668be47fe8e48;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c index fb96b54251..89ace99f25 100644 --- a/gdb/python/py-breakpoint.c +++ b/gdb/python/py-breakpoint.c @@ -1,6 +1,6 @@ /* Python interface to breakpoints - Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 2008-2012 Free Software Foundation, Inc. This file is part of GDB. @@ -21,6 +21,7 @@ #include "value.h" #include "exceptions.h" #include "python-internal.h" +#include "python.h" #include "charset.h" #include "breakpoint.h" #include "gdbcmd.h" @@ -28,62 +29,18 @@ #include "observer.h" #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 - breakpoint has a number. A breakpoint is valid if its slot in this - vector is non-null. When a breakpoint is deleted, we drop our - reference to it and zero its slot; this is how we let the Python - object have a lifetime which is independent from that of the gdb - breakpoint. */ -static breakpoint_object **bppy_breakpoints; - -/* Number of slots in bppy_breakpoints. */ -static int bppy_slots; +#include "arch-utils.h" +#include "language.h" /* Number of live breakpoints. */ static int bppy_live; /* Variables used to pass information between the Breakpoint constructor and the breakpoint-created hook function. */ -static breakpoint_object *bppy_pending_object; - -struct breakpoint_object -{ - PyObject_HEAD +breakpoint_object *bppy_pending_object; - /* 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) \ - do { \ - if (! bpnum_is_valid ((Breakpoint)->number)) \ - return PyErr_Format (PyExc_RuntimeError, _("Breakpoint %d is invalid."), \ - (Breakpoint)->number); \ - } while (0) - -/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python - exception if it is invalid. This macro is for use in setter functions. */ -#define BPPY_SET_REQUIRE_VALID(Breakpoint) \ - do { \ - if (! bpnum_is_valid ((Breakpoint)->number)) \ - { \ - PyErr_Format (PyExc_RuntimeError, _("Breakpoint %d is invalid."), \ - (Breakpoint)->number); \ - return -1; \ - } \ - } while (0) +/* Function that is called when a Python condition is evaluated. */ +static char * const stop_func = "stop"; /* This is used to initialize various gdb.bp_* constants. */ struct pybp_code @@ -115,18 +72,6 @@ static struct pybp_code pybp_watch_types[] = {NULL} /* Sentinel. */ }; -/* Evaluate to true if the breakpoint NUM is valid, false otherwise. */ -static int -bpnum_is_valid (int num) -{ - if (num >=0 - && num < bppy_slots - && bppy_breakpoints[num] != NULL) - return 1; - - return 0; -} - /* Python function which checks the validity of a breakpoint object. */ static PyObject * bppy_is_valid (PyObject *self, PyObject *args) @@ -170,6 +115,7 @@ bppy_set_enabled (PyObject *self, PyObject *newvalue, void *closure) { breakpoint_object *self_bp = (breakpoint_object *) self; int cmp; + volatile struct gdb_exception except; BPPY_SET_REQUIRE_VALID (self_bp); @@ -190,10 +136,16 @@ bppy_set_enabled (PyObject *self, PyObject *newvalue, void *closure) cmp = PyObject_IsTrue (newvalue); if (cmp < 0) return -1; - else if (cmp == 1) - enable_breakpoint (self_bp->bp); - else - disable_breakpoint (self_bp->bp); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + if (cmp == 1) + enable_breakpoint (self_bp->bp); + else + disable_breakpoint (self_bp->bp); + } + GDB_PY_SET_HANDLE_EXCEPTION (except); + return 0; } @@ -223,7 +175,7 @@ bppy_set_silent (PyObject *self, PyObject *newvalue, void *closure) if (cmp < 0) return -1; else - self_bp->bp->silent = cmp; + breakpoint_set_silent (self_bp->bp, cmp); return 0; } @@ -233,7 +185,7 @@ static int bppy_set_thread (PyObject *self, PyObject *newvalue, void *closure) { breakpoint_object *self_bp = (breakpoint_object *) self; - int id; + long id; BPPY_SET_REQUIRE_VALID (self_bp); @@ -245,7 +197,9 @@ bppy_set_thread (PyObject *self, PyObject *newvalue, void *closure) } else if (PyInt_Check (newvalue)) { - id = (int) PyInt_AsLong (newvalue); + if (! gdb_py_int_as_long (newvalue, &id)) + return -1; + if (! valid_thread_id (id)) { PyErr_SetString (PyExc_RuntimeError, @@ -262,7 +216,7 @@ bppy_set_thread (PyObject *self, PyObject *newvalue, void *closure) return -1; } - self_bp->bp->thread = id; + breakpoint_set_thread (self_bp->bp, id); return 0; } @@ -272,7 +226,9 @@ static int bppy_set_task (PyObject *self, PyObject *newvalue, void *closure) { breakpoint_object *self_bp = (breakpoint_object *) self; - int id; + long id; + int valid_id = 0; + volatile struct gdb_exception except; BPPY_SET_REQUIRE_VALID (self_bp); @@ -284,8 +240,16 @@ bppy_set_task (PyObject *self, PyObject *newvalue, void *closure) } else if (PyInt_Check (newvalue)) { - id = (int) PyInt_AsLong (newvalue); - if (! valid_task_id (id)) + if (! gdb_py_int_as_long (newvalue, &id)) + return -1; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + valid_id = valid_task_id (id); + } + GDB_PY_SET_HANDLE_EXCEPTION (except); + + if (! valid_id) { PyErr_SetString (PyExc_RuntimeError, _("Invalid task ID.")); @@ -301,11 +265,33 @@ bppy_set_task (PyObject *self, PyObject *newvalue, void *closure) return -1; } - self_bp->bp->task = id; + breakpoint_set_task (self_bp->bp, id); return 0; } +/* 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 + sections. */ + +static PyObject * +bppy_delete_breakpoint (PyObject *self, PyObject *args) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + volatile struct gdb_exception except; + + BPPY_REQUIRE_VALID (self_bp); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + delete_breakpoint (self_bp->bp); + } + GDB_PY_HANDLE_EXCEPTION (except); + + Py_RETURN_NONE; +} + /* Python function to set the ignore count of a breakpoint. */ static int @@ -313,6 +299,7 @@ bppy_set_ignore_count (PyObject *self, PyObject *newvalue, void *closure) { breakpoint_object *self_bp = (breakpoint_object *) self; long value; + volatile struct gdb_exception except; BPPY_SET_REQUIRE_VALID (self_bp); @@ -329,10 +316,17 @@ bppy_set_ignore_count (PyObject *self, PyObject *newvalue, void *closure) return -1; } - value = PyInt_AsLong (newvalue); + if (! gdb_py_int_as_long (newvalue, &value)) + return -1; + if (value < 0) value = 0; - set_ignore_count (self_bp->number, (int) value, 0); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + set_ignore_count (self_bp->number, (int) value, 0); + } + GDB_PY_SET_HANDLE_EXCEPTION (except); return 0; } @@ -351,11 +345,19 @@ bppy_set_hit_count (PyObject *self, PyObject *newvalue, void *closure) _("Cannot delete `hit_count' attribute.")); return -1; } - else if (! PyInt_Check (newvalue) || PyInt_AsLong (newvalue) != 0) + else { - PyErr_SetString (PyExc_AttributeError, - _("The value of `hit_count' must be zero.")); - return -1; + long value; + + if (! gdb_py_int_as_long (newvalue, &value)) + return -1; + + if (value != 0) + { + PyErr_SetString (PyExc_AttributeError, + _("The value of `hit_count' must be zero.")); + return -1; + } } self_bp->bp->hit_count = 0; @@ -388,16 +390,16 @@ bppy_get_expression (PyObject *self, void *closure) { char *str; breakpoint_object *obj = (breakpoint_object *) self; + struct watchpoint *wp; BPPY_REQUIRE_VALID (obj); - if (obj->bp->type != bp_watchpoint - && obj->bp->type != bp_hardware_watchpoint - && obj->bp->type != bp_read_watchpoint - && obj->bp->type != bp_access_watchpoint) + if (!is_watchpoint (obj->bp)) Py_RETURN_NONE; - str = obj->bp->exp_string; + wp = (struct watchpoint *) obj->bp; + + str = wp->exp_string; if (! str) str = ""; @@ -420,6 +422,9 @@ bppy_get_condition (PyObject *self, void *closure) return PyString_Decode (str, strlen (str), host_charset (), NULL); } +/* Returns 0 on success. Returns -1 on error, with a python exception set. + */ + static int bppy_set_condition (PyObject *self, PyObject *newvalue, void *closure) { @@ -448,6 +453,10 @@ bppy_set_condition (PyObject *self, PyObject *newvalue, void *closure) { set_breakpoint_condition (self_bp->bp, exp, 0); } + + if (newvalue != Py_None) + xfree (exp); + GDB_PY_SET_HANDLE_EXCEPTION (except); return 0; @@ -474,18 +483,18 @@ bppy_get_commands (PyObject *self, void *closure) string_file = mem_fileopen (); chain = make_cleanup_ui_file_delete (string_file); + ui_out_redirect (current_uiout, string_file); TRY_CATCH (except, RETURN_MASK_ALL) { - ui_out_redirect (uiout, string_file); - print_command_lines (uiout, breakpoint_commands (bp), 0); - ui_out_redirect (uiout, NULL); + print_command_lines (current_uiout, breakpoint_commands (bp), 0); } - cmdstr = ui_file_xstrdup (string_file, &length); + ui_out_redirect (current_uiout, NULL); GDB_PY_HANDLE_EXCEPTION (except); + cmdstr = ui_file_xstrdup (string_file, &length); + make_cleanup (xfree, cmdstr); result = PyString_Decode (cmdstr, strlen (cmdstr), host_charset (), NULL); do_cleanups (chain); - xfree (cmdstr); return result; } @@ -500,6 +509,21 @@ bppy_get_type (PyObject *self, void *closure) return PyInt_FromLong (self_bp->bp->type); } +/* Python function to get the visibility of the breakpoint. */ + +static PyObject * +bppy_get_visibility (PyObject *self, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + + BPPY_REQUIRE_VALID (self_bp); + + if (self_bp->bp->number < 0) + Py_RETURN_FALSE; + + Py_RETURN_TRUE; +} + /* Python function to get the breakpoint's number. */ static PyObject * bppy_get_number (PyObject *self, void *closure) @@ -562,50 +586,59 @@ 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", NULL }; - char *spec; + static char *keywords[] = { "spec", "type", "wp_class", "internal", NULL }; + const char *spec; int type = bp_breakpoint; int access_type = hw_write; + PyObject *internal = NULL; + int internal_bp = 0; volatile struct gdb_exception except; - if (! PyArg_ParseTupleAndKeywords (args, kwargs, "s|ii", keywords, - &spec, &type, &access_type)) - return NULL; + if (! PyArg_ParseTupleAndKeywords (args, kwargs, "s|iiO", keywords, + &spec, &type, &access_type, &internal)) + return -1; - result = subtype->tp_alloc (subtype, 0); - if (! result) - return NULL; - bppy_pending_object = (breakpoint_object *) result; + if (internal) + { + internal_bp = PyObject_IsTrue (internal); + if (internal_bp == -1) + return -1; + } + + bppy_pending_object = (breakpoint_object *) self; bppy_pending_object->number = -1; bppy_pending_object->bp = NULL; TRY_CATCH (except, RETURN_MASK_ALL) { + char *copy = xstrdup (spec); + struct cleanup *cleanup = make_cleanup (xfree, copy); + switch (type) { case bp_breakpoint: { create_breakpoint (python_gdbarch, - spec, NULL, -1, + copy, NULL, -1, NULL, 0, - 0, 0, 0, + 0, bp_breakpoint, 0, AUTO_BOOLEAN_TRUE, - NULL, 0, 1); + &bkpt_breakpoint_ops, + 0, 1, internal_bp, 0); break; } case bp_watchpoint: { if (access_type == hw_write) - watch_command_wrapper (spec, 0); + watch_command_wrapper (copy, 0, internal_bp); else if (access_type == hw_access) - awatch_command_wrapper (spec, 0); + awatch_command_wrapper (copy, 0, internal_bp); else if (access_type == hw_read) - rwatch_command_wrapper (spec, 0); + rwatch_command_wrapper (copy, 0, internal_bp); else error(_("Cannot understand watchpoint access type.")); break; @@ -613,46 +646,139 @@ bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs) default: error(_("Do not understand breakpoint type to set.")); } + + do_cleanups (cleanup); } 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; } +static int +build_bp_list (struct breakpoint *b, void *arg) +{ + PyObject *list = arg; + PyObject *bp = (PyObject *) b->py_bp_object; + int iserr = 0; + + /* Not all breakpoints will have a companion Python object. + Only breakpoints that were created via bppy_new, or + breakpoints that were created externally and are tracked by + the Python Scripting API. */ + if (bp) + iserr = PyList_Append (list, bp); + + if (iserr == -1) + return 1; + + return 0; +} + /* Static function to return a tuple holding all breakpoints. */ PyObject * gdbpy_breakpoints (PyObject *self, PyObject *args) { - PyObject *result; + PyObject *list, *tuple; if (bppy_live == 0) Py_RETURN_NONE; - result = PyTuple_New (bppy_live); - if (result) + list = PyList_New (0); + if (!list) + return NULL; + + /* If iteratre_over_breakpoints returns non NULL it signals an error + condition. In that case abandon building the list and return + NULL. */ + if (iterate_over_breakpoints (build_bp_list, list) != NULL) + { + Py_DECREF (list); + return NULL; + } + + tuple = PyList_AsTuple (list); + Py_DECREF (list); + + return tuple; +} + +/* 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 (bp_obj->is_finish_bp) + bpfinishpy_pre_stop_hook (bp_obj); + + if (PyObject_HasAttrString (py_bp, stop_func)) { - int i, out = 0; + PyObject *result = PyObject_CallMethod (py_bp, stop_func, NULL); - for (i = 0; out < bppy_live; ++i) + if (result) { - if (! bppy_breakpoints[i]) - continue; - Py_INCREF (bppy_breakpoints[i]); - PyTuple_SetItem (result, out, (PyObject *) bppy_breakpoints[i]); - ++out; + 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 (); } - return result; + + if (bp_obj->is_finish_bp) + bpfinishpy_post_stop_hook (bp_obj); + + 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) + has_func = PyObject_HasAttrString (py_bp, stop_func); + + do_cleanups (cleanup); + + return has_func; } @@ -662,17 +788,12 @@ gdbpy_breakpoints (PyObject *self, PyObject *args) /* Callback that is used when a breakpoint is created. This function will create a new Python breakpoint object. */ static void -gdbpy_breakpoint_created (int num) +gdbpy_breakpoint_created (struct breakpoint *bp) { breakpoint_object *newbp; - struct breakpoint *bp = NULL; PyGILState_STATE state; - if (num < 0) - return; - - bp = get_breakpoint (num); - if (! bp) + if (bp->number < 0 && bppy_pending_object == NULL) return; if (bp->type != bp_breakpoint @@ -682,21 +803,6 @@ gdbpy_breakpoint_created (int num) && bp->type != bp_access_watchpoint) return; - if (num >= bppy_slots) - { - int old = bppy_slots; - - bppy_slots = bppy_slots * 2 + 10; - bppy_breakpoints - = (breakpoint_object **) xrealloc (bppy_breakpoints, - (bppy_slots - * sizeof (breakpoint_object *))); - memset (&bppy_breakpoints[old], 0, - (bppy_slots - old) * sizeof (PyObject *)); - } - - ++bppy_live; - state = PyGILState_Ensure (); if (bppy_pending_object) @@ -708,14 +814,19 @@ gdbpy_breakpoint_created (int num) newbp = PyObject_New (breakpoint_object, &breakpoint_object_type); if (newbp) { - newbp->number = num; + newbp->number = bp->number; newbp->bp = bp; - bppy_breakpoints[num] = newbp; + newbp->bp->py_bp_object = newbp; + newbp->is_finish_bp = 0; Py_INCREF (newbp); + ++bppy_live; + } + else + { + PyErr_SetString (PyExc_RuntimeError, + _("Error while creating breakpoint from GDB.")); + gdbpy_print_stack (); } - - /* Just ignore errors here. */ - PyErr_Clear (); PyGILState_Release (state); } @@ -723,17 +834,24 @@ gdbpy_breakpoint_created (int num) /* Callback that is used when a breakpoint is deleted. This will invalidate the corresponding Python object. */ static void -gdbpy_breakpoint_deleted (int num) +gdbpy_breakpoint_deleted (struct breakpoint *b) { + int num = b->number; PyGILState_STATE state; + struct breakpoint *bp = NULL; + breakpoint_object *bp_obj; state = PyGILState_Ensure (); - if (bpnum_is_valid (num)) + bp = get_breakpoint (num); + if (bp) { - bppy_breakpoints[num]->bp = NULL; - Py_DECREF (bppy_breakpoints[num]); - bppy_breakpoints[num] = NULL; - --bppy_live; + bp_obj = bp->py_bp_object; + if (bp_obj) + { + bp_obj->bp = NULL; + --bppy_live; + Py_DECREF (bp_obj); + } } PyGILState_Release (state); } @@ -746,7 +864,7 @@ gdbpy_initialize_breakpoints (void) { int i; - breakpoint_object_type.tp_new = bppy_new; + breakpoint_object_type.tp_new = PyType_GenericNew; if (PyType_Ready (&breakpoint_object_type) < 0) return; @@ -781,6 +899,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 }, @@ -816,6 +965,8 @@ or None if no condition set."}, "Commands of the breakpoint, as specified by the user."}, { "type", bppy_get_type, NULL, "Type of breakpoint."}, + { "visible", bppy_get_visibility, NULL, + "Whether the breakpoint is visible to the user."}, { NULL } /* Sentinel. */ }; @@ -823,10 +974,12 @@ static PyMethodDef breakpoint_object_methods[] = { { "is_valid", bppy_is_valid, METH_NOARGS, "Return true if this breakpoint is valid, false if not." }, + { "delete", bppy_delete_breakpoint, METH_NOARGS, + "Delete the underlying GDB breakpoint." }, { NULL } /* Sentinel. */ }; -static PyTypeObject breakpoint_object_type = +PyTypeObject breakpoint_object_type = { PyObject_HEAD_INIT (NULL) 0, /*ob_size*/ @@ -846,9 +999,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 */ @@ -858,5 +1011,12 @@ 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 */ };