/* Python interface to values.
- Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
This file is part of GDB.
#include "dfp.h"
#include "valprint.h"
#include "infcall.h"
+#include "expression.h"
+#include "cp-abi.h"
#ifdef HAVE_PYTHON
#include "python-internal.h"
/* Even though Python scalar types directly map to host types, we use
- target types here to remain consistent with the the values system in
+ target types here to remain consistent with the values system in
GDB (which uses target arithmetic). */
/* Python's integer type corresponds to C's long type. */
struct value *value;
PyObject *address;
PyObject *type;
+ PyObject *dynamic_type;
} value_object;
/* List of all values which are currently exposed to Python. It is
Py_DECREF (self->type);
}
+ Py_XDECREF (self->dynamic_type);
+
self->ob_type->tp_free (self);
}
values_in_python = value_obj;
}
-/* Called when a new gdb.Value object needs to be allocated. */
+/* Called when a new gdb.Value object needs to be allocated. Returns NULL on
+ error, with a python exception set. */
static PyObject *
valpy_new (PyTypeObject *subtype, PyObject *args, PyObject *keywords)
{
value_incref (value);
value_obj->address = NULL;
value_obj->type = NULL;
+ value_obj->dynamic_type = NULL;
note_value (value_obj);
return (PyObject *) value_obj;
val_obj->address = value_to_value_object (res_val);
}
- Py_INCREF (val_obj->address);
+ Py_XINCREF (val_obj->address);
return val_obj->address;
}
{
obj->type = type_to_type_object (value_type (obj->value));
if (!obj->type)
- {
- obj->type = Py_None;
- Py_INCREF (obj->type);
- }
+ return NULL;
}
Py_INCREF (obj->type);
return obj->type;
}
+/* Return dynamic type of the value. */
+
+static PyObject *
+valpy_get_dynamic_type (PyObject *self, void *closure)
+{
+ value_object *obj = (value_object *) self;
+ volatile struct gdb_exception except;
+ struct type *type = NULL;
+
+ if (obj->dynamic_type != NULL)
+ {
+ Py_INCREF (obj->dynamic_type);
+ return obj->dynamic_type;
+ }
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ struct value *val = obj->value;
+
+ type = value_type (val);
+ CHECK_TYPEDEF (type);
+
+ if (((TYPE_CODE (type) == TYPE_CODE_PTR)
+ || (TYPE_CODE (type) == TYPE_CODE_REF))
+ && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS))
+ {
+ struct value *target;
+ int was_pointer = TYPE_CODE (type) == TYPE_CODE_PTR;
+
+ target = value_ind (val);
+ type = value_rtti_type (target, NULL, NULL, NULL);
+
+ if (type)
+ {
+ if (was_pointer)
+ type = lookup_pointer_type (type);
+ else
+ type = lookup_reference_type (type);
+ }
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_CLASS)
+ type = value_rtti_type (val, NULL, NULL, NULL);
+ else
+ {
+ /* Re-use object's static type. */
+ type = NULL;
+ }
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ if (type == NULL)
+ {
+ /* Ensure that the TYPE field is ready. */
+ if (!valpy_get_type (self, NULL))
+ return NULL;
+ /* We don't need to incref here, because valpy_get_type already
+ did it for us. */
+ obj->dynamic_type = obj->type;
+ }
+ else
+ obj->dynamic_type = type_to_type_object (type);
+
+ Py_INCREF (obj->dynamic_type);
+ return obj->dynamic_type;
+}
+
/* Implementation of gdb.Value.lazy_string ([encoding] [, length]) ->
string. Return a PyObject representing a lazy_string_object type.
A lazy string is a pointer to a string with an optional encoding and
static PyObject *
valpy_lazy_string (PyObject *self, PyObject *args, PyObject *kw)
{
- int length = -1;
+ gdb_py_longest length = -1;
struct value *value = ((value_object *) self)->value;
const char *user_encoding = NULL;
static char *keywords[] = { "encoding", "length", NULL };
PyObject *str_obj;
+ volatile struct gdb_exception except;
- if (!PyArg_ParseTupleAndKeywords (args, kw, "|si", keywords,
+ if (!PyArg_ParseTupleAndKeywords (args, kw, "|s" GDB_PY_LL_ARG, keywords,
&user_encoding, &length))
return NULL;
- if (TYPE_CODE (value_type (value)) == TYPE_CODE_PTR)
- value = value_ind (value);
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ if (TYPE_CODE (value_type (value)) == TYPE_CODE_PTR)
+ value = value_ind (value);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
str_obj = gdbpy_create_lazy_string_object (value_address (value), length,
- user_encoding, value_type (value));
+ user_encoding,
+ value_type (value));
return (PyObject *) str_obj;
}
return unicode;
}
-/* Cast a value to a given type. */
+/* A helper function that implements the various cast operators. */
+
static PyObject *
-valpy_cast (PyObject *self, PyObject *args)
+valpy_do_cast (PyObject *self, PyObject *args, enum exp_opcode op)
{
PyObject *type_obj;
struct type *type;
TRY_CATCH (except, RETURN_MASK_ALL)
{
- res_val = value_cast (type, ((value_object *) self)->value);
+ struct value *val = ((value_object *) self)->value;
+
+ if (op == UNOP_DYNAMIC_CAST)
+ res_val = value_dynamic_cast (type, val);
+ else if (op == UNOP_REINTERPRET_CAST)
+ res_val = value_reinterpret_cast (type, val);
+ else
+ {
+ gdb_assert (op == UNOP_CAST);
+ res_val = value_cast (type, val);
+ }
}
GDB_PY_HANDLE_EXCEPTION (except);
return value_to_value_object (res_val);
}
+/* Implementation of the "cast" method. */
+
+static PyObject *
+valpy_cast (PyObject *self, PyObject *args)
+{
+ return valpy_do_cast (self, args, UNOP_CAST);
+}
+
+/* Implementation of the "dynamic_cast" method. */
+
+static PyObject *
+valpy_dynamic_cast (PyObject *self, PyObject *args)
+{
+ return valpy_do_cast (self, args, UNOP_DYNAMIC_CAST);
+}
+
+/* Implementation of the "reinterpret_cast" method. */
+
+static PyObject *
+valpy_reinterpret_cast (PyObject *self, PyObject *args)
+{
+ return valpy_do_cast (self, args, UNOP_REINTERPRET_CAST);
+}
+
static Py_ssize_t
valpy_length (PyObject *self)
{
}
/* Given string name of an element inside structure, return its value
- object. */
+ object. Returns NULL on error, with a python exception set. */
static PyObject *
valpy_getitem (PyObject *self, PyObject *key)
{
type = check_typedef (value_type (tmp));
if (TYPE_CODE (type) != TYPE_CODE_ARRAY
&& TYPE_CODE (type) != TYPE_CODE_PTR)
- error( _("Cannot subscript requested type."));
+ error (_("Cannot subscript requested type."));
else
res_val = value_subscript (tmp, value_as_long (idx));
}
}
/* Called by the Python interpreter to perform an inferior function
- call on the value. */
+ call on the value. Returns NULL on error, with a python exception set. */
static PyObject *
valpy_call (PyObject *self, PyObject *args, PyObject *keywords)
{
volatile struct gdb_exception except;
struct value *function = ((value_object *) self)->value;
struct value **vargs = NULL;
- struct type *ftype = check_typedef (value_type (function));
+ struct type *ftype = NULL;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ ftype = check_typedef (value_type (function));
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
if (TYPE_CODE (ftype) != TYPE_CODE_FUNC)
{
return NULL;
}
+ if (! PyTuple_Check (args))
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("Inferior arguments must be provided in a tuple."));
+ return NULL;
+ }
+
args_count = PyTuple_Size (args);
if (args_count > 0)
{
valpy_str (PyObject *self)
{
char *s = NULL;
- struct ui_file *stb;
- struct cleanup *old_chain;
PyObject *result;
struct value_print_options opts;
volatile struct gdb_exception except;
get_user_print_options (&opts);
opts.deref_ref = 0;
- stb = mem_fileopen ();
- old_chain = make_cleanup_ui_file_delete (stb);
-
TRY_CATCH (except, RETURN_MASK_ALL)
{
+ struct ui_file *stb = mem_fileopen ();
+ struct cleanup *old_chain = make_cleanup_ui_file_delete (stb);
+
common_val_print (((value_object *) self)->value, stb, 0,
&opts, python_language);
s = ui_file_xstrdup (stb, NULL);
+
+ do_cleanups (old_chain);
}
GDB_PY_HANDLE_EXCEPTION (except);
- do_cleanups (old_chain);
-
result = PyUnicode_Decode (s, strlen (s), host_charset (), NULL);
xfree (s);
valpy_get_is_optimized_out (PyObject *self, void *closure)
{
struct value *value = ((value_object *) self)->value;
+ int opt = 0;
+ volatile struct gdb_exception except;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ opt = value_optimized_out (value);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
- if (value_optimized_out (value))
+ if (opt)
Py_RETURN_TRUE;
Py_RETURN_FALSE;
}
+/* Implements gdb.Value.is_lazy. */
+static PyObject *
+valpy_get_is_lazy (PyObject *self, void *closure)
+{
+ struct value *value = ((value_object *) self)->value;
+ int opt = 0;
+ volatile struct gdb_exception except;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ opt = value_lazy (value);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ if (opt)
+ Py_RETURN_TRUE;
+
+ Py_RETURN_FALSE;
+}
+
+/* Implements gdb.Value.fetch_lazy (). */
+static PyObject *
+valpy_fetch_lazy (PyObject *self, PyObject *args)
+{
+ struct value *value = ((value_object *) self)->value;
+ volatile struct gdb_exception except;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ if (value_lazy (value))
+ value_fetch_lazy (value);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ Py_RETURN_NONE;
+}
+
/* Calculate and return the address of the PyObject as the value of
the builtin __hash__ call. */
static long
((TYPE_CODE (TYPE) == TYPE_CODE_REF) ? (TYPE_TARGET_TYPE (TYPE)) : (TYPE))
/* Returns a value object which is the result of applying the operation
- specified by OPCODE to the given arguments. */
+ specified by OPCODE to the given arguments. Returns NULL on error, with
+ a python exception set. */
static PyObject *
valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other)
{
valpy_absolute (PyObject *self)
{
struct value *value = ((value_object *) self)->value;
+ volatile struct gdb_exception except;
+ int isabs = 1;
- if (value_less (value, value_zero (value_type (value), not_lval)))
- return valpy_negative (self);
- else
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ if (value_less (value, value_zero (value_type (value), not_lval)))
+ isabs = 0;
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ if (isabs)
return valpy_positive (self);
+ else
+ return valpy_negative (self);
}
/* Implements boolean evaluation of gdb.Value. */
static int
valpy_nonzero (PyObject *self)
{
+ volatile struct gdb_exception except;
value_object *self_value = (value_object *) self;
struct type *type;
+ int nonzero = 0; /* Appease GCC warning. */
type = check_typedef (value_type (self_value->value));
- if (is_integral_type (type) || TYPE_CODE (type) == TYPE_CODE_PTR)
- return !!value_as_long (self_value->value);
- else if (TYPE_CODE (type) == TYPE_CODE_FLT)
- return value_as_double (self_value->value) != 0;
- else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
- return !decimal_is_zero (value_contents (self_value->value),
- TYPE_LENGTH (type),
- gdbarch_byte_order (get_type_arch (type)));
- else
+ TRY_CATCH (except, RETURN_MASK_ALL)
{
- PyErr_SetString (PyExc_TypeError, _("Attempted truth testing on invalid "
- "gdb.Value type."));
- return 0;
+ if (is_integral_type (type) || TYPE_CODE (type) == TYPE_CODE_PTR)
+ nonzero = !!value_as_long (self_value->value);
+ else if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ nonzero = value_as_double (self_value->value) != 0;
+ else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
+ nonzero = !decimal_is_zero (value_contents (self_value->value),
+ TYPE_LENGTH (type),
+ gdbarch_byte_order (get_type_arch (type)));
+ else
+ /* All other values are True. */
+ nonzero = 1;
}
+ /* This is not documented in the Python documentation, but if this
+ function fails, return -1 as slot_nb_nonzero does (the default
+ Python nonzero function). */
+ GDB_PY_SET_HANDLE_EXCEPTION (except);
+
+ return nonzero;
}
/* Implements ~ for value objects. */
return valpy_binop (VALPY_BITXOR, self, other);
}
-/* Implements comparison operations for value objects. */
+/* Implements comparison operations for value objects. Returns NULL on error,
+ with a python exception set. */
static PyObject *
valpy_richcompare (PyObject *self, PyObject *other, int op)
{
static int
is_intlike (struct type *type, int ptr_ok)
{
- CHECK_TYPEDEF (type);
return (TYPE_CODE (type) == TYPE_CODE_INT
|| TYPE_CODE (type) == TYPE_CODE_ENUM
|| TYPE_CODE (type) == TYPE_CODE_BOOL
LONGEST l = 0;
volatile struct gdb_exception except;
- CHECK_TYPEDEF (type);
- if (!is_intlike (type, 0))
- {
- PyErr_SetString (PyExc_RuntimeError,
- _("Cannot convert value to int."));
- return NULL;
- }
-
TRY_CATCH (except, RETURN_MASK_ALL)
{
+ CHECK_TYPEDEF (type);
+ if (!is_intlike (type, 0))
+ error (_("Cannot convert value to int."));
+
l = value_as_long (value);
}
GDB_PY_HANDLE_EXCEPTION (except);
-#ifdef HAVE_LONG_LONG /* Defined by Python. */
- /* If we have 'long long', and the value overflows a 'long', use a
- Python Long; otherwise use a Python Int. */
- if (sizeof (l) > sizeof (long) && (l > PyInt_GetMax ()
- || l < (- (LONGEST) PyInt_GetMax ()) - 1))
- return PyLong_FromLongLong (l);
-#endif
- return PyInt_FromLong (l);
+ return gdb_py_object_from_longest (l);
}
/* Implements conversion to long. */
LONGEST l = 0;
volatile struct gdb_exception except;
- if (!is_intlike (type, 1))
- {
- PyErr_SetString (PyExc_RuntimeError,
- _("Cannot convert value to long."));
- return NULL;
- }
-
TRY_CATCH (except, RETURN_MASK_ALL)
{
+ CHECK_TYPEDEF (type);
+
+ if (!is_intlike (type, 1))
+ error (_("Cannot convert value to long."));
+
l = value_as_long (value);
}
GDB_PY_HANDLE_EXCEPTION (except);
-#ifdef HAVE_LONG_LONG /* Defined by Python. */
- return PyLong_FromLongLong (l);
-#else
- return PyLong_FromLong (l);
-#endif
+ return gdb_py_long_from_longest (l);
}
/* Implements conversion to float. */
double d = 0;
volatile struct gdb_exception except;
- CHECK_TYPEDEF (type);
- if (TYPE_CODE (type) != TYPE_CODE_FLT)
- {
- PyErr_SetString (PyExc_RuntimeError,
- _("Cannot convert value to float."));
- return NULL;
- }
-
TRY_CATCH (except, RETURN_MASK_ALL)
{
+ CHECK_TYPEDEF (type);
+
+ if (TYPE_CODE (type) != TYPE_CODE_FLT)
+ error (_("Cannot convert value to float."));
+
d = value_as_double (value);
}
GDB_PY_HANDLE_EXCEPTION (except);
value_incref (val);
val_obj->address = NULL;
val_obj->type = NULL;
+ val_obj->dynamic_type = NULL;
note_value (val_obj);
}
else if (gdbpy_is_lazy_string (obj))
{
PyObject *result;
- PyObject *function = PyString_FromString ("value");
- result = PyObject_CallMethodObjArgs (obj, function, NULL);
+ result = PyObject_CallMethodObjArgs (obj, gdbpy_value_cst, NULL);
value = value_copy (((value_object *) result)->value);
}
else
- PyErr_Format (PyExc_TypeError, _("Could not convert Python object: %s."),
+ PyErr_Format (PyExc_TypeError,
+ _("Could not convert Python object: %s."),
PyString_AsString (PyObject_Str (obj)));
}
if (except.reason < 0)
{ "address", valpy_get_address, NULL, "The address of the value.",
NULL },
{ "is_optimized_out", valpy_get_is_optimized_out, NULL,
- "Boolean telling whether the value is optimized out (i.e., not available).",
+ "Boolean telling whether the value is optimized "
+ "out (i.e., not available).",
NULL },
{ "type", valpy_get_type, NULL, "Type of the value.", NULL },
+ { "dynamic_type", valpy_get_dynamic_type, NULL,
+ "Dynamic type of the value.", NULL },
+ { "is_lazy", valpy_get_is_lazy, NULL,
+ "Boolean telling whether the value is lazy (not fetched yet\n\
+from the inferior). A lazy value is fetched when needed, or when\n\
+the \"fetch_lazy()\" method is called.", NULL },
{NULL} /* Sentinel */
};
static PyMethodDef value_object_methods[] = {
{ "cast", valpy_cast, METH_VARARGS, "Cast the value to the supplied type." },
+ { "dynamic_cast", valpy_dynamic_cast, METH_VARARGS,
+ "dynamic_cast (gdb.Type) -> gdb.Value\n\
+Cast the value to the supplied type, as if by the C++ dynamic_cast operator."
+ },
+ { "reinterpret_cast", valpy_reinterpret_cast, METH_VARARGS,
+ "reinterpret_cast (gdb.Type) -> gdb.Value\n\
+Cast the value to the supplied type, as if by the C++\n\
+reinterpret_cast operator."
+ },
{ "dereference", valpy_dereference, METH_NOARGS, "Dereferences the value." },
- { "lazy_string", (PyCFunction) valpy_lazy_string, METH_VARARGS | METH_KEYWORDS,
+ { "lazy_string", (PyCFunction) valpy_lazy_string,
+ METH_VARARGS | METH_KEYWORDS,
"lazy_string ([encoding] [, length]) -> lazy_string\n\
Return a lazy string representation of the value." },
{ "string", (PyCFunction) valpy_string, METH_VARARGS | METH_KEYWORDS,
"string ([encoding] [, errors] [, length]) -> string\n\
Return Unicode string representation of the value." },
+ { "fetch_lazy", valpy_fetch_lazy, METH_NOARGS,
+ "Fetches the value from the inferior, if it was lazy." },
{NULL} /* Sentinel */
};
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES
+ | Py_TPFLAGS_BASETYPE, /*tp_flags*/
"GDB value object", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */