2008-04-29 Vladimir Prus Tom Tromey Thiago Jung Bauermann * 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 . */ + +#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