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 2/9] export values mechanism to Python


2008-04-29  Vladimir Prus  <vladimir@codesourcery.com>
	    Tom Tromey <tromey@redhat.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* Makefile.in (SUBDIR_PYTHON_OBS): Add python-value.o.
	(SUBDIR_PYTHON_SRCS): Add python/value.c.
	(value.o): Depend on python.h.
	(python-value.o): New target.
	* python/python-internal.h (value_object_type,
	gdbpy_make_value_from_int, gdbpy_get_value_from_history,
	value_to_value_object, gdb_owned_value_to_value_object,
	value_object_to_value, gdbpy_initialize_values): Declare.
	* python/python.c (demand_python): Add new functions for values.
	Call gdbpy_initialize_values.
	* python/python.h (values_in_python): Declare.
	* python/value.c: New file.
	* value.c (value_prepend_to_list, value_remove_from_list): New
	functions.
	(preserve_values): Process elements in values_in_python list.
	Include python.h.
	* value.h (value_prepend_to_list,
	value_remove_from_list): Declare.

Index: tromey.git/gdb/Makefile.in
===================================================================
--- tromey.git.orig/gdb/Makefile.in	2008-04-29 11:00:35.000000000 -0300
+++ tromey.git/gdb/Makefile.in	2008-04-29 11:04:11.000000000 -0300
@@ -261,9 +261,11 @@ SUBDIR_TUI_CFLAGS= \
 # python sub directory definitons
 #
 SUBDIR_PYTHON_OBS = \
-	python.o
+	python.o \
+	python-value.o
 SUBDIR_PYTHON_SRCS = \
-	python/python.c
+	python/python.c \
+	python/value.c
 SUBDIR_PYTHON_DEPS =
 SUBDIR_PYTHON_LDFLAGS=
 SUBDIR_PYTHON_CFLAGS=
@@ -2982,7 +2984,7 @@ valprint.o: valprint.c $(defs_h) $(gdb_s
 value.o: value.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \
 	$(value_h) $(gdbcore_h) $(command_h) $(gdbcmd_h) $(target_h) \
 	$(language_h) $(demangle_h) $(doublest_h) \
-	$(gdb_assert_h) $(regcache_h) $(block_h) $(dfp_h)
+	$(gdb_assert_h) $(regcache_h) $(block_h) $(dfp_h) $(python_h)
 varobj.o: varobj.c $(defs_h) $(exceptions_h) $(value_h) $(expression_h) \
 	$(frame_h) $(language_h) $(wrapper_h) $(gdbcmd_h) $(block_h) \
 	$(gdb_assert_h) $(gdb_string_h) $(varobj_h) $(vec_h) $(gdbthread_h) \
@@ -3411,5 +3413,9 @@ 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-value.o: $(srcdir)/python/value.c $(defs_h) $(exceptions_h) \
+	$(python_internal_h) $(value_h)
+	$(CC) -c $(INTERNAL_CFLAGS) $(PYTHON_CFLAGS) \
+	$(srcdir)/python/value.c -o python-value.o
 
 ### end of the gdb Makefile.in.
Index: tromey.git/gdb/python/python-internal.h
===================================================================
--- tromey.git.orig/gdb/python/python-internal.h	2008-04-29 10:58:06.000000000 -0300
+++ tromey.git/gdb/python/python-internal.h	2008-04-29 11:04:11.000000000 -0300
@@ -27,6 +27,17 @@
 #endif
 
 extern PyObject *gdb_module;
+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 *value_to_value_object (struct value *v);
+PyObject *gdb_owned_value_to_value_object (struct value *v);
+
+struct value *value_object_to_value (PyObject *self);
+
+void gdbpy_initialize_values (void);
 
 /* Use this after a TRY_EXCEPT to throw the appropriate Python
    exception.  FIXME: throw different errors depending on
Index: tromey.git/gdb/python/python.c
===================================================================
--- tromey.git.orig/gdb/python/python.c	2008-04-29 11:03:46.000000000 -0300
+++ tromey.git/gdb/python/python.c	2008-04-29 11:04:11.000000000 -0300
@@ -44,6 +44,10 @@ demand_python ()
   if (!initialized)
     {
       static PyMethodDef GdbMethods[] = {
+	{ "make_value_from_int", gdbpy_make_value_from_int, METH_VARARGS,
+	  "Make a value from int" },
+	{ "get_value_from_history", gdbpy_get_value_from_history, METH_VARARGS,
+	  "Get a value from history" },
 	{ "execute", execute_gdb_command, METH_VARARGS,
 	  "Execute a gdb command" },
 	{ "show", get_show_variable, METH_VARARGS,
@@ -60,6 +64,8 @@ demand_python ()
       PyModule_AddStringConstant (gdb_module, "HOST_CONFIG", host_name);
       PyModule_AddStringConstant (gdb_module, "TARGET_CONFIG", target_name);
 
+      gdbpy_initialize_values ();
+
       PyRun_SimpleString ("import gdb");
 
       initialized = 1;
Index: tromey.git/gdb/python/python.h
===================================================================
--- tromey.git.orig/gdb/python/python.h	2008-04-29 10:58:06.000000000 -0300
+++ tromey.git/gdb/python/python.h	2008-04-29 11:04:11.000000000 -0300
@@ -24,6 +24,8 @@
 #include "value.h"
 #include "python-internal.h"
 
+extern struct value *values_in_python;
+
 void eval_python_from_control_command (struct command_line *);
 
 #endif /* GDB_PYTHON_H */
Index: tromey.git/gdb/python/value.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ tromey.git/gdb/python/value.c	2008-04-29 11:04:56.000000000 -0300
@@ -0,0 +1,392 @@
+/* Python interface to values.
+
+   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"
+
+typedef struct {
+  PyObject_HEAD
+  struct value *value;
+  int owned_by_gdb;
+} value_object;
+
+/* List of all values which are currently exposed to Python. It is maintained
+   so that when an objfile is discarded, preserve_values can copy the values'
+   types if needed.  */
+struct value *values_in_python;
+
+static void valpy_dealloc (PyObject *obj);
+static PyObject *valpy_dereference (PyObject *self, PyObject *args);
+static PyObject *valpy_get_element (PyObject *self, PyObject *args);
+static PyObject *valpy_str (PyObject *self);
+static PyObject *valpy_increment (PyObject *self, PyObject *args);
+static PyObject *valpy_equal_p (PyObject *self, PyObject *args);
+static PyObject * valpy_lazy_p (PyObject *self, PyObject *args);
+static PyObject * valpy_fetch_lazy (PyObject *self, PyObject *args);
+static PyObject * valpy_common_print (PyObject *self, PyObject *args);
+
+static PyMethodDef value_object_methods[] = {
+  { "dereference", valpy_dereference, METH_NOARGS, "Dereferences the value." },
+  { "get_element", valpy_get_element, METH_VARARGS,
+    "Obtains element inside value." },
+  { "increment", valpy_increment, METH_VARARGS,
+    "Increment value by the given amount." },
+  { "equals", valpy_equal_p, METH_VARARGS, "Compare values." },
+  { "is_lazy", valpy_lazy_p, METH_NOARGS,
+    "Returns True if the value is lazy, False if not." },
+  { "fetch_lazy", valpy_fetch_lazy, METH_NOARGS,
+    "Fetches value from inferior memory." },
+  { "common_print", valpy_common_print, METH_VARARGS, "Prints value." },
+  {NULL}  /* Sentinel */
+};
+
+PyTypeObject value_object_type = {
+  PyObject_HEAD_INIT (NULL)
+  0,				  /*ob_size*/
+  "gdb.Value",			  /*tp_name*/
+  sizeof (value_object),	  /*tp_basicsize*/
+  0,				  /*tp_itemsize*/
+  valpy_dealloc,		  /*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*/
+  valpy_str,			  /*tp_str*/
+  0,				  /*tp_getattro*/
+  0,				  /*tp_setattro*/
+  0,				  /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT,		  /*tp_flags*/
+  "GDB value object",		  /* tp_doc */
+  0,				  /* tp_traverse */
+  0,				  /* tp_clear */
+  0,				  /* tp_richcompare */
+  0,				  /* tp_weaklistoffset */
+  0,				  /* tp_iter */
+  0,				  /* tp_iternext */
+  value_object_methods		  /* tp_methods */
+};
+
+/* Mantra used to return value object wrapping value struct.  */
+#define VALPY_RETURN_VALUE(valpy_obj, value_st)			      \
+    do {							      \
+      valpy_obj = PyObject_New (value_object, &value_object_type);    \
+      if (valpy_obj != NULL)					      \
+	{							      \
+	  valpy_obj->value = value_st;				      \
+	  release_value (value_st);				      \
+	  value_prepend_to_list (&values_in_python, value_st);	      \
+	}							      \
+      return (PyObject *) valpy_obj;				      \
+    } while (0)
+
+
+static void
+valpy_dealloc (PyObject *obj)
+{
+  value_object *self = (value_object *) obj;
+
+  value_remove_from_list (&values_in_python, self->value);
+
+  if (!self->owned_by_gdb)
+    value_free (self->value);
+  self->ob_type->tp_free (self);
+}
+
+static PyObject *
+valpy_dereference (PyObject *self, PyObject *args)
+{
+  struct value *res_val = NULL;	  /* Initialize to appease gcc warning.  */
+  value_object *result;
+  volatile struct gdb_exception except;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      res_val = value_ind (((value_object *) self)->value);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  VALPY_RETURN_VALUE (result, res_val);
+}
+
+/* Takes value and string name of element inside that value.  */
+static PyObject *
+valpy_get_element (PyObject *self, PyObject *args)
+{
+  value_object *self_value = (value_object *) self;
+  char *field;
+  struct value *res_val = NULL;	  /* Initialize to appease gcc warning.  */
+  value_object *result;
+  volatile struct gdb_exception except;
+
+  if (!PyArg_ParseTuple (args, "s", &field))
+    return NULL;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      res_val = value_struct_elt (&self_value->value, NULL, field, 0, NULL);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  VALPY_RETURN_VALUE (result, res_val);
+}
+
+/* FIXME: copy paste from varobj.c */
+static char *
+value_get_print_value (struct value *value)
+{
+  long dummy;
+  struct ui_file *stb;
+  struct cleanup *old_chain;
+  char *thevalue;
+
+  if (value == NULL)
+    return NULL;
+
+  stb = mem_fileopen ();
+  old_chain = make_cleanup_ui_file_delete (stb);
+
+  common_val_print (value, stb, 0, 1, 0, 0);
+  thevalue = ui_file_xstrdup (stb, &dummy);
+
+  do_cleanups (old_chain);
+  return thevalue;
+}
+
+static PyObject *
+valpy_str (PyObject *self)
+{
+  char *s;
+  PyObject *result;
+
+  s = value_get_print_value (((value_object *) self)->value);
+  result = PyString_FromString (s);
+  xfree (s);
+
+  return result;
+}
+
+static PyObject *
+valpy_increment (PyObject *self, PyObject *args)
+{
+  int i;
+  struct value *res_val = NULL;	  /* Initialize to appease gcc warning.  */
+  struct value *inc;
+  value_object *result;
+  volatile struct gdb_exception except;
+
+  if (!PyArg_ParseTuple (args, "i", &i))
+    return NULL;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      /* FIXME: clear everything.  */
+      inc = value_from_longest (builtin_type_int, i);
+      res_val = value_add (((value_object *) self)->value, inc);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  VALPY_RETURN_VALUE (result, res_val);
+}
+
+static PyObject *
+valpy_equal_p (PyObject *self, PyObject *args)
+{
+  int equalp = 0;	  /* Initialize to appease gcc warning.  */
+  value_object *other;
+  volatile struct gdb_exception except;
+
+  if (!PyArg_ParseTuple (args, "O!", &value_object_type, &other))
+    return NULL;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      equalp = value_equal (((value_object *) self)->value, other->value);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  if (equalp == 1)
+    Py_RETURN_TRUE;
+
+  Py_RETURN_FALSE;
+}
+
+static PyObject *
+valpy_lazy_p (PyObject *self, PyObject *args)
+{
+  if (value_lazy (((value_object *) self)->value))
+    Py_RETURN_TRUE;
+
+  Py_RETURN_FALSE;
+}
+
+static PyObject *
+valpy_fetch_lazy (PyObject *self, PyObject *args)
+{
+  volatile struct gdb_exception except;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      value_fetch_lazy (((value_object *) self)->value);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  Py_RETURN_NONE;
+}
+
+static PyObject *
+valpy_common_print (PyObject *self, PyObject *args)
+{
+  value_object *self_value = (value_object *) self;
+  int ret = 0, format, recurse, pretty;
+  PyObject *format_obj, *deref_obj;
+  struct ui_stream *stb;
+  struct cleanup *chain;
+  volatile struct gdb_exception except;
+
+  if (!PyArg_ParseTuple (args, "OO!ii", &format_obj, &PyBool_Type, &deref_obj,
+			 &recurse, &pretty))
+    return NULL;
+
+  if (format_obj == Py_None)
+    format = 0;
+  else
+    {
+      if (!PyString_Check (format_obj) || PyString_Size (format_obj) != 1)
+	{
+	  PyErr_SetString (PyExc_TypeError, "Argument 1 must be char or None.");
+	  return NULL;
+	}
+
+      format = *PyString_AsString (format_obj);
+    }
+
+  stb = ui_out_stream_new (uiout);
+  chain = make_cleanup_ui_out_stream_delete (stb);
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      ret = common_val_print (self_value->value, stb->stream, format,
+			      deref_obj == Py_True, recurse, pretty);
+      /* FIXME: should I really use ui_out_field_stream?  */
+      ui_out_field_stream (uiout, "value", stb);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  do_cleanups (chain);
+
+  return PyInt_FromLong (ret);
+}
+
+/* A value owned by GDB is in the all_values chain, so it will be freed
+   automatically when not needed anymore (i.e., before the current command
+   completes).  */
+PyObject *
+gdb_owned_value_to_value_object (struct value *v)
+{
+  value_object *result = PyObject_New (value_object, &value_object_type);
+  if (result != NULL)
+    {
+      result->value = v;
+      result->owned_by_gdb = 1;
+      /* FIXME: should we do it? What is it? */
+      /* I don't think it is needed, since a GDB owned value has a very short
+         lifetime. The purpose of the list is explained in the comment above
+         its declaration. -- bauermann  */
+      value_prepend_to_list (&values_in_python, v);
+    }
+  return (PyObject *)result;
+}
+
+/* Returns an object for a value which is released from the all_values chain,
+   so its lifetime is not bound to the execution of a command.  */
+PyObject *
+value_to_value_object (struct value *v)
+{
+  value_object *val_obj;
+
+  VALPY_RETURN_VALUE (val_obj, v);
+}
+
+struct value *
+value_object_to_value (PyObject *self)
+{
+  value_object *real = (value_object *)self;
+  return real->value;
+}
+
+PyObject *
+gdbpy_make_value_from_int (PyObject *self, PyObject *args)
+{
+  int i;
+  struct value *res_val = NULL;   /* Initialize to appease gcc warning.  */
+  value_object *result;
+  volatile struct gdb_exception except;
+
+  if (!PyArg_ParseTuple (args, "i", &i))
+    return NULL;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      res_val = value_from_longest (builtin_type_int, i);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  VALPY_RETURN_VALUE (result, res_val);
+}
+
+PyObject *
+gdbpy_get_value_from_history (PyObject *self, PyObject *args)
+{
+  int i;
+  struct value *res_val = NULL;	  /* Initialize to appease gcc warning.  */
+  value_object *result;
+  volatile struct gdb_exception except;
+
+  if (!PyArg_ParseTuple (args, "i", &i))
+    return NULL;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      res_val = access_value_history (i);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  VALPY_RETURN_VALUE (result, res_val);
+}
+
+void
+gdbpy_initialize_values (void)
+{
+  value_object_type.tp_new = PyType_GenericNew;
+  if (PyType_Ready (&value_object_type) < 0)
+    return;
+
+  Py_INCREF (&value_object_type);
+  PyModule_AddObject (gdb_module, "Value", (PyObject *) &value_object_type);
+
+  values_in_python = NULL;
+}
Index: tromey.git/gdb/value.c
===================================================================
--- tromey.git.orig/gdb/value.c	2008-04-29 10:57:39.000000000 -0300
+++ tromey.git/gdb/value.c	2008-04-29 11:04:11.000000000 -0300
@@ -36,6 +36,10 @@
 #include "block.h"
 #include "dfp.h"
 
+#ifdef HAVE_PYTHON
+#include "python/python.h"
+#endif
+
 /* Prototypes for exported functions. */
 
 void _initialize_values (void);
@@ -129,8 +133,8 @@ struct value
 
   /* Values are stored in a chain, so that they can be deleted easily
      over calls to the inferior.  Values assigned to internal
-     variables or put into the value history are taken off this
-     list.  */
+     variables, put into the value history or exposed to Python are
+     taken off this list.  */
   struct value *next;
 
   /* Register number if the value is from a register.  */
@@ -256,6 +260,31 @@ allocate_repeat_value (struct type *type
 					    type, range_type));
 }
 
+/* Needed if another module needs to maintain its on list of values.  */
+void
+value_prepend_to_list (struct value **head, struct value *val)
+{
+  val->next = *head;
+  *head = val;
+}
+
+/* Needed if another module needs to maintain its on list of values.  */
+void
+value_remove_from_list (struct value **head, struct value *val)
+{
+  struct value *prev;
+
+  if (*head == val)
+    *head = (*head)->next;
+  else
+    for (prev = *head; prev->next; prev = prev->next)
+      if (prev->next == val)
+      {
+	prev->next = val->next;
+	break;
+      }
+}
+
 /* Accessor methods.  */
 
 struct value *
@@ -915,6 +944,7 @@ preserve_values (struct objfile *objfile
   htab_t copied_types;
   struct value_history_chunk *cur;
   struct internalvar *var;
+  struct value *val;
   int i;
 
   /* Create the hash table.  We allocate on the objfile's obstack, since
@@ -929,6 +959,11 @@ preserve_values (struct objfile *objfile
   for (var = internalvars; var; var = var->next)
     preserve_one_value (var->value, objfile, copied_types);
 
+#ifdef HAVE_PYTHON
+  for (val = values_in_python; val; val = val->next)
+    preserve_one_value (val, objfile, copied_types);
+#endif
+
   htab_delete (copied_types);
 }
 
Index: tromey.git/gdb/value.h
===================================================================
--- tromey.git.orig/gdb/value.h	2008-04-29 10:58:06.000000000 -0300
+++ tromey.git/gdb/value.h	2008-04-29 11:04:11.000000000 -0300
@@ -39,9 +39,15 @@ struct ui_file;
 
 struct value;
 
+/* Needed if another module needs to maintain its on list of values.  */
+
+void value_prepend_to_list (struct value **head, struct value *val);
+void value_remove_from_list (struct value **head, struct value *val);
+
 /* Values are stored in a chain, so that they can be deleted easily
-   over calls to the inferior.  Values assigned to internal variables
-   or put into the value history are taken off this list.  */
+   over calls to the inferior.  Values assigned to internal variables,
+   put into the value history or exposed to Python are taken off this
+   list.  */
 
 struct value *value_next (struct value *);
 

-- 
-- 
[]'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]