* Symbols In Python:: Python representation of symbols.
* Symbol Tables In Python:: Python representation of symbol tables.
* Lazy Strings In Python:: Python representation of lazy strings.
+* Breakpoints In Python:: Manipulating breakpoints using Python.
@end menu
@node Basic Python
It must be a boolean value. If omitted, it defaults to @code{False}.
@end defun
+@findex gdb.breakpoints
+@defun breakpoints
+Return a sequence holding all of @value{GDBN}'s breakpoints.
+@xref{Breakpoints In Python}, for more information.
+@end defun
+
@findex gdb.parameter
@defun parameter parameter
Return the value of a @value{GDBN} parameter. @var{parameter} is a
@end defmethod
@end table
+@node Breakpoints In Python
+@subsubsection Manipulating breakpoints using Python
+
+@cindex breakpoints in python
+@tindex gdb.Breakpoint
+
+Python code can manipulate breakpoints via the @code{gdb.Breakpoint}
+class.
+
+@defmethod Breakpoint __init__ spec @r{[}type@r{]} @r{[}wp_class@r{]}
+Create a new breakpoint. @var{spec} is a string naming the
+location of the breakpoint, or an expression that defines a
+watchpoint. The contents can be any location recognized by the
+@code{break} command, or in the case of a watchpoint, by the @code{watch}
+command. The optional @var{type} denotes the breakpoint to create
+from the types defined later in this chapter. This argument can be
+either: @code{BP_BREAKPOINT} or @code{BP_WATCHPOINT}. @var{type}
+defaults to @code{BP_BREAKPOINT}. The optional @var{wp_class}
+argument defines the class of watchpoint to create, if @var{type} is
+defined as @code{BP_WATCHPOINT}. If a watchpoint class is not
+provided, it is assumed to be a @var{WP_WRITE} class.
+@end defmethod
+
+The available watchpoint types represented by constants are defined in the
+@code{gdb} module:
+
+@table @code
+@findex WP_READ
+@findex gdb.WP_READ
+@item WP_READ
+Read only watchpoint.
+
+@findex WP_WRITE
+@findex gdb.WP_WRITE
+@item WP_WRITE
+Write only watchpoint.
+
+@findex WP_ACCESS
+@findex gdb.WP_ACCESS
+@item WP_ACCESS
+Read/Write watchpoint.
+@end table
+
+@defmethod Breakpoint is_valid
+Return @code{True} if this @code{Breakpoint} object is valid,
+@code{False} otherwise. A @code{Breakpoint} object can become invalid
+if the user deletes the breakpoint. In this case, the object still
+exists, but the underlying breakpoint does not. In the cases of
+watchpoint scope, the watchpoint remains valid even if execution of the
+inferior leaves the scope of that watchpoint.
+@end defmethod
+
+@defivar Breakpoint enabled
+This attribute is @code{True} if the breakpoint is enabled, and
+@code{False} otherwise. This attribute is writable.
+@end defivar
+
+@defivar Breakpoint silent
+This attribute is @code{True} if the breakpoint is silent, and
+@code{False} otherwise. This attribute is writable.
+
+Note that a breakpoint can also be silent if it has commands and the
+first command is @code{silent}. This is not reported by the
+@code{silent} attribute.
+@end defivar
+
+@defivar Breakpoint thread
+If the breakpoint is thread-specific, this attribute holds the thread
+id. If the breakpoint is not thread-specific, this attribute is
+@code{None}. This attribute is writable.
+@end defivar
+
+@defivar Breakpoint task
+If the breakpoint is Ada task-specific, this attribute holds the Ada task
+id. If the breakpoint is not task-specific (or the underlying
+language is not Ada), this attribute is @code{None}. This attribute
+is writable.
+@end defivar
+
+@defivar Breakpoint ignore_count
+This attribute holds the ignore count for the breakpoint, an integer.
+This attribute is writable.
+@end defivar
+
+@defivar Breakpoint number
+This attribute holds the breakpoint's number --- the identifier used by
+the user to manipulate the breakpoint. This attribute is not writable.
+@end defivar
+
+@defivar Breakpoint type
+This attribute holds the breakpoint's type --- the identifier used to
+determine the actual breakpoint type or use-case. This attribute is not
+writable.
+@end defivar
+
+The available types are represented by constants defined in the @code{gdb}
+module:
+
+@table @code
+@findex BP_BREAKPOINT
+@findex gdb.BP_BREAKPOINT
+@item BP_BREAKPOINT
+Normal code breakpoint.
+
+@findex BP_WATCHPOINT
+@findex gdb.BP_WATCHPOINT
+@item BP_WATCHPOINT
+Watchpoint breakpoint.
+
+@findex BP_HARDWARE_WATCHPOINT
+@findex gdb.BP_HARDWARE_WATCHPOINT
+@item BP_HARDWARE_WATCHPOINT
+Hardware assisted watchpoint.
+
+@findex BP_READ_WATCHPOINT
+@findex gdb.BP_READ_WATCHPOINT
+@item BP_READ_WATCHPOINT
+Hardware assisted read watchpoint.
+
+@findex BP_ACCESS_WATCHPOINT
+@findex gdb.BP_ACCESS_WATCHPOINT
+@item BP_ACCESS_WATCHPOINT
+Hardware assisted access watchpoint.
+@end table
+
+@defivar Breakpoint hit_count
+This attribute holds the hit count for the breakpoint, an integer.
+This attribute is writable, but currently it can only be set to zero.
+@end defivar
+
+@defivar Breakpoint location
+This attribute holds the location of the breakpoint, as specified by
+the user. It is a string. If the breakpoint does not have a location
+(that is, it is a watchpoint) the attribute's value is @code{None}. This
+attribute is not writable.
+@end defivar
+
+@defivar Breakpoint expression
+This attribute holds a breakpoint expression, as specified by
+the user. It is a string. If the breakpoint does not have an
+expression (the breakpoint is not a watchpoint) the attribute's value
+is @code{None}. This attribute is not writable.
+@end defivar
+
+@defivar Breakpoint condition
+This attribute holds the condition of the breakpoint, as specified by
+the user. It is a string. If there is no condition, this attribute's
+value is @code{None}. This attribute is writable.
+@end defivar
+
+@defivar Breakpoint commands
+This attribute holds the commands attached to the breakpoint. If
+there are commands, this attribute's value is a string holding all the
+commands, separated by newlines. If there are no commands, this
+attribute is @code{None}. This attribute is not writable.
+@end defivar
+
@node Lazy Strings In Python
@subsubsection Python representation of lazy strings.
--- /dev/null
+/* Python interface to breakpoints
+
+ Copyright (C) 2008, 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 <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "value.h"
+#include "exceptions.h"
+#include "python-internal.h"
+#include "charset.h"
+#include "breakpoint.h"
+#include "gdbcmd.h"
+#include "gdbthread.h"
+#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;
+
+/* 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
+
+ /* 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)
+
+/* This is used to initialize various gdb.bp_* constants. */
+struct pybp_code
+{
+ /* The name. */
+ const char *name;
+ /* The code. */
+ enum type_code code;
+};
+
+/* Entries related to the type of user set breakpoints. */
+static struct pybp_code pybp_codes[] =
+{
+ { "BP_NONE", bp_none},
+ { "BP_BREAKPOINT", bp_breakpoint},
+ { "BP_WATCHPOINT", bp_watchpoint},
+ { "BP_HARDWARE_WATCHPOINT", bp_hardware_watchpoint},
+ { "BP_READ_WATCHPOINT", bp_read_watchpoint},
+ { "BP_ACCESS_WATCHPOINT", bp_access_watchpoint},
+ {NULL} /* Sentinel. */
+};
+
+/* Entries related to the type of watchpoint. */
+static struct pybp_code pybp_watch_types[] =
+{
+ { "WP_READ", hw_read},
+ { "WP_WRITE", hw_write},
+ { "WP_ACCESS", hw_access},
+ {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)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+
+ if (self_bp->bp)
+ Py_RETURN_TRUE;
+ Py_RETURN_FALSE;
+}
+
+/* Python function to test whether or not the breakpoint is enabled. */
+static PyObject *
+bppy_get_enabled (PyObject *self, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+
+ BPPY_REQUIRE_VALID (self_bp);
+ if (! self_bp->bp)
+ Py_RETURN_FALSE;
+ if (self_bp->bp->enable_state == bp_enabled)
+ Py_RETURN_TRUE;
+ Py_RETURN_FALSE;
+}
+
+/* Python function to test whether or not the breakpoint is silent. */
+static PyObject *
+bppy_get_silent (PyObject *self, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+
+ BPPY_REQUIRE_VALID (self_bp);
+ if (self_bp->bp->silent)
+ Py_RETURN_TRUE;
+ Py_RETURN_FALSE;
+}
+
+/* Python function to set the enabled state of a breakpoint. */
+static int
+bppy_set_enabled (PyObject *self, PyObject *newvalue, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+ int cmp;
+
+ BPPY_SET_REQUIRE_VALID (self_bp);
+
+ if (newvalue == NULL)
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("Cannot delete `enabled' attribute."));
+
+ return -1;
+ }
+ else if (! PyBool_Check (newvalue))
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("The value of `enabled' must be a boolean."));
+ return -1;
+ }
+
+ cmp = PyObject_IsTrue (newvalue);
+ if (cmp < 0)
+ return -1;
+ else if (cmp == 1)
+ enable_breakpoint (self_bp->bp);
+ else
+ disable_breakpoint (self_bp->bp);
+ return 0;
+}
+
+/* Python function to set the 'silent' state of a breakpoint. */
+static int
+bppy_set_silent (PyObject *self, PyObject *newvalue, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+ int cmp;
+
+ BPPY_SET_REQUIRE_VALID (self_bp);
+
+ if (newvalue == NULL)
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("Cannot delete `silent' attribute."));
+ return -1;
+ }
+ else if (! PyBool_Check (newvalue))
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("The value of `silent' must be a boolean."));
+ return -1;
+ }
+
+ cmp = PyObject_IsTrue (newvalue);
+ if (cmp < 0)
+ return -1;
+ else
+ self_bp->bp->silent = cmp;
+
+ return 0;
+}
+
+/* Python function to set the thread of a breakpoint. */
+static int
+bppy_set_thread (PyObject *self, PyObject *newvalue, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+ int id;
+
+ BPPY_SET_REQUIRE_VALID (self_bp);
+
+ if (newvalue == NULL)
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("Cannot delete `thread' attribute."));
+ return -1;
+ }
+ else if (PyInt_Check (newvalue))
+ {
+ id = (int) PyInt_AsLong (newvalue);
+ if (! valid_thread_id (id))
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ _("Invalid thread ID."));
+ return -1;
+ }
+ }
+ else if (newvalue == Py_None)
+ id = -1;
+ else
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("The value of `thread' must be an integer or None."));
+ return -1;
+ }
+
+ self_bp->bp->thread = id;
+
+ return 0;
+}
+
+/* Python function to set the (Ada) task of a breakpoint. */
+static int
+bppy_set_task (PyObject *self, PyObject *newvalue, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+ int id;
+
+ BPPY_SET_REQUIRE_VALID (self_bp);
+
+ if (newvalue == NULL)
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("Cannot delete `task' attribute."));
+ return -1;
+ }
+ else if (PyInt_Check (newvalue))
+ {
+ id = (int) PyInt_AsLong (newvalue);
+ if (! valid_task_id (id))
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ _("Invalid task ID."));
+ return -1;
+ }
+ }
+ else if (newvalue == Py_None)
+ id = 0;
+ else
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("The value of `task' must be an integer or None."));
+ return -1;
+ }
+
+ self_bp->bp->task = id;
+
+ return 0;
+}
+
+
+/* Python function to set the ignore count of a breakpoint. */
+static int
+bppy_set_ignore_count (PyObject *self, PyObject *newvalue, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+ long value;
+
+ BPPY_SET_REQUIRE_VALID (self_bp);
+
+ if (newvalue == NULL)
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("Cannot delete `ignore_count' attribute."));
+ return -1;
+ }
+ else if (! PyInt_Check (newvalue))
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("The value of `ignore_count' must be an integer."));
+ return -1;
+ }
+
+ value = PyInt_AsLong (newvalue);
+ if (value < 0)
+ value = 0;
+ set_ignore_count (self_bp->number, (int) value, 0);
+
+ return 0;
+}
+
+/* Python function to set the hit count of a breakpoint. */
+static int
+bppy_set_hit_count (PyObject *self, PyObject *newvalue, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+
+ BPPY_SET_REQUIRE_VALID (self_bp);
+
+ if (newvalue == NULL)
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("Cannot delete `hit_count' attribute."));
+ return -1;
+ }
+ else if (! PyInt_Check (newvalue) || PyInt_AsLong (newvalue) != 0)
+ {
+ PyErr_SetString (PyExc_AttributeError,
+ _("The value of `hit_count' must be zero."));
+ return -1;
+ }
+
+ self_bp->bp->hit_count = 0;
+
+ return 0;
+}
+
+/* Python function to get the location of a breakpoint. */
+static PyObject *
+bppy_get_location (PyObject *self, void *closure)
+{
+ char *str;
+ breakpoint_object *obj = (breakpoint_object *) self;
+
+ BPPY_REQUIRE_VALID (obj);
+
+ if (obj->bp->type != bp_breakpoint)
+ Py_RETURN_NONE;
+
+ str = obj->bp->addr_string;
+
+ if (! str)
+ str = "";
+ return PyString_Decode (str, strlen (str), host_charset (), NULL);
+}
+
+/* Python function to get the breakpoint expression. */
+static PyObject *
+bppy_get_expression (PyObject *self, void *closure)
+{
+ char *str;
+ breakpoint_object *obj = (breakpoint_object *) self;
+
+ 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)
+ Py_RETURN_NONE;
+
+ str = obj->bp->exp_string;
+ if (! str)
+ str = "";
+
+ return PyString_Decode (str, strlen (str), host_charset (), NULL);
+}
+
+/* Python function to get the condition expression of a breakpoint. */
+static PyObject *
+bppy_get_condition (PyObject *self, void *closure)
+{
+ char *str;
+ breakpoint_object *obj = (breakpoint_object *) self;
+
+ BPPY_REQUIRE_VALID (obj);
+
+ str = obj->bp->cond_string;
+ if (! str)
+ Py_RETURN_NONE;
+
+ return PyString_Decode (str, strlen (str), host_charset (), NULL);
+}
+
+static int
+bppy_set_condition (PyObject *self, PyObject *newvalue, void *closure)
+{
+ char *exp;
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+ volatile struct gdb_exception except;
+
+ BPPY_SET_REQUIRE_VALID (self_bp);
+
+ if (newvalue == NULL)
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("Cannot delete `condition' attribute."));
+ return -1;
+ }
+ else if (newvalue == Py_None)
+ exp = "";
+ else
+ {
+ exp = python_string_to_host_string (newvalue);
+ if (exp == NULL)
+ return -1;
+ }
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ set_breakpoint_condition (self_bp->bp, exp, 0);
+ }
+ GDB_PY_SET_HANDLE_EXCEPTION (except);
+
+ return 0;
+}
+
+/* Python function to get the commands attached to a breakpoint. */
+static PyObject *
+bppy_get_commands (PyObject *self, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+ struct breakpoint *bp = self_bp->bp;
+ long length;
+ volatile struct gdb_exception except;
+ struct ui_file *string_file;
+ struct cleanup *chain;
+ PyObject *result;
+ char *cmdstr;
+
+ BPPY_REQUIRE_VALID (self_bp);
+
+ if (! self_bp->bp->commands)
+ Py_RETURN_NONE;
+
+ string_file = mem_fileopen ();
+ chain = make_cleanup_ui_file_delete (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);
+ }
+ cmdstr = ui_file_xstrdup (string_file, &length);
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ result = PyString_Decode (cmdstr, strlen (cmdstr), host_charset (), NULL);
+ do_cleanups (chain);
+ xfree (cmdstr);
+ return result;
+}
+
+/* Python function to get the breakpoint type. */
+static PyObject *
+bppy_get_type (PyObject *self, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+
+ BPPY_REQUIRE_VALID (self_bp);
+
+ return PyInt_FromLong (self_bp->bp->type);
+}
+
+/* Python function to get the breakpoint's number. */
+static PyObject *
+bppy_get_number (PyObject *self, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+
+ BPPY_REQUIRE_VALID (self_bp);
+
+ return PyInt_FromLong (self_bp->number);
+}
+
+/* Python function to get the breakpoint's thread ID. */
+static PyObject *
+bppy_get_thread (PyObject *self, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+
+ BPPY_REQUIRE_VALID (self_bp);
+
+ if (self_bp->bp->thread == -1)
+ Py_RETURN_NONE;
+
+ return PyInt_FromLong (self_bp->bp->thread);
+}
+
+/* Python function to get the breakpoint's task ID (in Ada). */
+static PyObject *
+bppy_get_task (PyObject *self, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+
+ BPPY_REQUIRE_VALID (self_bp);
+
+ if (self_bp->bp->task == 0)
+ Py_RETURN_NONE;
+
+ return PyInt_FromLong (self_bp->bp->task);
+}
+
+/* Python function to get the breakpoint's hit count. */
+static PyObject *
+bppy_get_hit_count (PyObject *self, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+
+ BPPY_REQUIRE_VALID (self_bp);
+
+ return PyInt_FromLong (self_bp->bp->hit_count);
+}
+
+/* Python function to get the breakpoint's ignore count. */
+static PyObject *
+bppy_get_ignore_count (PyObject *self, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+
+ BPPY_REQUIRE_VALID (self_bp);
+
+ return PyInt_FromLong (self_bp->bp->ignore_count);
+}
+
+/* Python function to create a new breakpoint. */
+static PyObject *
+bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
+{
+ PyObject *result;
+ static char *keywords[] = { "spec", "type", "wp_class", NULL };
+ char *spec;
+ int type = bp_breakpoint;
+ int access_type = hw_write;
+ volatile struct gdb_exception except;
+
+ if (! PyArg_ParseTupleAndKeywords (args, kwargs, "s|ii", keywords,
+ &spec, &type, &access_type))
+ return NULL;
+
+ result = subtype->tp_alloc (subtype, 0);
+ if (! result)
+ return NULL;
+ bppy_pending_object = (breakpoint_object *) result;
+ bppy_pending_object->number = -1;
+ bppy_pending_object->bp = NULL;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ switch (type)
+ {
+ case bp_breakpoint:
+ {
+ create_breakpoint (python_gdbarch,
+ spec, NULL, -1,
+ 0,
+ 0, 0, 0,
+ 0,
+ AUTO_BOOLEAN_TRUE,
+ NULL, 0, 1);
+ break;
+ }
+ case bp_watchpoint:
+ {
+ if (access_type == hw_write)
+ watch_command_wrapper (spec, 0);
+ else if (access_type == hw_access)
+ awatch_command_wrapper (spec, 0);
+ else if (access_type == hw_read)
+ rwatch_command_wrapper (spec, 0);
+ else
+ error(_("Cannot understand watchpoint access type."));
+ break;
+ }
+ default:
+ error(_("Do not understand breakpoint type to set."));
+ }
+ }
+ if (except.reason < 0)
+ {
+ subtype->tp_free (result);
+ return PyErr_Format (except.reason == RETURN_QUIT
+ ? PyExc_KeyboardInterrupt : PyExc_RuntimeError,
+ "%s", except.message);
+ }
+
+ BPPY_REQUIRE_VALID ((breakpoint_object *) result);
+ return result;
+}
+
+\f
+
+/* Static function to return a tuple holding all breakpoints. */
+
+PyObject *
+gdbpy_breakpoints (PyObject *self, PyObject *args)
+{
+ PyObject *result;
+
+ if (bppy_live == 0)
+ Py_RETURN_NONE;
+
+ result = PyTuple_New (bppy_live);
+ if (result)
+ {
+ int i, out = 0;
+ for (i = 0; out < bppy_live; ++i)
+ {
+ if (! bppy_breakpoints[i])
+ continue;
+ Py_INCREF (bppy_breakpoints[i]);
+ PyTuple_SetItem (result, out, (PyObject *) bppy_breakpoints[i]);
+ ++out;
+ }
+ }
+ return result;
+}
+
+\f
+
+/* Event callback functions. */
+
+/* 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)
+{
+ breakpoint_object *newbp;
+ struct breakpoint *bp = NULL;
+ PyGILState_STATE state;
+
+ if (num < 0)
+ return;
+
+ bp = get_breakpoint (num);
+ if (! bp)
+ return;
+
+ if (bp->type != bp_breakpoint
+ && bp->type != bp_watchpoint
+ && bp->type != bp_hardware_watchpoint
+ && bp->type != bp_read_watchpoint
+ && 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)
+ {
+ newbp = bppy_pending_object;
+ bppy_pending_object = NULL;
+ }
+ else
+ newbp = PyObject_New (breakpoint_object, &breakpoint_object_type);
+ if (newbp)
+ {
+ PyObject *hookfn;
+
+ newbp->number = num;
+ newbp->bp = bp;
+ bppy_breakpoints[num] = newbp;
+ Py_INCREF (newbp);
+ }
+
+ /* Just ignore errors here. */
+ PyErr_Clear ();
+
+ PyGILState_Release (state);
+}
+
+/* Callback that is used when a breakpoint is deleted. This will
+ invalidate the corresponding Python object. */
+static void
+gdbpy_breakpoint_deleted (int num)
+{
+ PyGILState_STATE state;
+
+ state = PyGILState_Ensure ();
+ if (bpnum_is_valid (num))
+ {
+ bppy_breakpoints[num]->bp = NULL;
+ Py_DECREF (bppy_breakpoints[num]);
+ bppy_breakpoints[num] = NULL;
+ --bppy_live;
+ }
+ PyGILState_Release (state);
+}
+
+\f
+
+/* Initialize the Python breakpoint code. */
+void
+gdbpy_initialize_breakpoints (void)
+{
+ int i;
+
+ breakpoint_object_type.tp_new = bppy_new;
+ if (PyType_Ready (&breakpoint_object_type) < 0)
+ return;
+
+ Py_INCREF (&breakpoint_object_type);
+ PyModule_AddObject (gdb_module, "Breakpoint",
+ (PyObject *) &breakpoint_object_type);
+
+ observer_attach_breakpoint_created (gdbpy_breakpoint_created);
+ observer_attach_breakpoint_deleted (gdbpy_breakpoint_deleted);
+
+ /* Add breakpoint types constants. */
+ for (i = 0; pybp_codes[i].name; ++i)
+ {
+ if (PyModule_AddIntConstant (gdb_module,
+ /* Cast needed for Python 2.4. */
+ (char *) pybp_codes[i].name,
+ pybp_codes[i].code) < 0)
+ return;
+ }
+
+ /* Add watchpoint types constants. */
+ for (i = 0; pybp_watch_types[i].name; ++i)
+ {
+ if (PyModule_AddIntConstant (gdb_module,
+ /* Cast needed for Python 2.4. */
+ (char *) pybp_watch_types[i].name,
+ pybp_watch_types[i].code) < 0)
+ return;
+ }
+
+}
+
+\f
+
+static PyGetSetDef breakpoint_object_getset[] = {
+ { "enabled", bppy_get_enabled, bppy_set_enabled,
+ "Boolean telling whether the breakpoint is enabled.", NULL },
+ { "silent", bppy_get_silent, bppy_set_silent,
+ "Boolean telling whether the breakpoint is silent.", NULL },
+ { "thread", bppy_get_thread, bppy_set_thread,
+ "Thread ID for the breakpoint.\n\
+If the value is a thread ID (integer), then this is a thread-specific breakpoint.\n\
+If the value is None, then this breakpoint is not thread-specific.\n\
+No other type of value can be used.", NULL },
+ { "task", bppy_get_task, bppy_set_task,
+ "Thread ID for the breakpoint.\n\
+If the value is a task ID (integer), then this is an Ada task-specific breakpoint.\n\
+If the value is None, then this breakpoint is not task-specific.\n\
+No other type of value can be used.", NULL },
+ { "ignore_count", bppy_get_ignore_count, bppy_set_ignore_count,
+ "Number of times this breakpoint should be automatically continued.",
+ NULL },
+ { "number", bppy_get_number, NULL,
+ "Breakpoint's number assigned by GDB.", NULL },
+ { "hit_count", bppy_get_hit_count, bppy_set_hit_count,
+ "Number of times the breakpoint has been hit.\n\
+Can be set to zero to clear the count. No other value is valid\n\
+when setting this property.", NULL },
+ { "location", bppy_get_location, NULL,
+ "Location of the breakpoint, as specified by the user.", NULL},
+ { "expression", bppy_get_expression, NULL,
+ "Expression of the breakpoint, as specified by the user.", NULL},
+ { "condition", bppy_get_condition, bppy_set_condition,
+ "Condition of the breakpoint, as specified by the user,\
+or None if no condition set."},
+ { "commands", bppy_get_commands, NULL,
+ "Commands of the breakpoint, as specified by the user."},
+ { "type", bppy_get_type, NULL,
+ "Type of breakpoint."},
+ { NULL } /* Sentinel. */
+};
+
+static PyMethodDef breakpoint_object_methods[] =
+{
+ { "is_valid", bppy_is_valid, METH_NOARGS,
+ "Return true if this breakpoint is valid, false if not." },
+ { NULL } /* Sentinel. */
+};
+
+static PyTypeObject breakpoint_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.Breakpoint", /*tp_name*/
+ sizeof (breakpoint_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*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 object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ breakpoint_object_methods, /* tp_methods */
+ 0, /* tp_members */
+ breakpoint_object_getset /* tp_getset */
+};
--- /dev/null
+# Copyright (C) 2010 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 <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite. It tests the mechanism
+# exposing values to Python.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+set testfile "py-breakpoint"
+set srcfile ${testfile}.c
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
+ return -1
+}
+
+# Run a command in GDB, and report a failure if a Python exception is thrown.
+# If report_pass is true, report a pass if no exception is thrown.
+proc gdb_py_test_silent_cmd {cmd name report_pass} {
+ global gdb_prompt
+
+ gdb_test_multiple $cmd $name {
+ -re "Traceback.*$gdb_prompt $" { fail $name }
+ -re "$gdb_prompt $" { if $report_pass { pass $name } }
+ }
+}
+
+# Start with a fresh gdb.
+clean_restart ${testfile}
+
+# Skip all tests if Python scripting is not enabled.
+if { [skip_python_tests] } { continue }
+
+if ![runto_main] then {
+ fail "Cannot run to main."
+ return 0
+}
+
+global hex decimal
+
+# Initially there should be one breakpoint: main.
+
+gdb_py_test_silent_cmd "python blist = gdb.breakpoints()" "Get Breakpoint List" 0
+gdb_test "python print blist\[0\]" "<gdb.Breakpoint object at $hex>" "Check obj exists"
+gdb_test "python print blist\[0\].location" "main." "Check breakpoint location"
+
+gdb_breakpoint [gdb_get_line_number "Break at multiply."]
+gdb_continue_to_breakpoint "Break at multiply."
+
+# Check that the Python breakpoint code noted the addition of a
+# breakpoint "behind the scenes".
+gdb_py_test_silent_cmd "python blist = gdb.breakpoints()" "Get Breakpoint List" 0
+gdb_test "python print len(blist)" "2" "Check for two breakpoints"
+gdb_test "python print blist\[0\]" "<gdb.Breakpoint object at $hex>" "Check obj exists"
+gdb_test "python print blist\[0\].location" "main." "Check breakpoint location"
+gdb_test "python print blist\[1\]" "<gdb.Breakpoint object at $hex>" "Check obj exists"
+gdb_test "python print blist\[1\].location" "py-breakpoint\.c:41*" "Check breakpoint location"
+
+# Check hit and ignore counts.
+gdb_test "python print blist\[1\].hit_count" "1" "Check breakpoint hit count"
+gdb_py_test_silent_cmd "python blist\[1\].ignore_count = 4" "Set breakpoint hit count" 0
+gdb_continue_to_breakpoint "Break at multiply."
+gdb_test "python print blist\[1\].hit_count" "6" "Check breakpoint hit count"
+gdb_test "print result" "545" "Check expected variable result after 6 iterations"
+
+# Test breakpoint is enabled and disabled correctly..
+gdb_breakpoint [gdb_get_line_number "Break at add."]
+gdb_continue_to_breakpoint "Break at add."
+gdb_test "python print blist\[1\].enabled" "True" "Check breakpoint enabled."
+gdb_py_test_silent_cmd "python blist\[1\].enabled = False" "Set breakpoint disabled." 0
+gdb_continue_to_breakpoint "Break at add."
+gdb_py_test_silent_cmd "python blist\[1\].enabled = True" "Set breakpoint enabled." 0
+gdb_continue_to_breakpoint "Break at multiply."
+
+# Test other getters and setters.
+gdb_py_test_silent_cmd "python blist = gdb.breakpoints()" "Get Breakpoint List" 0
+gdb_test "python print blist\[1\].thread" "None" "Check breakpoint thread"
+gdb_test "python print blist\[1\].type == gdb.BP_BREAKPOINT" "True" "Check breakpoint type"
+gdb_test "python print blist\[0\].number" "1" "Check breakpoint number"
+gdb_test "python print blist\[1\].number" "2" "Check breakpoint number"
+gdb_test "python print blist\[2\].number" "3" "Check breakpoint number"
+
+# Start with a fresh gdb.
+clean_restart ${testfile}
+
+if ![runto_main] then {
+ fail "Cannot run to main."
+ return 0
+}
+
+# Test conditional setting.
+set bp_location1 [gdb_get_line_number "Break at multiply."]
+gdb_py_test_silent_cmd "python bp1 = gdb.Breakpoint (\"$bp_location1\")" "Set breakpoint" 0
+gdb_continue_to_breakpoint "Break at multiply."
+gdb_py_test_silent_cmd "python bp1.condition = \"i == 5\"" "Set breakpoint" 0
+gdb_test "python print bp1.condition" "i == 5" "Test conditional has been set"
+gdb_continue_to_breakpoint "Break at multiply."
+gdb_test "print i" "5" "Test conditional breakpoint stopped after five iterations"
+gdb_py_test_silent_cmd "python bp1.condition = None" "Clear condition" 0
+gdb_test "python print bp1.condition" "None" "Test conditional read"
+gdb_continue_to_breakpoint "Break at multiply."
+gdb_test "print i" "6" "Test breakpoint stopped after six iterations"
+
+# Test commands.
+gdb_breakpoint [gdb_get_line_number "Break at add."]
+set test {commands $bpnum}
+gdb_test_multiple $test $test { -re "\r\n>$" { pass $test } }
+set test {print "Command for breakpoint has been executed."}
+gdb_test_multiple $test $test { -re "\r\n>$" { pass $test } }
+set test {print result}
+gdb_test_multiple $test $test { -re "\r\n>$" { pass $test } }
+gdb_test "end"
+
+gdb_py_test_silent_cmd "python blist = gdb.breakpoints()" "Get Breakpoint List" 0
+gdb_test "python print blist\[len(blist)-1\].commands" "print \"Command for breakpoint has been executed.\".*print result"
+
+# Watchpoints
+# Start with a fresh gdb.
+clean_restart ${testfile}
+
+if ![runto_main] then {
+ fail "Cannot run to main."
+ return 0
+}
+
+gdb_py_test_silent_cmd "python wp1 = gdb.Breakpoint (\"result\", type=gdb.BP_WATCHPOINT, wp_class=gdb.WP_WRITE )" "Set watchpoint" 0
+gdb_test "continue" ".*watchpoint.*result.*Old value = 0.*New value = 25.*main.*" "Test watchpoint write"
+
+
+