This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC][patch 4/9] export breakpoints to Python


2008-04-29  Tom Tromey <tromey@redhat.com>

	* Makefile.in (SUBDIR_PYTHON_OBS): Add python-breakpoint.o.
	(SUBDIR_PYTHON_SRCS): Add python/breakpoint.c.
	(python-breakpoint.o): New target.
	* python/breakpoint.c: New file.
	* python/hooks.c (gdbpy_initialize_hooks): Register breakpoint
	event callback functions.
	* python/python-internal.h (gdbpy_get_breakpoints,
	gdbpy_initialize_breakpoints, gdbpy_breakpoint_created,
	gdbpy_breakpoint_deleted): Declare.
	* python/python.c (demand_python): Add "get_breakpoints"
	function.  Call gdbpy_initialize_breakpoints.

Index: tromey.git/gdb/Makefile.in
===================================================================
--- tromey.git.orig/gdb/Makefile.in	2008-04-29 11:05:09.000000000 -0300
+++ tromey.git/gdb/Makefile.in	2008-04-29 11:05:15.000000000 -0300
@@ -262,10 +262,12 @@ SUBDIR_TUI_CFLAGS= \
 #
 SUBDIR_PYTHON_OBS = \
 	python.o \
+	python-breakpoint.o \
 	python-hooks.o \
 	python-value.o
 SUBDIR_PYTHON_SRCS = \
 	python/python.c \
+	python/breakpoint.c \
 	python/hooks.c \
 	python/value.c
 SUBDIR_PYTHON_DEPS =
@@ -3415,6 +3417,11 @@ python.o: $(srcdir)/python/python.c $(de
 	$(command_h) $(libiberty_h) $(cli_decode_h) $(charset_h) $(top_h) \
 	$(exceptions_h) $(python_internal_h) $(version_h)
 	$(CC) -c $(INTERNAL_CFLAGS) $(PYTHON_CFLAGS) $(srcdir)/python/python.c
+python-breakpoint.o: $(srcdir)/python/breakpoint.c $(defs_h) $(python_h) \
+	$(value_h) $(exceptions_h) $(python_internal_h) $(charset_h) \
+	$(breakpoint_h) $(gdbcmd_h)
+	$(CC) -c $(INTERNAL_CFLAGS) $(PYTHON_CFLAGS) \
+	$(srcdir)/python/breakpoint.c -o python-breakpoint.o
 python-hooks.o: $(srcdir)/python/hooks.c $(defs_h) $(cli_decode_h) \
 	$(charset_h) $(gdb_events_h) $(python_h) $(python_internal_h)
 	$(CC) -c $(INTERNAL_CFLAGS) $(PYTHON_CFLAGS) \
Index: tromey.git/gdb/python/breakpoint.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ tromey.git/gdb/python/breakpoint.c	2008-04-29 11:05:15.000000000 -0300
@@ -0,0 +1,408 @@
+/* Python interface to breakpoints
+
+   Copyright (C) 2008 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"
+
+
+/* From breakpoint.c.  */
+extern struct breakpoint *breakpoint_chain;
+
+
+typedef struct breakpoint_object breakpoint_object;
+
+static PyObject *bppy_is_valid (PyObject *, PyObject *);
+static PyObject *bppy_is_enabled (PyObject *, PyObject *);
+static PyObject *bppy_is_silent (PyObject *, PyObject *);
+static PyObject *bppy_set_enabled (PyObject *, PyObject *);
+static PyObject *bppy_set_silent (PyObject *, PyObject *);
+static PyObject *bppy_get_location (PyObject *, PyObject *);
+static PyObject *bppy_get_condition (PyObject *, PyObject *);
+static PyObject *bppy_get_commands (PyObject *, PyObject *);
+
+
+/* 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;
+};
+
+#define BPPY_VALID_P(Num)			\
+    ((Num) >= 0					\
+     && (Num) < bppy_slots			\
+     && bppy_breakpoints[Num] != NULL)
+
+#define BPPY_REQUIRE_VALID(Breakpoint)					\
+    do {								\
+      if (! BPPY_VALID_P ((Breakpoint)->number))			\
+	return PyErr_Format (PyExc_RuntimeError, "breakpoint %d is invalid", \
+			     (Breakpoint)->number);			\
+    } while (0)
+
+static PyMethodDef breakpoint_object_methods[] =
+{
+  { "is_valid", bppy_is_valid, METH_NOARGS,
+    "Return true if this breakpoint is valid, false if not." },
+  { "is_enabled", bppy_is_enabled, METH_NOARGS,
+    "Return true if this breakpoint is enabled, false if disabled." },
+  { "is_silent", bppy_is_silent, METH_NOARGS,
+    "Return true if this breakpoint is silent, false if verbose." },
+
+  { "set_enabled", bppy_set_enabled, METH_O,
+    "Enable or disable this breakpoint" },
+  { "set_silent", bppy_set_silent, METH_O,
+    "Make this breakpoint quiet or verbose" },
+
+  { "get_location", bppy_get_location, METH_NOARGS,
+    "Return the location of this breakpoint, as specified by the user"},
+  { "get_condition", bppy_get_condition, METH_NOARGS,
+    "Return the condition of this breakpoint, as specified by the user.\n\
+Returns None if no condition set."},
+  { "get_commands", bppy_get_commands, METH_NOARGS,
+    "Return the commands of this breakpoint, as specified by the user"},
+
+  { 0 }
+};
+
+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 */
+};
+
+static PyObject *
+bppy_is_valid (PyObject *self, PyObject *args)
+{
+  if (((breakpoint_object *) self)->bp)
+    Py_RETURN_TRUE;
+  Py_RETURN_FALSE;
+}
+
+static PyObject *
+bppy_is_enabled (PyObject *self, PyObject *args)
+{
+  if (! ((breakpoint_object *) self)->bp)
+    Py_RETURN_FALSE;
+  /* Not clear what we really want here.  */
+  if (((breakpoint_object *) self)->bp->enable_state == bp_enabled)
+    Py_RETURN_TRUE;
+  Py_RETURN_FALSE;
+}
+
+static PyObject *
+bppy_is_silent (PyObject *self, PyObject *args)
+{
+  BPPY_REQUIRE_VALID ((breakpoint_object *) self);
+  if (((breakpoint_object *) self)->bp->silent)
+    Py_RETURN_TRUE;
+  Py_RETURN_FALSE;
+}
+
+static PyObject *
+bppy_set_enabled (PyObject *self, PyObject *newvalue)
+{
+  breakpoint_object *self_bp = (breakpoint_object *) self;
+
+  BPPY_REQUIRE_VALID (self_bp);
+  if (! PyBool_Check (newvalue))
+    return PyErr_Format (PyExc_RuntimeError, "argument must be boolean");
+
+  if (newvalue == Py_True)
+    enable_breakpoint (self_bp->bp);
+  else
+    disable_breakpoint (self_bp->bp);
+
+  Py_RETURN_NONE;
+}
+
+static PyObject *
+bppy_set_silent (PyObject *self, PyObject *newvalue)
+{
+  breakpoint_object *self_bp = (breakpoint_object *) self;
+
+  BPPY_REQUIRE_VALID (self_bp);
+  if (! PyBool_Check (newvalue))
+    return PyErr_Format (PyExc_RuntimeError, "argument must be boolean");
+
+  self_bp->bp->silent = (newvalue == Py_True);
+
+  Py_RETURN_NONE;
+}
+
+static PyObject *
+bppy_get_location (PyObject *self, PyObject *args)
+{
+  char *str;
+
+  BPPY_REQUIRE_VALID ((breakpoint_object *) self);
+  str = ((breakpoint_object *) self)->bp->addr_string;
+  /* FIXME: watchpoints?  tracepoints?  */
+  if (! str)
+    str = "";
+  return PyString_Decode (str, strlen (str), host_charset (),
+			  NULL /* FIXME */);
+}
+
+static PyObject *
+bppy_get_condition (PyObject *self, PyObject *args)
+{
+  char *str;
+  BPPY_REQUIRE_VALID ((breakpoint_object *) self);
+
+  str = ((breakpoint_object *) self)->bp->cond_string;
+  if (! str)
+    Py_RETURN_NONE;
+  return PyString_Decode (str, strlen (str), host_charset (),
+			  NULL /* FIXME */);
+}
+
+static PyObject *
+bppy_get_commands (PyObject *self, PyObject *args)
+{
+  breakpoint_object *self_bp = (breakpoint_object *) self;
+  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)
+    {
+      /* FIXME: this can fail.  Maybe we need to be making a new
+	 ui_out object here?  */
+      ui_out_redirect (uiout, string_file);
+      print_command_lines (uiout, self_bp->bp->commands, 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 /* FIXME */);
+  do_cleanups (chain);
+  xfree (cmdstr);
+  return result;
+}
+
+static PyObject *
+bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
+{
+  PyObject *result;
+  char *spec;
+  volatile struct gdb_exception except;
+
+  /* FIXME: allow condition, thread, temporary, ... ? */
+  if (! PyArg_ParseTuple (args, "s", &spec))
+    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)
+    {
+      set_breakpoint (spec, NULL, 0, 0, -1, 0, AUTO_BOOLEAN_TRUE);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  BPPY_REQUIRE_VALID ((breakpoint_object *) result);
+  return result;
+}
+
+
+
+/* Static function to return a tuple holding all breakpoints.  */
+
+PyObject *
+gdbpy_get_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;
+}
+
+
+
+/* Event callback functions.  */
+
+void
+gdbpy_breakpoint_created (int num)
+{
+  breakpoint_object *newbp;
+  struct breakpoint *bp;
+
+  if (num < 0)
+    return;
+
+  for (bp = breakpoint_chain; bp; bp = bp->next)
+    if (bp->number == num)
+      break;
+  if (! bp)
+    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;
+
+  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;
+
+      hookfn = gdbpy_get_hook_function ("new_breakpoint");
+      if (hookfn)
+	{
+	  /* FIXME: refc?  */
+	  PyObject_CallFunctionObjArgs (hookfn, newbp, NULL);
+	}
+    }
+
+  if (PyErr_Occurred ())
+    {
+      /* FIXME -- what to do?  */
+      PyErr_Print ();
+    }
+}
+
+void
+gdbpy_breakpoint_deleted (int num)
+{
+  if (BPPY_VALID_P (num))
+    {
+      bppy_breakpoints[num]->bp = NULL;
+      Py_DECREF (bppy_breakpoints[num]);
+      bppy_breakpoints[num] = NULL;
+      --bppy_live;
+    }
+}
+
+void
+gdbpy_initialize_breakpoints (void)
+{
+  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);
+}
Index: tromey.git/gdb/python/hooks.c
===================================================================
--- tromey.git.orig/gdb/python/hooks.c	2008-04-29 11:05:09.000000000 -0300
+++ tromey.git/gdb/python/hooks.c	2008-04-29 11:05:15.000000000 -0300
@@ -112,6 +112,8 @@ void
 gdbpy_initialize_hooks (void)
 {
   handlers.architecture_changed = gdbpy_architecture_changed;
+  handlers.breakpoint_create = gdbpy_breakpoint_created;
+  handlers.breakpoint_delete = gdbpy_breakpoint_deleted;
   deprecated_set_gdb_event_hooks (&handlers);
 
   deprecated_set_hook = gdbpy_set_hook;
Index: tromey.git/gdb/python/python-internal.h
===================================================================
--- tromey.git.orig/gdb/python/python-internal.h	2008-04-29 11:05:09.000000000 -0300
+++ tromey.git/gdb/python/python-internal.h	2008-04-29 11:05:15.000000000 -0300
@@ -31,6 +31,7 @@ extern PyTypeObject value_object_type;
 
 PyObject *gdbpy_make_value_from_int (PyObject *self, PyObject *args);
 PyObject *gdbpy_get_value_from_history (PyObject *self, PyObject *args);
+PyObject *gdbpy_get_breakpoints (PyObject *, PyObject *);
 
 PyObject *variable_to_python (struct cmd_list_element *);
 PyObject *value_to_value_object (struct value *v);
@@ -42,6 +43,7 @@ PyObject *gdbpy_get_hook_function (const
 
 void gdbpy_initialize_values (void);
 void gdbpy_initialize_hooks (void);
+void gdbpy_initialize_breakpoints (void);
 
 /* Use this after a TRY_EXCEPT to throw the appropriate Python
    exception.  FIXME: throw different errors depending on
@@ -54,4 +56,8 @@ void gdbpy_initialize_hooks (void);
 			     "%s", Exception.message);			\
     } while (0)
 
+/* Breakpoint hook functions.  */
+void gdbpy_breakpoint_created (int);
+void gdbpy_breakpoint_deleted (int);
+
 #endif /* GDB_PYTHON_INTERNAL_H */
Index: tromey.git/gdb/python/python.c
===================================================================
--- tromey.git.orig/gdb/python/python.c	2008-04-29 11:05:09.000000000 -0300
+++ tromey.git/gdb/python/python.c	2008-04-29 11:05:15.000000000 -0300
@@ -53,6 +53,9 @@ demand_python ()
 	{ "show", get_show_variable, METH_VARARGS,
 	  "Return a gdb setting's value" },
 
+	{ "get_breakpoints", gdbpy_get_breakpoints, METH_NOARGS,
+	  "Return a tuple of all breakpoint objects" },
+
 	{NULL, NULL, 0, NULL}
       };
 
@@ -66,6 +69,7 @@ demand_python ()
 
       gdbpy_initialize_hooks ();
       gdbpy_initialize_values ();
+      gdbpy_initialize_breakpoints ();
 
       PyRun_SimpleString ("import gdb");
 

-- 
-- 
[]'s
Thiago Jung Bauermann
Software Engineer
IBM Linux Technology Center


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]