2010-04-09 Phil Muldoon <pmuldoon@redhat.com>
authorPhil Muldoon <pmuldoon@redhat.com>
Fri, 9 Apr 2010 09:41:43 +0000 (09:41 +0000)
committerPhil Muldoon <pmuldoon@redhat.com>
Fri, 9 Apr 2010 09:41:43 +0000 (09:41 +0000)
    Thiago Jung Bauermann  <bauerman@br.ibm.com>
        Tom Tromey  <tromey@redhat.com>

* breakpoint.c (condition_command): Simplify.  Move condition
setting code to ...
(set_breakpoint_condition): ... here.  New function.
* breakpoint.h  (set_breakpoint_condition): Declare.
* Makefile.in (SUBDIR_PYTHON_OBS): Add py-breakpoint.
(SUBDIR_PYTHON_SRCS): Likewise.
(py-breakpoint.o): New rule.
* python/py-breakpoint.c: New file.
* python/python-internal.h (gdbpy_breakpoints)
(gdbpy_initialize_breakpoints): Declare.
(GDB_PY_SET_HANDLE_EXCEPTION) Define.

2010-04-09  Phil Muldoon  <pmuldoon@redhat.com>

* gdb.python/py-breakpoint.exp: New File.
* gdb.python/py-breakpoint.C: Ditto.

2010-04-09  Phil Muldoon  <pmuldoon@redhat.com>
    Thiago Jung Bauermann  <bauerman@br.ibm.com>
        Tom Tromey  <tromey@redhat.com>

* gdb.texinfo (Breakpoints In Python): New Node.

14 files changed:
gdb/ChangeLog
gdb/Makefile.in
gdb/NEWS
gdb/breakpoint.c
gdb/breakpoint.h
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/python/py-breakpoint.c [new file with mode: 0644]
gdb/python/python-internal.h
gdb/python/python.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.python/Makefile.in
gdb/testsuite/gdb.python/py-breakpoint.c [new file with mode: 0644]
gdb/testsuite/gdb.python/py-breakpoint.exp [new file with mode: 0644]

index 9e7ce8769f028f43d3d0b5c8c78089af6fd5cb22..ae3449eca1e675e9f2ebaedcb25b63e87c2702df 100644 (file)
@@ -1,3 +1,19 @@
+2010-04-09  Phil Muldoon  <pmuldoon@redhat.com>
+           Thiago Jung Bauermann  <bauerman@br.ibm.com>
+           Tom Tromey  <tromey@redhat.com>
+
+       * breakpoint.c (condition_command): Simplify.  Move condition
+       setting code to ...
+       (set_breakpoint_condition): ... here.  New function.
+       * breakpoint.h  (set_breakpoint_condition): Declare.
+       * Makefile.in (SUBDIR_PYTHON_OBS): Add py-breakpoint.
+       (SUBDIR_PYTHON_SRCS): Likewise.
+       (py-breakpoint.o): New rule.
+       * python/py-breakpoint.c: New file.
+       * python/python-internal.h (gdbpy_breakpoints)
+       (gdbpy_initialize_breakpoints): Declare.
+       (GDB_PY_SET_HANDLE_EXCEPTION) Define.
+
 2010-04-09  Pedro Alves  <pedro@codesourcery.com>
 
        * regformats/regdat.sh: Include server.h.  Don't include
index 72b546dfabc9947d0a84900ed914d659e488a368..b507d3e109875f43fa7926b02cb403396c09e436 100644 (file)
@@ -268,6 +268,7 @@ SUBDIR_TUI_CFLAGS= \
 SUBDIR_PYTHON_OBS = \
        python.o \
        py-block.o \
+       py-breakpoint.o \
        py-cmd.o \
        py-frame.o \
        py-function.o \
@@ -282,6 +283,7 @@ SUBDIR_PYTHON_OBS = \
 SUBDIR_PYTHON_SRCS = \
        python/python.c \
        python/py-block.c \
+       python/py-breakpoint.c \
        python/py-cmd.c \
        python/py-frame.c \
        python/py-function.c \
@@ -1986,6 +1988,10 @@ py-block.o: $(srcdir)/python/py-block.c
        $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-block.c
        $(POSTCOMPILE)
 
+py-breakpoint.o: $(srcdir)/python/py-breakpoint.c
+       $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpoint.c
+       $(POSTCOMPILE)
+
 py-cmd.o: $(srcdir)/python/py-cmd.c
        $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-cmd.c
        $(POSTCOMPILE)
index 3d12fbead3ab5eed5842404fdf71bdb1de819766..8ccdc080cc38c58a522add2e3857552d71c2cf9e 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -25,8 +25,8 @@
 
 * Python scripting
 
-** The GDB Python API now has access to symbols, symbol tables, and
-   frame's code blocks.
+** The GDB Python API now has access to breakpoints, symbols, symbol
+   tables, and frame's code blocks.
 
 ** New methods gdb.target_charset and gdb.target_wide_charset.
 
index 213d96cbb6c11408db5245cf4b2e0d840efa94e7..8ef5cd926a01e223d5c8a2022357530fced966bf 100644 (file)
@@ -709,6 +709,61 @@ get_breakpoint (int num)
 }
 
 \f
+
+void
+set_breakpoint_condition (struct breakpoint *b, char *exp,
+                         int from_tty)
+{
+  struct bp_location *loc = b->loc;
+
+  for (; loc; loc = loc->next)
+    {
+      xfree (loc->cond);
+      loc->cond = NULL;
+    }
+  xfree (b->cond_string);
+  b->cond_string = NULL;
+  xfree (b->cond_exp);
+  b->cond_exp = NULL;
+
+  if (*exp == 0)
+    {
+      if (from_tty)
+       printf_filtered (_("Breakpoint %d now unconditional.\n"), b->number);
+    }
+  else
+    {
+      char *arg = exp;
+      /* I don't know if it matters whether this is the string the user
+        typed in or the decompiled expression.  */
+      b->cond_string = xstrdup (arg);
+      b->condition_not_parsed = 0;
+
+      if (is_watchpoint (b))
+       {
+         innermost_block = NULL;
+         arg = exp;
+         b->cond_exp = parse_exp_1 (&arg, 0, 0);
+         if (*arg)
+           error (_("Junk at end of expression"));
+         b->cond_exp_valid_block = innermost_block;
+       }
+      else
+       {
+         for (loc = b->loc; loc; loc = loc->next)
+           {
+             arg = exp;
+             loc->cond =
+               parse_exp_1 (&arg, block_for_pc (loc->address), 0);
+             if (*arg)
+               error (_("Junk at end of expression"));
+           }
+       }
+    }
+  breakpoints_changed ();
+  observer_notify_breakpoint_modified (b->number);
+}
+
 /* condition N EXP -- set break condition of breakpoint N to EXP.  */
 
 static void
@@ -729,53 +784,7 @@ condition_command (char *arg, int from_tty)
   ALL_BREAKPOINTS (b)
     if (b->number == bnum)
       {
-       struct bp_location *loc = b->loc;
-       for (; loc; loc = loc->next)
-         {
-           xfree (loc->cond);
-           loc->cond = NULL;
-         }
-       xfree (b->cond_string);
-       b->cond_string = NULL;
-       xfree (b->cond_exp);
-       b->cond_exp = NULL;
-
-       if (*p == 0)
-         {
-           if (from_tty)
-             printf_filtered (_("Breakpoint %d now unconditional.\n"), bnum);
-         }
-       else
-         {
-           arg = p;
-           /* I don't know if it matters whether this is the string the user
-              typed in or the decompiled expression.  */
-           b->cond_string = xstrdup (arg);
-           b->condition_not_parsed = 0;
-
-           if (is_watchpoint (b))
-             {
-               innermost_block = NULL;
-               arg = p;
-               b->cond_exp = parse_exp_1 (&arg, 0, 0);
-               if (*arg)
-                 error (_("Junk at end of expression"));
-               b->cond_exp_valid_block = innermost_block;
-             }
-           else
-             {
-               for (loc = b->loc; loc; loc = loc->next)
-                 {
-                   arg = p;
-                   loc->cond =
-                     parse_exp_1 (&arg, block_for_pc (loc->address), 0);
-                   if (*arg)
-                     error (_("Junk at end of expression"));
-                 }
-             }
-         }
-       breakpoints_changed ();
-       observer_notify_breakpoint_modified (b->number);
+       set_breakpoint_condition (b, arg, from_tty);
        return;
       }
 
index 912cc3c84526d7e6470a4b1eb637b185d9d7617b..99638270fa6c1e376f6139a0146afb2807cd0362 100644 (file)
@@ -1005,6 +1005,10 @@ extern int breakpoints_always_inserted_mode (void);
    in our opinion won't ever trigger.  */
 extern void breakpoint_retire_moribund (void);
 
+/* Set break condition of breakpoint B to EXP.  */
+extern void set_breakpoint_condition (struct breakpoint *b, char *exp,
+                                     int from_tty);
+
 /* Checks if we are catching syscalls or not.
    Returns 0 if not, greater than 0 if we are.  */
 extern int catch_syscall_enabled (void);
index 9b98dc08bd5be99f4f6e4c481cbcf5e760eebc88..30585770d6f168ae77a96a5645e09e864aef4f97 100644 (file)
@@ -1,3 +1,9 @@
+2010-04-09  Phil Muldoon  <pmuldoon@redhat.com>
+           Thiago Jung Bauermann  <bauerman@br.ibm.com>
+           Tom Tromey  <tromey@redhat.com>
+
+       * gdb.texinfo (Breakpoints In Python): New Node.
+
 2010-04-08  Stan Shebs  <stan@codesourcery.com>
 
        * gdb.texinfo (Tracepoint Packets): Describe disconn and circular
index bd2b441299e0a43127da4b6ce72532be2d2a289b..4ddda64c89787c8069f871988b6bd42c2c414bdd 100644 (file)
@@ -19714,6 +19714,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
 * 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
@@ -19739,6 +19740,12 @@ command as having originated from the user invoking it interactively.
 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
@@ -21279,6 +21286,163 @@ Return the symbol table's source absolute file name.
 @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.
 
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
new file mode 100644 (file)
index 0000000..4750d6d
--- /dev/null
@@ -0,0 +1,862 @@
+/* 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 */
+};
index e8fcfa9e7f690b4b44f9c0ea6efed9a04bf0abee..98d2b3f2b9d4b7dd2ee8d2633bdb62b4ac879f3a 100644 (file)
@@ -75,6 +75,7 @@ extern PyTypeObject block_object_type;
 extern PyTypeObject symbol_object_type;
 
 PyObject *gdbpy_history (PyObject *self, PyObject *args);
+PyObject *gdbpy_breakpoints (PyObject *, PyObject *);
 PyObject *gdbpy_frame_stop_reason_string (PyObject *, PyObject *);
 PyObject *gdbpy_lookup_symbol (PyObject *self, PyObject *args, PyObject *kw);
 PyObject *gdbpy_selected_frame (PyObject *self, PyObject *args);
@@ -82,6 +83,7 @@ PyObject *gdbpy_block_for_pc (PyObject *self, PyObject *args);
 PyObject *gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw);
 PyObject *gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
                                           const char *encoding, struct type *type);
+PyObject *gdbpy_get_hook_function (const char *);
 
 PyObject *symtab_and_line_to_sal_object (struct symtab_and_line sal);
 PyObject *symtab_to_symtab_object (struct symtab *symtab);
@@ -111,6 +113,7 @@ void gdbpy_initialize_blocks (void);
 void gdbpy_initialize_types (void);
 void gdbpy_initialize_functions (void);
 void gdbpy_initialize_objfile (void);
+void gdbpy_initialize_breakpoints (void);
 void gdbpy_initialize_lazy_string (void);
 
 struct cleanup *make_cleanup_py_decref (PyObject *py);
@@ -131,6 +134,18 @@ extern const struct language_defn *python_language;
                             "%s", Exception.message);                  \
     } while (0)
 
+/* Use this after a TRY_EXCEPT to throw the appropriate Python
+   exception.  This macro is for use inside setter functions.  */
+#define GDB_PY_SET_HANDLE_EXCEPTION(Exception)                         \
+    do {                                                               \
+      if (Exception.reason < 0)                                                \
+        {                                                              \
+         PyErr_Format (Exception.reason == RETURN_QUIT                 \
+                       ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, \
+                       "%s", Exception.message);                       \
+         return -1;                                                    \
+       }                                                               \
+    } while (0)
 
 void gdbpy_print_stack (void);
 
index 5ce4829b5f1896458242c676ba1055f73e66056b..9cf4520c060b8146d69809be4a5c73fffb1c429a 100644 (file)
@@ -668,6 +668,7 @@ Enables or disables auto-loading of Python code when an object is opened."),
   gdbpy_initialize_functions ();
   gdbpy_initialize_types ();
   gdbpy_initialize_objfile ();
+  gdbpy_initialize_breakpoints ();
   gdbpy_initialize_lazy_string ();
 
   PyRun_SimpleString ("import gdb");
@@ -726,6 +727,9 @@ static PyMethodDef GdbMethods[] =
   { "parameter", gdbpy_parameter, METH_VARARGS,
     "Return a gdb parameter's value" },
 
+  { "breakpoints", gdbpy_breakpoints, METH_NOARGS,
+    "Return a tuple of all breakpoint objects" },
+
   { "default_visualizer", gdbpy_default_visualizer, METH_VARARGS,
     "Find the default visualizer for a Value." },
 
index 1c0b8b5c401d23e3d67cbd4d88c5462226ca995c..30c5df177d68ba702469e777b557ac9a1d494b01 100644 (file)
@@ -1,3 +1,8 @@
+2010-04-09  Phil Muldoon  <pmuldoon@redhat.com>
+
+       * gdb.python/py-breakpoint.exp: New File.
+       * gdb.python/py-breakpoint.C: Ditto.
+
 2010-04-08  Stan Shebs  <stan@codesourcery.com>
 
        * gdb.trace/actions.exp: Clear default-collect.
index 578ac5420ff6cbcd289ee44332dd9b319e15f3d8..c6a267817c8457ff8e4a56cf3f8f2831d5e5d1ae 100644 (file)
@@ -2,7 +2,7 @@ VPATH = @srcdir@
 srcdir = @srcdir@
 
 EXECUTABLES = py-type py-value py-prettyprint py-template py-block \
-       py-symbol py-mi
+               py-symbol py-mi py-breakpoint
 
 all info install-info dvi install uninstall installcheck check:
        @echo "Nothing to be done for $@..."
diff --git a/gdb/testsuite/gdb.python/py-breakpoint.c b/gdb/testsuite/gdb.python/py-breakpoint.c
new file mode 100644 (file)
index 0000000..b2ad81b
--- /dev/null
@@ -0,0 +1,46 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 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/>.
+*/
+
+
+
+int multiply (int i)
+{
+  return i * i;
+}
+
+int add (int i)
+{
+  return i + i; 
+}
+
+
+int main (int argc, char *argv[])
+{
+  int foo = 5;
+  int bar = 42;
+  int result = 0;
+  int i;
+
+  for (i = 0; i < 10; i++)
+    {
+      result += multiply (foo);  /* Break at multiply. */
+      result += add (bar); /* Break at add. */
+    }
+
+  return 0; /* Break at end. */
+}
diff --git a/gdb/testsuite/gdb.python/py-breakpoint.exp b/gdb/testsuite/gdb.python/py-breakpoint.exp
new file mode 100644 (file)
index 0000000..903912c
--- /dev/null
@@ -0,0 +1,142 @@
+# 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"
+
+
+