|  | /* Python interface to values. | 
|  |  | 
|  | Copyright (C) 2008-2023 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 "charset.h" | 
|  | #include "value.h" | 
|  | #include "language.h" | 
|  | #include "target-float.h" | 
|  | #include "valprint.h" | 
|  | #include "infcall.h" | 
|  | #include "expression.h" | 
|  | #include "cp-abi.h" | 
|  | #include "python.h" | 
|  |  | 
|  | #include "python-internal.h" | 
|  |  | 
|  | /* Even though Python scalar types directly map to host types, we use | 
|  | 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.  */ | 
|  | #define builtin_type_pyint \ | 
|  | builtin_type (gdbpy_enter::get_gdbarch ())->builtin_long | 
|  |  | 
|  | /* Python's float type corresponds to C's double type.  */ | 
|  | #define builtin_type_pyfloat \ | 
|  | builtin_type (gdbpy_enter::get_gdbarch ())->builtin_double | 
|  |  | 
|  | /* Python's long type corresponds to C's long long type.  */ | 
|  | #define builtin_type_pylong \ | 
|  | builtin_type (gdbpy_enter::get_gdbarch ())->builtin_long_long | 
|  |  | 
|  | /* Python's long type corresponds to C's long long type.  Unsigned version.  */ | 
|  | #define builtin_type_upylong builtin_type \ | 
|  | (gdbpy_enter::get_gdbarch ())->builtin_unsigned_long_long | 
|  |  | 
|  | #define builtin_type_pybool \ | 
|  | language_bool_type (current_language, gdbpy_enter::get_gdbarch ()) | 
|  |  | 
|  | #define builtin_type_pychar \ | 
|  | language_string_char_type (current_language, gdbpy_enter::get_gdbarch ()) | 
|  |  | 
|  | struct value_object { | 
|  | PyObject_HEAD | 
|  | struct value_object *next; | 
|  | struct value_object *prev; | 
|  | struct value *value; | 
|  | PyObject *address; | 
|  | PyObject *type; | 
|  | PyObject *dynamic_type; | 
|  | }; | 
|  |  | 
|  | /* 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.  */ | 
|  | /* This variable is unnecessarily initialized to NULL in order to | 
|  | work around a linker bug on MacOS.  */ | 
|  | static value_object *values_in_python = NULL; | 
|  |  | 
|  | /* Clear out an old GDB value stored within SELF, and reset the fields to | 
|  | nullptr.  This should be called when a gdb.Value is deallocated, and | 
|  | also if a gdb.Value is reinitialized with a new value.  */ | 
|  |  | 
|  | static void | 
|  | valpy_clear_value (value_object *self) | 
|  | { | 
|  | /* Indicate we are no longer interested in the value object.  */ | 
|  | value_decref (self->value); | 
|  | self->value = nullptr; | 
|  |  | 
|  | Py_CLEAR (self->address); | 
|  | Py_CLEAR (self->type); | 
|  | Py_CLEAR (self->dynamic_type); | 
|  | } | 
|  |  | 
|  | /* Called by the Python interpreter when deallocating a value object.  */ | 
|  | static void | 
|  | valpy_dealloc (PyObject *obj) | 
|  | { | 
|  | value_object *self = (value_object *) obj; | 
|  |  | 
|  | /* If SELF failed to initialize correctly then it may not have a value | 
|  | contained within it.  */ | 
|  | if (self->value != nullptr) | 
|  | { | 
|  | /* Remove SELF from the global list of values.  */ | 
|  | if (self->prev != nullptr) | 
|  | self->prev->next = self->next; | 
|  | else | 
|  | { | 
|  | gdb_assert (values_in_python == self); | 
|  | values_in_python = self->next; | 
|  | } | 
|  | if (self->next != nullptr) | 
|  | self->next->prev = self->prev; | 
|  |  | 
|  | /* Release the value object and any cached Python objects.  */ | 
|  | valpy_clear_value (self); | 
|  | } | 
|  |  | 
|  | Py_TYPE (self)->tp_free (self); | 
|  | } | 
|  |  | 
|  | /* Helper to push a gdb.Value object on to the global list of values.  If | 
|  | VALUE_OBJ is already on the lit then this does nothing.  */ | 
|  |  | 
|  | static void | 
|  | note_value (value_object *value_obj) | 
|  | { | 
|  | if (value_obj->next == nullptr) | 
|  | { | 
|  | gdb_assert (value_obj->prev == nullptr); | 
|  | value_obj->next = values_in_python; | 
|  | if (value_obj->next != nullptr) | 
|  | value_obj->next->prev = value_obj; | 
|  | values_in_python = value_obj; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Convert a python object OBJ with type TYPE to a gdb value.  The | 
|  | python object in question must conform to the python buffer | 
|  | protocol.  On success, return the converted value, otherwise | 
|  | nullptr.  */ | 
|  |  | 
|  | static struct value * | 
|  | convert_buffer_and_type_to_value (PyObject *obj, struct type *type) | 
|  | { | 
|  | Py_buffer_up buffer_up; | 
|  | Py_buffer py_buf; | 
|  |  | 
|  | if (PyObject_CheckBuffer (obj) | 
|  | && PyObject_GetBuffer (obj, &py_buf, PyBUF_SIMPLE) == 0) | 
|  | { | 
|  | /* Got a buffer, py_buf, out of obj.  Cause it to be released | 
|  | when it goes out of scope.  */ | 
|  | buffer_up.reset (&py_buf); | 
|  | } | 
|  | else | 
|  | { | 
|  | PyErr_SetString (PyExc_TypeError, | 
|  | _("Object must support the python buffer protocol.")); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | if (type->length () > py_buf.len) | 
|  | { | 
|  | PyErr_SetString (PyExc_ValueError, | 
|  | _("Size of type is larger than that of buffer object.")); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | return value_from_contents (type, (const gdb_byte *) py_buf.buf); | 
|  | } | 
|  |  | 
|  | /* Implement gdb.Value.__init__.  */ | 
|  |  | 
|  | static int | 
|  | valpy_init (PyObject *self, PyObject *args, PyObject *kwds) | 
|  | { | 
|  | static const char *keywords[] = { "val", "type", NULL }; | 
|  | PyObject *val_obj = nullptr; | 
|  | PyObject *type_obj = nullptr; | 
|  |  | 
|  | if (!gdb_PyArg_ParseTupleAndKeywords (args, kwds, "O|O", keywords, | 
|  | &val_obj, &type_obj)) | 
|  | return -1; | 
|  |  | 
|  | struct type *type = nullptr; | 
|  | if (type_obj != nullptr && type_obj != Py_None) | 
|  | { | 
|  | type = type_object_to_type (type_obj); | 
|  | if (type == nullptr) | 
|  | { | 
|  | PyErr_SetString (PyExc_TypeError, | 
|  | _("type argument must be a gdb.Type.")); | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | struct value *value; | 
|  | if (type == nullptr) | 
|  | value = convert_value_from_python (val_obj); | 
|  | else | 
|  | value = convert_buffer_and_type_to_value (val_obj, type); | 
|  | if (value == nullptr) | 
|  | { | 
|  | gdb_assert (PyErr_Occurred ()); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* There might be a previous value here.  */ | 
|  | value_object *value_obj = (value_object *) self; | 
|  | if (value_obj->value != nullptr) | 
|  | valpy_clear_value (value_obj); | 
|  |  | 
|  | /* Store the value into this Python object.  */ | 
|  | value_obj->value = release_value (value).release (); | 
|  |  | 
|  | /* Ensure that this gdb.Value is in the set of all gdb.Value objects.  If | 
|  | we are already in the set then this is call does nothing.  */ | 
|  | note_value (value_obj); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Iterate over all the Value objects, calling preserve_one_value on | 
|  | each.  */ | 
|  | void | 
|  | gdbpy_preserve_values (const struct extension_language_defn *extlang, | 
|  | struct objfile *objfile, htab_t copied_types) | 
|  | { | 
|  | value_object *iter; | 
|  |  | 
|  | for (iter = values_in_python; iter; iter = iter->next) | 
|  | preserve_one_value (iter->value, objfile, copied_types); | 
|  | } | 
|  |  | 
|  | /* Given a value of a pointer type, apply the C unary * operator to it.  */ | 
|  | static PyObject * | 
|  | valpy_dereference (PyObject *self, PyObject *args) | 
|  | { | 
|  | PyObject *result = NULL; | 
|  |  | 
|  | try | 
|  | { | 
|  | struct value *res_val; | 
|  | scoped_value_mark free_values; | 
|  |  | 
|  | res_val = value_ind (((value_object *) self)->value); | 
|  | result = value_to_value_object (res_val); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* Given a value of a pointer type or a reference type, return the value | 
|  | referenced. The difference between this function and valpy_dereference is | 
|  | that the latter applies * unary operator to a value, which need not always | 
|  | result in the value referenced. For example, for a value which is a reference | 
|  | to an 'int' pointer ('int *'), valpy_dereference will result in a value of | 
|  | type 'int' while valpy_referenced_value will result in a value of type | 
|  | 'int *'.  */ | 
|  |  | 
|  | static PyObject * | 
|  | valpy_referenced_value (PyObject *self, PyObject *args) | 
|  | { | 
|  | PyObject *result = NULL; | 
|  |  | 
|  | try | 
|  | { | 
|  | struct value *self_val, *res_val; | 
|  | scoped_value_mark free_values; | 
|  |  | 
|  | self_val = ((value_object *) self)->value; | 
|  | switch (check_typedef (value_type (self_val))->code ()) | 
|  | { | 
|  | case TYPE_CODE_PTR: | 
|  | res_val = value_ind (self_val); | 
|  | break; | 
|  | case TYPE_CODE_REF: | 
|  | case TYPE_CODE_RVALUE_REF: | 
|  | res_val = coerce_ref (self_val); | 
|  | break; | 
|  | default: | 
|  | error(_("Trying to get the referenced value from a value which is " | 
|  | "neither a pointer nor a reference.")); | 
|  | } | 
|  |  | 
|  | result = value_to_value_object (res_val); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* Return a value which is a reference to the value.  */ | 
|  |  | 
|  | static PyObject * | 
|  | valpy_reference_value (PyObject *self, PyObject *args, enum type_code refcode) | 
|  | { | 
|  | PyObject *result = NULL; | 
|  |  | 
|  | try | 
|  | { | 
|  | struct value *self_val; | 
|  | scoped_value_mark free_values; | 
|  |  | 
|  | self_val = ((value_object *) self)->value; | 
|  | result = value_to_value_object (value_ref (self_val, refcode)); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static PyObject * | 
|  | valpy_lvalue_reference_value (PyObject *self, PyObject *args) | 
|  | { | 
|  | return valpy_reference_value (self, args, TYPE_CODE_REF); | 
|  | } | 
|  |  | 
|  | static PyObject * | 
|  | valpy_rvalue_reference_value (PyObject *self, PyObject *args) | 
|  | { | 
|  | return valpy_reference_value (self, args, TYPE_CODE_RVALUE_REF); | 
|  | } | 
|  |  | 
|  | /* Return a "const" qualified version of the value.  */ | 
|  |  | 
|  | static PyObject * | 
|  | valpy_const_value (PyObject *self, PyObject *args) | 
|  | { | 
|  | PyObject *result = NULL; | 
|  |  | 
|  | try | 
|  | { | 
|  | struct value *self_val, *res_val; | 
|  | scoped_value_mark free_values; | 
|  |  | 
|  | self_val = ((value_object *) self)->value; | 
|  | res_val = make_cv_value (1, 0, self_val); | 
|  | result = value_to_value_object (res_val); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* Return "&value".  */ | 
|  | static PyObject * | 
|  | valpy_get_address (PyObject *self, void *closure) | 
|  | { | 
|  | value_object *val_obj = (value_object *) self; | 
|  |  | 
|  | if (!val_obj->address) | 
|  | { | 
|  | try | 
|  | { | 
|  | struct value *res_val; | 
|  | scoped_value_mark free_values; | 
|  |  | 
|  | res_val = value_addr (val_obj->value); | 
|  | val_obj->address = value_to_value_object (res_val); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | val_obj->address = Py_None; | 
|  | Py_INCREF (Py_None); | 
|  | } | 
|  | } | 
|  |  | 
|  | Py_XINCREF (val_obj->address); | 
|  |  | 
|  | return val_obj->address; | 
|  | } | 
|  |  | 
|  | /* Return type of the value.  */ | 
|  | static PyObject * | 
|  | valpy_get_type (PyObject *self, void *closure) | 
|  | { | 
|  | value_object *obj = (value_object *) self; | 
|  |  | 
|  | if (!obj->type) | 
|  | { | 
|  | obj->type = type_to_type_object (value_type (obj->value)); | 
|  | if (!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; | 
|  | struct type *type = NULL; | 
|  |  | 
|  | if (obj->dynamic_type != NULL) | 
|  | { | 
|  | Py_INCREF (obj->dynamic_type); | 
|  | return obj->dynamic_type; | 
|  | } | 
|  |  | 
|  | try | 
|  | { | 
|  | struct value *val = obj->value; | 
|  | scoped_value_mark free_values; | 
|  |  | 
|  | type = value_type (val); | 
|  | type = check_typedef (type); | 
|  |  | 
|  | if (type->is_pointer_or_reference () | 
|  | && (type->target_type ()->code () == TYPE_CODE_STRUCT)) | 
|  | { | 
|  | struct value *target; | 
|  | int was_pointer = type->code () == TYPE_CODE_PTR; | 
|  |  | 
|  | if (was_pointer) | 
|  | target = value_ind (val); | 
|  | else | 
|  | target = coerce_ref (val); | 
|  | type = value_rtti_type (target, NULL, NULL, NULL); | 
|  |  | 
|  | if (type) | 
|  | { | 
|  | if (was_pointer) | 
|  | type = lookup_pointer_type (type); | 
|  | else | 
|  | type = lookup_lvalue_reference_type (type); | 
|  | } | 
|  | } | 
|  | else if (type->code () == TYPE_CODE_STRUCT) | 
|  | type = value_rtti_type (val, NULL, NULL, NULL); | 
|  | else | 
|  | { | 
|  | /* Re-use object's static type.  */ | 
|  | type = NULL; | 
|  | } | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | if (type == NULL) | 
|  | obj->dynamic_type = valpy_get_type (self, NULL); | 
|  | else | 
|  | obj->dynamic_type = type_to_type_object (type); | 
|  |  | 
|  | Py_XINCREF (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 | 
|  | length.  If ENCODING is not given, encoding is set to None.  If an | 
|  | ENCODING is provided the encoding parameter is set to ENCODING, but | 
|  | the string is not encoded. | 
|  | If LENGTH is provided then the length parameter is set to LENGTH. | 
|  | Otherwise if the value is an array of known length then the array's length | 
|  | is used.  Otherwise the length will be set to -1 (meaning first null of | 
|  | appropriate with). | 
|  |  | 
|  | Note: In order to not break any existing uses this allows creating | 
|  | lazy strings from anything.  PR 20769.  E.g., | 
|  | gdb.parse_and_eval("my_int_variable").lazy_string(). | 
|  | "It's easier to relax restrictions than it is to impose them after the | 
|  | fact."  So we should be flagging any unintended uses as errors, but it's | 
|  | perhaps too late for that.  */ | 
|  |  | 
|  | static PyObject * | 
|  | valpy_lazy_string (PyObject *self, PyObject *args, PyObject *kw) | 
|  | { | 
|  | gdb_py_longest length = -1; | 
|  | struct value *value = ((value_object *) self)->value; | 
|  | const char *user_encoding = NULL; | 
|  | static const char *keywords[] = { "encoding", "length", NULL }; | 
|  | PyObject *str_obj = NULL; | 
|  |  | 
|  | if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "|s" GDB_PY_LL_ARG, | 
|  | keywords, &user_encoding, &length)) | 
|  | return NULL; | 
|  |  | 
|  | if (length < -1) | 
|  | { | 
|  | PyErr_SetString (PyExc_ValueError, _("Invalid length.")); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | try | 
|  | { | 
|  | scoped_value_mark free_values; | 
|  | struct type *type, *realtype; | 
|  | CORE_ADDR addr; | 
|  |  | 
|  | type = value_type (value); | 
|  | realtype = check_typedef (type); | 
|  |  | 
|  | switch (realtype->code ()) | 
|  | { | 
|  | case TYPE_CODE_ARRAY: | 
|  | { | 
|  | LONGEST array_length = -1; | 
|  | LONGEST low_bound, high_bound; | 
|  |  | 
|  | /* PR 20786: There's no way to specify an array of length zero. | 
|  | Record a length of [0,-1] which is how Ada does it.  Anything | 
|  | we do is broken, but this one possible solution.  */ | 
|  | if (get_array_bounds (realtype, &low_bound, &high_bound)) | 
|  | array_length = high_bound - low_bound + 1; | 
|  | if (length == -1) | 
|  | length = array_length; | 
|  | else if (array_length == -1) | 
|  | { | 
|  | type = lookup_array_range_type (realtype->target_type (), | 
|  | 0, length - 1); | 
|  | } | 
|  | else if (length != array_length) | 
|  | { | 
|  | /* We need to create a new array type with the | 
|  | specified length.  */ | 
|  | if (length > array_length) | 
|  | error (_("Length is larger than array size.")); | 
|  | type = lookup_array_range_type (realtype->target_type (), | 
|  | low_bound, | 
|  | low_bound + length - 1); | 
|  | } | 
|  | addr = value_address (value); | 
|  | break; | 
|  | } | 
|  | case TYPE_CODE_PTR: | 
|  | /* If a length is specified we defer creating an array of the | 
|  | specified width until we need to.  */ | 
|  | addr = value_as_address (value); | 
|  | break; | 
|  | default: | 
|  | /* Should flag an error here.  PR 20769.  */ | 
|  | addr = value_address (value); | 
|  | break; | 
|  | } | 
|  |  | 
|  | str_obj = gdbpy_create_lazy_string_object (addr, length, user_encoding, | 
|  | type); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | return str_obj; | 
|  | } | 
|  |  | 
|  | /* Implementation of gdb.Value.string ([encoding] [, errors] | 
|  | [, length]) -> string.  Return Unicode string with value contents. | 
|  | If ENCODING is not given, the string is assumed to be encoded in | 
|  | the target's charset.  If LENGTH is provided, only fetch string to | 
|  | the length provided.  */ | 
|  |  | 
|  | static PyObject * | 
|  | valpy_string (PyObject *self, PyObject *args, PyObject *kw) | 
|  | { | 
|  | int length = -1; | 
|  | gdb::unique_xmalloc_ptr<gdb_byte> buffer; | 
|  | struct value *value = ((value_object *) self)->value; | 
|  | const char *encoding = NULL; | 
|  | const char *errors = NULL; | 
|  | const char *user_encoding = NULL; | 
|  | const char *la_encoding = NULL; | 
|  | struct type *char_type; | 
|  | static const char *keywords[] = { "encoding", "errors", "length", NULL }; | 
|  |  | 
|  | if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "|ssi", keywords, | 
|  | &user_encoding, &errors, &length)) | 
|  | return NULL; | 
|  |  | 
|  | try | 
|  | { | 
|  | c_get_string (value, &buffer, &length, &char_type, &la_encoding); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | encoding = (user_encoding && *user_encoding) ? user_encoding : la_encoding; | 
|  | return PyUnicode_Decode ((const char *) buffer.get (), | 
|  | length * char_type->length (), | 
|  | encoding, errors); | 
|  | } | 
|  |  | 
|  | /* Given a Python object, copy its truth value to a C bool (the value | 
|  | pointed by dest). | 
|  | If src_obj is NULL, then *dest is not modified. | 
|  |  | 
|  | Return true in case of success (including src_obj being NULL), false | 
|  | in case of error.  */ | 
|  |  | 
|  | static bool | 
|  | copy_py_bool_obj (bool *dest, PyObject *src_obj) | 
|  | { | 
|  | if (src_obj) | 
|  | { | 
|  | int cmp = PyObject_IsTrue (src_obj); | 
|  | if (cmp < 0) | 
|  | return false; | 
|  | *dest = cmp; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Implementation of gdb.Value.format_string (...) -> string. | 
|  | Return Unicode string with value contents formatted using the | 
|  | keyword-only arguments.  */ | 
|  |  | 
|  | static PyObject * | 
|  | valpy_format_string (PyObject *self, PyObject *args, PyObject *kw) | 
|  | { | 
|  | static const char *keywords[] = | 
|  | { | 
|  | /* Basic C/C++ options.  */ | 
|  | "raw",			/* See the /r option to print.  */ | 
|  | "pretty_arrays",		/* See set print array on|off.  */ | 
|  | "pretty_structs",		/* See set print pretty on|off.  */ | 
|  | "array_indexes",		/* See set print array-indexes on|off.  */ | 
|  | "symbols",		/* See set print symbol on|off.  */ | 
|  | "unions",			/* See set print union on|off.  */ | 
|  | "address",		/* See set print address on|off.  */ | 
|  | "styling",		/* Should we apply styling.  */ | 
|  | "nibbles",		/* See set print nibbles on|off.  */ | 
|  | "summary",		/* Summary mode for non-scalars.  */ | 
|  | /* C++ options.  */ | 
|  | "deref_refs",		/* No corresponding setting.  */ | 
|  | "actual_objects",		/* See set print object on|off.  */ | 
|  | "static_members",		/* See set print static-members on|off.  */ | 
|  | /* C non-bool options.  */ | 
|  | "max_characters", 	/* See set print characters N.  */ | 
|  | "max_elements", 		/* See set print elements N.  */ | 
|  | "max_depth",		/* See set print max-depth N.  */ | 
|  | "repeat_threshold",	/* See set print repeats.  */ | 
|  | "format",			/* The format passed to the print command.  */ | 
|  | NULL | 
|  | }; | 
|  |  | 
|  | /* This function has too many arguments to be useful as positionals, so | 
|  | the user should specify them all as keyword arguments. | 
|  | Python 3.3 and later have a way to specify it (both in C and Python | 
|  | itself), but we could be compiled with older versions, so we just | 
|  | check that the args tuple is empty.  */ | 
|  | Py_ssize_t positional_count = PyObject_Length (args); | 
|  | if (positional_count < 0) | 
|  | return NULL; | 
|  | else if (positional_count > 0) | 
|  | { | 
|  | /* This matches the error message that Python 3.3 raises when | 
|  | passing positionals to functions expecting keyword-only | 
|  | arguments.  */ | 
|  | PyErr_Format (PyExc_TypeError, | 
|  | "format_string() takes 0 positional arguments but %zu were given", | 
|  | positional_count); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | struct value_print_options opts; | 
|  | gdbpy_get_print_options (&opts); | 
|  | opts.deref_ref = false; | 
|  |  | 
|  | /* We need objects for booleans as the "p" flag for bools is new in | 
|  | Python 3.3.  */ | 
|  | PyObject *raw_obj = NULL; | 
|  | PyObject *pretty_arrays_obj = NULL; | 
|  | PyObject *pretty_structs_obj = NULL; | 
|  | PyObject *array_indexes_obj = NULL; | 
|  | PyObject *symbols_obj = NULL; | 
|  | PyObject *unions_obj = NULL; | 
|  | PyObject *address_obj = NULL; | 
|  | PyObject *styling_obj = Py_False; | 
|  | PyObject *nibbles_obj = NULL; | 
|  | PyObject *deref_refs_obj = NULL; | 
|  | PyObject *actual_objects_obj = NULL; | 
|  | PyObject *static_members_obj = NULL; | 
|  | PyObject *summary_obj = NULL; | 
|  | char *format = NULL; | 
|  | if (!gdb_PyArg_ParseTupleAndKeywords (args, | 
|  | kw, | 
|  | "|O!O!O!O!O!O!O!O!O!O!O!O!O!IIIIs", | 
|  | keywords, | 
|  | &PyBool_Type, &raw_obj, | 
|  | &PyBool_Type, &pretty_arrays_obj, | 
|  | &PyBool_Type, &pretty_structs_obj, | 
|  | &PyBool_Type, &array_indexes_obj, | 
|  | &PyBool_Type, &symbols_obj, | 
|  | &PyBool_Type, &unions_obj, | 
|  | &PyBool_Type, &address_obj, | 
|  | &PyBool_Type, &styling_obj, | 
|  | &PyBool_Type, &nibbles_obj, | 
|  | &PyBool_Type, &summary_obj, | 
|  | &PyBool_Type, &deref_refs_obj, | 
|  | &PyBool_Type, &actual_objects_obj, | 
|  | &PyBool_Type, &static_members_obj, | 
|  | &opts.print_max_chars, | 
|  | &opts.print_max, | 
|  | &opts.max_depth, | 
|  | &opts.repeat_count_threshold, | 
|  | &format)) | 
|  | return NULL; | 
|  |  | 
|  | /* Set boolean arguments.  */ | 
|  | if (!copy_py_bool_obj (&opts.raw, raw_obj)) | 
|  | return NULL; | 
|  | if (!copy_py_bool_obj (&opts.prettyformat_arrays, pretty_arrays_obj)) | 
|  | return NULL; | 
|  | if (!copy_py_bool_obj (&opts.prettyformat_structs, pretty_structs_obj)) | 
|  | return NULL; | 
|  | if (!copy_py_bool_obj (&opts.print_array_indexes, array_indexes_obj)) | 
|  | return NULL; | 
|  | if (!copy_py_bool_obj (&opts.symbol_print, symbols_obj)) | 
|  | return NULL; | 
|  | if (!copy_py_bool_obj (&opts.unionprint, unions_obj)) | 
|  | return NULL; | 
|  | if (!copy_py_bool_obj (&opts.addressprint, address_obj)) | 
|  | return NULL; | 
|  | if (!copy_py_bool_obj (&opts.nibblesprint, nibbles_obj)) | 
|  | return NULL; | 
|  | if (!copy_py_bool_obj (&opts.deref_ref, deref_refs_obj)) | 
|  | return NULL; | 
|  | if (!copy_py_bool_obj (&opts.objectprint, actual_objects_obj)) | 
|  | return NULL; | 
|  | if (!copy_py_bool_obj (&opts.static_field_print, static_members_obj)) | 
|  | return NULL; | 
|  | if (!copy_py_bool_obj (&opts.summary, summary_obj)) | 
|  | return nullptr; | 
|  |  | 
|  | /* Numeric arguments for which 0 means unlimited (which we represent as | 
|  | UINT_MAX).  Note that the max-depth numeric argument uses -1 as | 
|  | unlimited, and 0 is a valid choice.  */ | 
|  | if (opts.print_max == 0) | 
|  | opts.print_max = UINT_MAX; | 
|  | if (opts.repeat_count_threshold == 0) | 
|  | opts.repeat_count_threshold = UINT_MAX; | 
|  |  | 
|  | /* Other arguments.  */ | 
|  | if (format != NULL) | 
|  | { | 
|  | if (strlen (format) == 1) | 
|  | opts.format = format[0]; | 
|  | else | 
|  | { | 
|  | /* Mimic the message on standard Python ones for similar | 
|  | errors.  */ | 
|  | PyErr_SetString (PyExc_ValueError, | 
|  | "a single character is required"); | 
|  | return NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | string_file stb (PyObject_IsTrue (styling_obj)); | 
|  |  | 
|  | try | 
|  | { | 
|  | common_val_print (((value_object *) self)->value, &stb, 0, | 
|  | &opts, current_language); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | return PyUnicode_Decode (stb.c_str (), stb.size (), host_charset (), NULL); | 
|  | } | 
|  |  | 
|  | /* A helper function that implements the various cast operators.  */ | 
|  |  | 
|  | static PyObject * | 
|  | valpy_do_cast (PyObject *self, PyObject *args, enum exp_opcode op) | 
|  | { | 
|  | PyObject *type_obj, *result = NULL; | 
|  | struct type *type; | 
|  |  | 
|  | if (! PyArg_ParseTuple (args, "O", &type_obj)) | 
|  | return NULL; | 
|  |  | 
|  | type = type_object_to_type (type_obj); | 
|  | if (! type) | 
|  | { | 
|  | PyErr_SetString (PyExc_RuntimeError, | 
|  | _("Argument must be a type.")); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | try | 
|  | { | 
|  | struct value *val = ((value_object *) self)->value; | 
|  | struct value *res_val; | 
|  | scoped_value_mark free_values; | 
|  |  | 
|  | 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); | 
|  | } | 
|  |  | 
|  | result = value_to_value_object (res_val); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* 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) | 
|  | { | 
|  | /* We don't support getting the number of elements in a struct / class.  */ | 
|  | PyErr_SetString (PyExc_NotImplementedError, | 
|  | _("Invalid operation on gdb.Value.")); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* Return 1 if the gdb.Field object FIELD is present in the value V. | 
|  | Returns 0 otherwise.  If any Python error occurs, -1 is returned.  */ | 
|  |  | 
|  | static int | 
|  | value_has_field (struct value *v, PyObject *field) | 
|  | { | 
|  | struct type *parent_type, *val_type; | 
|  | enum type_code type_code; | 
|  | gdbpy_ref<> type_object (PyObject_GetAttrString (field, "parent_type")); | 
|  | int has_field = 0; | 
|  |  | 
|  | if (type_object == NULL) | 
|  | return -1; | 
|  |  | 
|  | parent_type = type_object_to_type (type_object.get ()); | 
|  | if (parent_type == NULL) | 
|  | { | 
|  | PyErr_SetString (PyExc_TypeError, | 
|  | _("'parent_type' attribute of gdb.Field object is not a" | 
|  | "gdb.Type object.")); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | try | 
|  | { | 
|  | val_type = value_type (v); | 
|  | val_type = check_typedef (val_type); | 
|  | if (val_type->is_pointer_or_reference ()) | 
|  | val_type = check_typedef (val_type->target_type ()); | 
|  |  | 
|  | type_code = val_type->code (); | 
|  | if ((type_code == TYPE_CODE_STRUCT || type_code == TYPE_CODE_UNION) | 
|  | && types_equal (val_type, parent_type)) | 
|  | has_field = 1; | 
|  | else | 
|  | has_field = 0; | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_SET_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | return has_field; | 
|  | } | 
|  |  | 
|  | /* Return the value of a flag FLAG_NAME in a gdb.Field object FIELD. | 
|  | Returns 1 if the flag value is true, 0 if it is false, and -1 if | 
|  | a Python error occurs.  */ | 
|  |  | 
|  | static int | 
|  | get_field_flag (PyObject *field, const char *flag_name) | 
|  | { | 
|  | gdbpy_ref<> flag_object (PyObject_GetAttrString (field, flag_name)); | 
|  |  | 
|  | if (flag_object == NULL) | 
|  | return -1; | 
|  |  | 
|  | return PyObject_IsTrue (flag_object.get ()); | 
|  | } | 
|  |  | 
|  | /* Return the "type" attribute of a gdb.Field object. | 
|  | Returns NULL on error, with a Python exception set.  */ | 
|  |  | 
|  | static struct type * | 
|  | get_field_type (PyObject *field) | 
|  | { | 
|  | gdbpy_ref<> ftype_obj (PyObject_GetAttrString (field, "type")); | 
|  | struct type *ftype; | 
|  |  | 
|  | if (ftype_obj == NULL) | 
|  | return NULL; | 
|  | ftype = type_object_to_type (ftype_obj.get ()); | 
|  | if (ftype == NULL) | 
|  | PyErr_SetString (PyExc_TypeError, | 
|  | _("'type' attribute of gdb.Field object is not a " | 
|  | "gdb.Type object.")); | 
|  |  | 
|  | return ftype; | 
|  | } | 
|  |  | 
|  | /* Given string name or a gdb.Field object corresponding to an element inside | 
|  | a structure, return its value object.  Returns NULL on error, with a python | 
|  | exception set.  */ | 
|  |  | 
|  | static PyObject * | 
|  | valpy_getitem (PyObject *self, PyObject *key) | 
|  | { | 
|  | struct gdb_exception except; | 
|  | value_object *self_value = (value_object *) self; | 
|  | gdb::unique_xmalloc_ptr<char> field; | 
|  | struct type *base_class_type = NULL, *field_type = NULL; | 
|  | long bitpos = -1; | 
|  | PyObject *result = NULL; | 
|  |  | 
|  | if (gdbpy_is_string (key)) | 
|  | { | 
|  | field = python_string_to_host_string (key); | 
|  | if (field == NULL) | 
|  | return NULL; | 
|  | } | 
|  | else if (gdbpy_is_field (key)) | 
|  | { | 
|  | int is_base_class, valid_field; | 
|  |  | 
|  | valid_field = value_has_field (self_value->value, key); | 
|  | if (valid_field < 0) | 
|  | return NULL; | 
|  | else if (valid_field == 0) | 
|  | { | 
|  | PyErr_SetString (PyExc_TypeError, | 
|  | _("Invalid lookup for a field not contained in " | 
|  | "the value.")); | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | is_base_class = get_field_flag (key, "is_base_class"); | 
|  | if (is_base_class < 0) | 
|  | return NULL; | 
|  | else if (is_base_class > 0) | 
|  | { | 
|  | base_class_type = get_field_type (key); | 
|  | if (base_class_type == NULL) | 
|  | return NULL; | 
|  | } | 
|  | else | 
|  | { | 
|  | gdbpy_ref<> name_obj (PyObject_GetAttrString (key, "name")); | 
|  |  | 
|  | if (name_obj == NULL) | 
|  | return NULL; | 
|  |  | 
|  | if (name_obj != Py_None) | 
|  | { | 
|  | field = python_string_to_host_string (name_obj.get ()); | 
|  | if (field == NULL) | 
|  | return NULL; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (!PyObject_HasAttrString (key, "bitpos")) | 
|  | { | 
|  | PyErr_SetString (PyExc_AttributeError, | 
|  | _("gdb.Field object has no name and no " | 
|  | "'bitpos' attribute.")); | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  | gdbpy_ref<> bitpos_obj (PyObject_GetAttrString (key, "bitpos")); | 
|  | if (bitpos_obj == NULL) | 
|  | return NULL; | 
|  | if (!gdb_py_int_as_long (bitpos_obj.get (), &bitpos)) | 
|  | return NULL; | 
|  |  | 
|  | field_type = get_field_type (key); | 
|  | if (field_type == NULL) | 
|  | return NULL; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | try | 
|  | { | 
|  | struct value *tmp = self_value->value; | 
|  | struct value *res_val = NULL; | 
|  | scoped_value_mark free_values; | 
|  |  | 
|  | if (field) | 
|  | res_val = value_struct_elt (&tmp, {}, field.get (), NULL, | 
|  | "struct/class/union"); | 
|  | else if (bitpos >= 0) | 
|  | res_val = value_struct_elt_bitpos (&tmp, bitpos, field_type, | 
|  | "struct/class/union"); | 
|  | else if (base_class_type != NULL) | 
|  | { | 
|  | struct type *val_type; | 
|  |  | 
|  | val_type = check_typedef (value_type (tmp)); | 
|  | if (val_type->code () == TYPE_CODE_PTR) | 
|  | res_val = value_cast (lookup_pointer_type (base_class_type), tmp); | 
|  | else if (val_type->code () == TYPE_CODE_REF) | 
|  | res_val = value_cast (lookup_lvalue_reference_type (base_class_type), | 
|  | tmp); | 
|  | else if (val_type->code () == TYPE_CODE_RVALUE_REF) | 
|  | res_val = value_cast (lookup_rvalue_reference_type (base_class_type), | 
|  | tmp); | 
|  | else | 
|  | res_val = value_cast (base_class_type, tmp); | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Assume we are attempting an array access, and let the | 
|  | value code throw an exception if the index has an invalid | 
|  | type.  */ | 
|  | struct value *idx = convert_value_from_python (key); | 
|  |  | 
|  | if (idx != NULL) | 
|  | { | 
|  | /* Check the value's type is something that can be accessed via | 
|  | a subscript.  */ | 
|  | struct type *type; | 
|  |  | 
|  | tmp = coerce_ref (tmp); | 
|  | type = check_typedef (value_type (tmp)); | 
|  | if (type->code () != TYPE_CODE_ARRAY | 
|  | && type->code () != TYPE_CODE_PTR) | 
|  | error (_("Cannot subscript requested type.")); | 
|  | else | 
|  | res_val = value_subscript (tmp, value_as_long (idx)); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (res_val) | 
|  | result = value_to_value_object (res_val); | 
|  | } | 
|  | catch (gdb_exception &ex) | 
|  | { | 
|  | except = std::move (ex); | 
|  | } | 
|  |  | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static int | 
|  | valpy_setitem (PyObject *self, PyObject *key, PyObject *value) | 
|  | { | 
|  | PyErr_Format (PyExc_NotImplementedError, | 
|  | _("Setting of struct elements is not currently supported.")); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* Called by the Python interpreter to perform an inferior function | 
|  | call on the value.  Returns NULL on error, with a python exception set.  */ | 
|  | static PyObject * | 
|  | valpy_call (PyObject *self, PyObject *args, PyObject *keywords) | 
|  | { | 
|  | Py_ssize_t args_count; | 
|  | struct value *function = ((value_object *) self)->value; | 
|  | struct value **vargs = NULL; | 
|  | struct type *ftype = NULL; | 
|  | PyObject *result = NULL; | 
|  |  | 
|  | try | 
|  | { | 
|  | ftype = check_typedef (value_type (function)); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | if (ftype->code () != TYPE_CODE_FUNC) | 
|  | { | 
|  | PyErr_SetString (PyExc_RuntimeError, | 
|  | _("Value is not callable (not 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) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | vargs = XALLOCAVEC (struct value *, args_count); | 
|  | for (i = 0; i < args_count; i++) | 
|  | { | 
|  | PyObject *item = PyTuple_GetItem (args, i); | 
|  |  | 
|  | if (item == NULL) | 
|  | return NULL; | 
|  |  | 
|  | vargs[i] = convert_value_from_python (item); | 
|  | if (vargs[i] == NULL) | 
|  | return NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | try | 
|  | { | 
|  | scoped_value_mark free_values; | 
|  |  | 
|  | value *return_value | 
|  | = call_function_by_hand (function, NULL, | 
|  | gdb::make_array_view (vargs, args_count)); | 
|  | result = value_to_value_object (return_value); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* Called by the Python interpreter to obtain string representation | 
|  | of the object.  */ | 
|  | static PyObject * | 
|  | valpy_str (PyObject *self) | 
|  | { | 
|  | struct value_print_options opts; | 
|  |  | 
|  | gdbpy_get_print_options (&opts); | 
|  | opts.deref_ref = false; | 
|  |  | 
|  | string_file stb; | 
|  |  | 
|  | try | 
|  | { | 
|  | common_val_print (((value_object *) self)->value, &stb, 0, | 
|  | &opts, current_language); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | return PyUnicode_Decode (stb.c_str (), stb.size (), host_charset (), NULL); | 
|  | } | 
|  |  | 
|  | /* Implements gdb.Value.is_optimized_out.  */ | 
|  | static PyObject * | 
|  | valpy_get_is_optimized_out (PyObject *self, void *closure) | 
|  | { | 
|  | struct value *value = ((value_object *) self)->value; | 
|  | int opt = 0; | 
|  |  | 
|  | try | 
|  | { | 
|  | opt = value_optimized_out (value); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | 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; | 
|  |  | 
|  | try | 
|  | { | 
|  | opt = value_lazy (value); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | 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; | 
|  |  | 
|  | try | 
|  | { | 
|  | if (value_lazy (value)) | 
|  | value_fetch_lazy (value); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | 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 Py_hash_t | 
|  | valpy_hash (PyObject *self) | 
|  | { | 
|  | return (intptr_t) self; | 
|  | } | 
|  |  | 
|  | enum valpy_opcode | 
|  | { | 
|  | VALPY_ADD, | 
|  | VALPY_SUB, | 
|  | VALPY_MUL, | 
|  | VALPY_DIV, | 
|  | VALPY_REM, | 
|  | VALPY_POW, | 
|  | VALPY_LSH, | 
|  | VALPY_RSH, | 
|  | VALPY_BITAND, | 
|  | VALPY_BITOR, | 
|  | VALPY_BITXOR | 
|  | }; | 
|  |  | 
|  | /* If TYPE is a reference, return the target; otherwise return TYPE.  */ | 
|  | #define STRIP_REFERENCE(TYPE) \ | 
|  | (TYPE_IS_REFERENCE (TYPE) ? ((TYPE)->target_type ()) : (TYPE)) | 
|  |  | 
|  | /* Helper for valpy_binop.  Returns a value object which is the result | 
|  | of applying the operation specified by OPCODE to the given | 
|  | arguments.  Throws a GDB exception on error.  */ | 
|  |  | 
|  | static PyObject * | 
|  | valpy_binop_throw (enum valpy_opcode opcode, PyObject *self, PyObject *other) | 
|  | { | 
|  | PyObject *result = NULL; | 
|  |  | 
|  | struct value *arg1, *arg2; | 
|  | struct value *res_val = NULL; | 
|  | enum exp_opcode op = OP_NULL; | 
|  | int handled = 0; | 
|  |  | 
|  | scoped_value_mark free_values; | 
|  |  | 
|  | /* If the gdb.Value object is the second operand, then it will be | 
|  | passed to us as the OTHER argument, and SELF will be an entirely | 
|  | different kind of object, altogether.  Because of this, we can't | 
|  | assume self is a gdb.Value object and need to convert it from | 
|  | python as well.  */ | 
|  | arg1 = convert_value_from_python (self); | 
|  | if (arg1 == NULL) | 
|  | return NULL; | 
|  |  | 
|  | arg2 = convert_value_from_python (other); | 
|  | if (arg2 == NULL) | 
|  | return NULL; | 
|  |  | 
|  | switch (opcode) | 
|  | { | 
|  | case VALPY_ADD: | 
|  | { | 
|  | struct type *ltype = value_type (arg1); | 
|  | struct type *rtype = value_type (arg2); | 
|  |  | 
|  | ltype = check_typedef (ltype); | 
|  | ltype = STRIP_REFERENCE (ltype); | 
|  | rtype = check_typedef (rtype); | 
|  | rtype = STRIP_REFERENCE (rtype); | 
|  |  | 
|  | handled = 1; | 
|  | if (ltype->code () == TYPE_CODE_PTR | 
|  | && is_integral_type (rtype)) | 
|  | res_val = value_ptradd (arg1, value_as_long (arg2)); | 
|  | else if (rtype->code () == TYPE_CODE_PTR | 
|  | && is_integral_type (ltype)) | 
|  | res_val = value_ptradd (arg2, value_as_long (arg1)); | 
|  | else | 
|  | { | 
|  | handled = 0; | 
|  | op = BINOP_ADD; | 
|  | } | 
|  | } | 
|  | break; | 
|  | case VALPY_SUB: | 
|  | { | 
|  | struct type *ltype = value_type (arg1); | 
|  | struct type *rtype = value_type (arg2); | 
|  |  | 
|  | ltype = check_typedef (ltype); | 
|  | ltype = STRIP_REFERENCE (ltype); | 
|  | rtype = check_typedef (rtype); | 
|  | rtype = STRIP_REFERENCE (rtype); | 
|  |  | 
|  | handled = 1; | 
|  | if (ltype->code () == TYPE_CODE_PTR | 
|  | && rtype->code () == TYPE_CODE_PTR) | 
|  | /* A ptrdiff_t for the target would be preferable here.  */ | 
|  | res_val = value_from_longest (builtin_type_pyint, | 
|  | value_ptrdiff (arg1, arg2)); | 
|  | else if (ltype->code () == TYPE_CODE_PTR | 
|  | && is_integral_type (rtype)) | 
|  | res_val = value_ptradd (arg1, - value_as_long (arg2)); | 
|  | else | 
|  | { | 
|  | handled = 0; | 
|  | op = BINOP_SUB; | 
|  | } | 
|  | } | 
|  | break; | 
|  | case VALPY_MUL: | 
|  | op = BINOP_MUL; | 
|  | break; | 
|  | case VALPY_DIV: | 
|  | op = BINOP_DIV; | 
|  | break; | 
|  | case VALPY_REM: | 
|  | op = BINOP_REM; | 
|  | break; | 
|  | case VALPY_POW: | 
|  | op = BINOP_EXP; | 
|  | break; | 
|  | case VALPY_LSH: | 
|  | op = BINOP_LSH; | 
|  | break; | 
|  | case VALPY_RSH: | 
|  | op = BINOP_RSH; | 
|  | break; | 
|  | case VALPY_BITAND: | 
|  | op = BINOP_BITWISE_AND; | 
|  | break; | 
|  | case VALPY_BITOR: | 
|  | op = BINOP_BITWISE_IOR; | 
|  | break; | 
|  | case VALPY_BITXOR: | 
|  | op = BINOP_BITWISE_XOR; | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (!handled) | 
|  | { | 
|  | if (binop_user_defined_p (op, arg1, arg2)) | 
|  | res_val = value_x_binop (arg1, arg2, op, OP_NULL, EVAL_NORMAL); | 
|  | else | 
|  | res_val = value_binop (arg1, arg2, op); | 
|  | } | 
|  |  | 
|  | if (res_val) | 
|  | result = value_to_value_object (res_val); | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* Returns a value object which is the result of applying the operation | 
|  | 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) | 
|  | { | 
|  | PyObject *result = NULL; | 
|  |  | 
|  | try | 
|  | { | 
|  | result = valpy_binop_throw (opcode, self, other); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static PyObject * | 
|  | valpy_add (PyObject *self, PyObject *other) | 
|  | { | 
|  | return valpy_binop (VALPY_ADD, self, other); | 
|  | } | 
|  |  | 
|  | static PyObject * | 
|  | valpy_subtract (PyObject *self, PyObject *other) | 
|  | { | 
|  | return valpy_binop (VALPY_SUB, self, other); | 
|  | } | 
|  |  | 
|  | static PyObject * | 
|  | valpy_multiply (PyObject *self, PyObject *other) | 
|  | { | 
|  | return valpy_binop (VALPY_MUL, self, other); | 
|  | } | 
|  |  | 
|  | static PyObject * | 
|  | valpy_divide (PyObject *self, PyObject *other) | 
|  | { | 
|  | return valpy_binop (VALPY_DIV, self, other); | 
|  | } | 
|  |  | 
|  | static PyObject * | 
|  | valpy_remainder (PyObject *self, PyObject *other) | 
|  | { | 
|  | return valpy_binop (VALPY_REM, self, other); | 
|  | } | 
|  |  | 
|  | static PyObject * | 
|  | valpy_power (PyObject *self, PyObject *other, PyObject *unused) | 
|  | { | 
|  | /* We don't support the ternary form of pow.  I don't know how to express | 
|  | that, so let's just throw NotImplementedError to at least do something | 
|  | about it.  */ | 
|  | if (unused != Py_None) | 
|  | { | 
|  | PyErr_SetString (PyExc_NotImplementedError, | 
|  | "Invalid operation on gdb.Value."); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return valpy_binop (VALPY_POW, self, other); | 
|  | } | 
|  |  | 
|  | static PyObject * | 
|  | valpy_negative (PyObject *self) | 
|  | { | 
|  | PyObject *result = NULL; | 
|  |  | 
|  | try | 
|  | { | 
|  | /* Perhaps overkill, but consistency has some virtue.  */ | 
|  | scoped_value_mark free_values; | 
|  | struct value *val; | 
|  |  | 
|  | val = value_neg (((value_object *) self)->value); | 
|  | result = value_to_value_object (val); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static PyObject * | 
|  | valpy_positive (PyObject *self) | 
|  | { | 
|  | return value_to_value_object (((value_object *) self)->value); | 
|  | } | 
|  |  | 
|  | static PyObject * | 
|  | valpy_absolute (PyObject *self) | 
|  | { | 
|  | struct value *value = ((value_object *) self)->value; | 
|  | int isabs = 1; | 
|  |  | 
|  | try | 
|  | { | 
|  | scoped_value_mark free_values; | 
|  |  | 
|  | if (value_less (value, value_zero (value_type (value), not_lval))) | 
|  | isabs = 0; | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | 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) | 
|  | { | 
|  | struct gdb_exception except; | 
|  | value_object *self_value = (value_object *) self; | 
|  | struct type *type; | 
|  | int nonzero = 0; /* Appease GCC warning.  */ | 
|  |  | 
|  | try | 
|  | { | 
|  | type = check_typedef (value_type (self_value->value)); | 
|  |  | 
|  | if (is_integral_type (type) || type->code () == TYPE_CODE_PTR) | 
|  | nonzero = !!value_as_long (self_value->value); | 
|  | else if (is_floating_value (self_value->value)) | 
|  | nonzero = !target_float_is_zero | 
|  | (value_contents (self_value->value).data (), type); | 
|  | else | 
|  | /* All other values are True.  */ | 
|  | nonzero = 1; | 
|  | } | 
|  | catch (gdb_exception &ex) | 
|  | { | 
|  | except = std::move (ex); | 
|  | } | 
|  |  | 
|  | /* 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.  */ | 
|  | static PyObject * | 
|  | valpy_invert (PyObject *self) | 
|  | { | 
|  | struct value *val = NULL; | 
|  |  | 
|  | try | 
|  | { | 
|  | val = value_complement (((value_object *) self)->value); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | return value_to_value_object (val); | 
|  | } | 
|  |  | 
|  | /* Implements left shift for value objects.  */ | 
|  | static PyObject * | 
|  | valpy_lsh (PyObject *self, PyObject *other) | 
|  | { | 
|  | return valpy_binop (VALPY_LSH, self, other); | 
|  | } | 
|  |  | 
|  | /* Implements right shift for value objects.  */ | 
|  | static PyObject * | 
|  | valpy_rsh (PyObject *self, PyObject *other) | 
|  | { | 
|  | return valpy_binop (VALPY_RSH, self, other); | 
|  | } | 
|  |  | 
|  | /* Implements bitwise and for value objects.  */ | 
|  | static PyObject * | 
|  | valpy_and (PyObject *self, PyObject *other) | 
|  | { | 
|  | return valpy_binop (VALPY_BITAND, self, other); | 
|  | } | 
|  |  | 
|  | /* Implements bitwise or for value objects.  */ | 
|  | static PyObject * | 
|  | valpy_or (PyObject *self, PyObject *other) | 
|  | { | 
|  | return valpy_binop (VALPY_BITOR, self, other); | 
|  | } | 
|  |  | 
|  | /* Implements bitwise xor for value objects.  */ | 
|  | static PyObject * | 
|  | valpy_xor (PyObject *self, PyObject *other) | 
|  | { | 
|  | return valpy_binop (VALPY_BITXOR, self, other); | 
|  | } | 
|  |  | 
|  | /* Helper for valpy_richcompare.  Implements comparison operations for | 
|  | value objects.  Returns true/false on success.  Returns -1 with a | 
|  | Python exception set if a Python error is detected.  Throws a GDB | 
|  | exception on other errors (memory error, etc.).  */ | 
|  |  | 
|  | static int | 
|  | valpy_richcompare_throw (PyObject *self, PyObject *other, int op) | 
|  | { | 
|  | int result; | 
|  | struct value *value_other; | 
|  | struct value *value_self; | 
|  |  | 
|  | scoped_value_mark free_values; | 
|  |  | 
|  | value_other = convert_value_from_python (other); | 
|  | if (value_other == NULL) | 
|  | return -1; | 
|  |  | 
|  | value_self = ((value_object *) self)->value; | 
|  |  | 
|  | switch (op) | 
|  | { | 
|  | case Py_LT: | 
|  | result = value_less (value_self, value_other); | 
|  | break; | 
|  | case Py_LE: | 
|  | result = value_less (value_self, value_other) | 
|  | || value_equal (value_self, value_other); | 
|  | break; | 
|  | case Py_EQ: | 
|  | result = value_equal (value_self, value_other); | 
|  | break; | 
|  | case Py_NE: | 
|  | result = !value_equal (value_self, value_other); | 
|  | break; | 
|  | case Py_GT: | 
|  | result = value_less (value_other, value_self); | 
|  | break; | 
|  | case Py_GE: | 
|  | result = (value_less (value_other, value_self) | 
|  | || value_equal (value_self, value_other)); | 
|  | break; | 
|  | default: | 
|  | /* Can't happen.  */ | 
|  | PyErr_SetString (PyExc_NotImplementedError, | 
|  | _("Invalid operation on gdb.Value.")); | 
|  | result = -1; | 
|  | break; | 
|  | } | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* 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) | 
|  | { | 
|  | int result = 0; | 
|  |  | 
|  | if (other == Py_None) | 
|  | /* Comparing with None is special.  From what I can tell, in Python | 
|  | None is smaller than anything else.  */ | 
|  | switch (op) { | 
|  | case Py_LT: | 
|  | case Py_LE: | 
|  | case Py_EQ: | 
|  | Py_RETURN_FALSE; | 
|  | case Py_NE: | 
|  | case Py_GT: | 
|  | case Py_GE: | 
|  | Py_RETURN_TRUE; | 
|  | default: | 
|  | /* Can't happen.  */ | 
|  | PyErr_SetString (PyExc_NotImplementedError, | 
|  | _("Invalid operation on gdb.Value.")); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | try | 
|  | { | 
|  | result = valpy_richcompare_throw (self, other, op); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | /* In this case, the Python exception has already been set.  */ | 
|  | if (result < 0) | 
|  | return NULL; | 
|  |  | 
|  | if (result == 1) | 
|  | Py_RETURN_TRUE; | 
|  |  | 
|  | Py_RETURN_FALSE; | 
|  | } | 
|  |  | 
|  | /* Implements conversion to long.  */ | 
|  | static PyObject * | 
|  | valpy_long (PyObject *self) | 
|  | { | 
|  | struct value *value = ((value_object *) self)->value; | 
|  | struct type *type = value_type (value); | 
|  | LONGEST l = 0; | 
|  |  | 
|  | try | 
|  | { | 
|  | if (is_floating_value (value)) | 
|  | { | 
|  | type = builtin_type_pylong; | 
|  | value = value_cast (type, value); | 
|  | } | 
|  |  | 
|  | type = check_typedef (type); | 
|  |  | 
|  | if (!is_integral_type (type) | 
|  | && type->code () != TYPE_CODE_PTR) | 
|  | error (_("Cannot convert value to long.")); | 
|  |  | 
|  | l = value_as_long (value); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | if (type->is_unsigned ()) | 
|  | return gdb_py_object_from_ulongest (l).release (); | 
|  | else | 
|  | return gdb_py_object_from_longest (l).release (); | 
|  | } | 
|  |  | 
|  | /* Implements conversion to float.  */ | 
|  | static PyObject * | 
|  | valpy_float (PyObject *self) | 
|  | { | 
|  | struct value *value = ((value_object *) self)->value; | 
|  | struct type *type = value_type (value); | 
|  | double d = 0; | 
|  |  | 
|  | try | 
|  | { | 
|  | type = check_typedef (type); | 
|  |  | 
|  | if (type->code () == TYPE_CODE_FLT && is_floating_value (value)) | 
|  | d = target_float_to_host_double (value_contents (value).data (), type); | 
|  | else if (type->code () == TYPE_CODE_INT) | 
|  | { | 
|  | /* Note that valpy_long accepts TYPE_CODE_PTR and some | 
|  | others here here -- but casting a pointer or bool to a | 
|  | float seems wrong.  */ | 
|  | d = value_as_long (value); | 
|  | } | 
|  | else | 
|  | error (_("Cannot convert value to float.")); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | return PyFloat_FromDouble (d); | 
|  | } | 
|  |  | 
|  | /* 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 *val) | 
|  | { | 
|  | value_object *val_obj; | 
|  |  | 
|  | val_obj = PyObject_New (value_object, &value_object_type); | 
|  | if (val_obj != NULL) | 
|  | { | 
|  | val_obj->value = release_value (val).release (); | 
|  | val_obj->next = nullptr; | 
|  | val_obj->prev = nullptr; | 
|  | val_obj->address = NULL; | 
|  | val_obj->type = NULL; | 
|  | val_obj->dynamic_type = NULL; | 
|  | note_value (val_obj); | 
|  | } | 
|  |  | 
|  | return (PyObject *) val_obj; | 
|  | } | 
|  |  | 
|  | /* Returns an object for a value, but without releasing it from the | 
|  | all_values chain.  */ | 
|  | PyObject * | 
|  | value_to_value_object_no_release (struct value *val) | 
|  | { | 
|  | value_object *val_obj; | 
|  |  | 
|  | val_obj = PyObject_New (value_object, &value_object_type); | 
|  | if (val_obj != NULL) | 
|  | { | 
|  | value_incref (val); | 
|  | val_obj->value = val; | 
|  | val_obj->next = nullptr; | 
|  | val_obj->prev = nullptr; | 
|  | val_obj->address = NULL; | 
|  | val_obj->type = NULL; | 
|  | val_obj->dynamic_type = NULL; | 
|  | note_value (val_obj); | 
|  | } | 
|  |  | 
|  | return (PyObject *) val_obj; | 
|  | } | 
|  |  | 
|  | /* Returns a borrowed reference to the struct value corresponding to | 
|  | the given value object.  */ | 
|  | struct value * | 
|  | value_object_to_value (PyObject *self) | 
|  | { | 
|  | value_object *real; | 
|  |  | 
|  | if (! PyObject_TypeCheck (self, &value_object_type)) | 
|  | return NULL; | 
|  | real = (value_object *) self; | 
|  | return real->value; | 
|  | } | 
|  |  | 
|  | /* Try to convert a Python value to a gdb value.  If the value cannot | 
|  | be converted, set a Python exception and return NULL.  Returns a | 
|  | reference to a new value on the all_values chain.  */ | 
|  |  | 
|  | struct value * | 
|  | convert_value_from_python (PyObject *obj) | 
|  | { | 
|  | struct value *value = NULL; /* -Wall */ | 
|  | int cmp; | 
|  |  | 
|  | gdb_assert (obj != NULL); | 
|  |  | 
|  | try | 
|  | { | 
|  | if (PyBool_Check (obj)) | 
|  | { | 
|  | cmp = PyObject_IsTrue (obj); | 
|  | if (cmp >= 0) | 
|  | value = value_from_longest (builtin_type_pybool, cmp); | 
|  | } | 
|  | else if (PyLong_Check (obj)) | 
|  | { | 
|  | LONGEST l = PyLong_AsLongLong (obj); | 
|  |  | 
|  | if (PyErr_Occurred ()) | 
|  | { | 
|  | /* If the error was an overflow, we can try converting to | 
|  | ULONGEST instead.  */ | 
|  | if (PyErr_ExceptionMatches (PyExc_OverflowError)) | 
|  | { | 
|  | gdbpy_err_fetch fetched_error; | 
|  | gdbpy_ref<> zero = gdb_py_object_from_longest (0); | 
|  |  | 
|  | /* Check whether obj is positive.  */ | 
|  | if (PyObject_RichCompareBool (obj, zero.get (), Py_GT) > 0) | 
|  | { | 
|  | ULONGEST ul; | 
|  |  | 
|  | ul = PyLong_AsUnsignedLongLong (obj); | 
|  | if (! PyErr_Occurred ()) | 
|  | value = value_from_ulongest (builtin_type_upylong, ul); | 
|  | } | 
|  | else | 
|  | { | 
|  | /* There's nothing we can do.  */ | 
|  | fetched_error.restore (); | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | value = value_from_longest (builtin_type_pylong, l); | 
|  | } | 
|  | else if (PyFloat_Check (obj)) | 
|  | { | 
|  | double d = PyFloat_AsDouble (obj); | 
|  |  | 
|  | if (! PyErr_Occurred ()) | 
|  | value = value_from_host_double (builtin_type_pyfloat, d); | 
|  | } | 
|  | else if (gdbpy_is_string (obj)) | 
|  | { | 
|  | gdb::unique_xmalloc_ptr<char> s | 
|  | = python_string_to_target_string (obj); | 
|  | if (s != NULL) | 
|  | value = value_cstring (s.get (), strlen (s.get ()), | 
|  | builtin_type_pychar); | 
|  | } | 
|  | else if (PyObject_TypeCheck (obj, &value_object_type)) | 
|  | value = value_copy (((value_object *) obj)->value); | 
|  | else if (gdbpy_is_lazy_string (obj)) | 
|  | { | 
|  | PyObject *result; | 
|  |  | 
|  | 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."), obj); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | gdbpy_convert_exception (except); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return value; | 
|  | } | 
|  |  | 
|  | /* Returns value object in the ARGth position in GDB's history.  */ | 
|  | PyObject * | 
|  | gdbpy_history (PyObject *self, PyObject *args) | 
|  | { | 
|  | int i; | 
|  | struct value *res_val = NULL;	  /* Initialize to appease gcc warning.  */ | 
|  |  | 
|  | if (!PyArg_ParseTuple (args, "i", &i)) | 
|  | return NULL; | 
|  |  | 
|  | try | 
|  | { | 
|  | res_val = access_value_history (i); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | return value_to_value_object (res_val); | 
|  | } | 
|  |  | 
|  | /* Add a gdb.Value into GDB's history, and return (as an integer) the | 
|  | position of the newly added value.  */ | 
|  | PyObject * | 
|  | gdbpy_add_history (PyObject *self, PyObject *args) | 
|  | { | 
|  | PyObject *value_obj; | 
|  |  | 
|  | if (!PyArg_ParseTuple (args, "O", &value_obj)) | 
|  | return nullptr; | 
|  |  | 
|  | struct value *value = convert_value_from_python (value_obj); | 
|  | if (value == nullptr) | 
|  | return nullptr; | 
|  |  | 
|  | try | 
|  | { | 
|  | int idx = record_latest_value (value); | 
|  | return gdb_py_object_from_longest (idx).release (); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | /* Return an integer, the number of items in GDB's history.  */ | 
|  |  | 
|  | PyObject * | 
|  | gdbpy_history_count (PyObject *self, PyObject *args) | 
|  | { | 
|  | return gdb_py_object_from_ulongest (value_history_count ()).release (); | 
|  | } | 
|  |  | 
|  | /* Return the value of a convenience variable.  */ | 
|  | PyObject * | 
|  | gdbpy_convenience_variable (PyObject *self, PyObject *args) | 
|  | { | 
|  | const char *varname; | 
|  | struct value *res_val = NULL; | 
|  |  | 
|  | if (!PyArg_ParseTuple (args, "s", &varname)) | 
|  | return NULL; | 
|  |  | 
|  | try | 
|  | { | 
|  | struct internalvar *var = lookup_only_internalvar (varname); | 
|  |  | 
|  | if (var != NULL) | 
|  | { | 
|  | res_val = value_of_internalvar (gdbpy_enter::get_gdbarch (), var); | 
|  | if (value_type (res_val)->code () == TYPE_CODE_VOID) | 
|  | res_val = NULL; | 
|  | } | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | if (res_val == NULL) | 
|  | Py_RETURN_NONE; | 
|  |  | 
|  | return value_to_value_object (res_val); | 
|  | } | 
|  |  | 
|  | /* Set the value of a convenience variable.  */ | 
|  | PyObject * | 
|  | gdbpy_set_convenience_variable (PyObject *self, PyObject *args) | 
|  | { | 
|  | const char *varname; | 
|  | PyObject *value_obj; | 
|  | struct value *value = NULL; | 
|  |  | 
|  | if (!PyArg_ParseTuple (args, "sO", &varname, &value_obj)) | 
|  | return NULL; | 
|  |  | 
|  | /* None means to clear the variable.  */ | 
|  | if (value_obj != Py_None) | 
|  | { | 
|  | value = convert_value_from_python (value_obj); | 
|  | if (value == NULL) | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | try | 
|  | { | 
|  | if (value == NULL) | 
|  | { | 
|  | struct internalvar *var = lookup_only_internalvar (varname); | 
|  |  | 
|  | if (var != NULL) | 
|  | clear_internalvar (var); | 
|  | } | 
|  | else | 
|  | { | 
|  | struct internalvar *var = lookup_internalvar (varname); | 
|  |  | 
|  | set_internalvar (var, value); | 
|  | } | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | Py_RETURN_NONE; | 
|  | } | 
|  |  | 
|  | /* Returns 1 in OBJ is a gdb.Value object, 0 otherwise.  */ | 
|  |  | 
|  | int | 
|  | gdbpy_is_value_object (PyObject *obj) | 
|  | { | 
|  | return PyObject_TypeCheck (obj, &value_object_type); | 
|  | } | 
|  |  | 
|  | int | 
|  | gdbpy_initialize_values (void) | 
|  | { | 
|  | if (PyType_Ready (&value_object_type) < 0) | 
|  | return -1; | 
|  |  | 
|  | return gdb_pymodule_addobject (gdb_module, "Value", | 
|  | (PyObject *) &value_object_type); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | static gdb_PyGetSetDef value_object_getset[] = { | 
|  | { "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).", | 
|  | 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." }, | 
|  | { "referenced_value", valpy_referenced_value, METH_NOARGS, | 
|  | "Return the value referenced by a TYPE_CODE_REF or TYPE_CODE_PTR value." }, | 
|  | { "reference_value", valpy_lvalue_reference_value, METH_NOARGS, | 
|  | "Return a value of type TYPE_CODE_REF referencing this value." }, | 
|  | { "rvalue_reference_value", valpy_rvalue_reference_value, METH_NOARGS, | 
|  | "Return a value of type TYPE_CODE_RVALUE_REF referencing this value." }, | 
|  | { "const_value", valpy_const_value, METH_NOARGS, | 
|  | "Return a 'const' qualied version of the same value." }, | 
|  | { "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." }, | 
|  | { "format_string", (PyCFunction) valpy_format_string, | 
|  | METH_VARARGS | METH_KEYWORDS, | 
|  | "format_string (...) -> string\n\ | 
|  | Return a string representation of the value using the specified\n\ | 
|  | formatting options" }, | 
|  | {NULL}  /* Sentinel */ | 
|  | }; | 
|  |  | 
|  | static PyNumberMethods value_object_as_number = { | 
|  | valpy_add, | 
|  | valpy_subtract, | 
|  | valpy_multiply, | 
|  | valpy_remainder, | 
|  | NULL,			      /* nb_divmod */ | 
|  | valpy_power,		      /* nb_power */ | 
|  | valpy_negative,	      /* nb_negative */ | 
|  | valpy_positive,	      /* nb_positive */ | 
|  | valpy_absolute,	      /* nb_absolute */ | 
|  | valpy_nonzero,	      /* nb_nonzero */ | 
|  | valpy_invert,		      /* nb_invert */ | 
|  | valpy_lsh,		      /* nb_lshift */ | 
|  | valpy_rsh,		      /* nb_rshift */ | 
|  | valpy_and,		      /* nb_and */ | 
|  | valpy_xor,		      /* nb_xor */ | 
|  | valpy_or,		      /* nb_or */ | 
|  | valpy_long,		      /* nb_int */ | 
|  | NULL,			      /* reserved */ | 
|  | valpy_float,		      /* nb_float */ | 
|  | NULL,                       /* nb_inplace_add */ | 
|  | NULL,                       /* nb_inplace_subtract */ | 
|  | NULL,                       /* nb_inplace_multiply */ | 
|  | NULL,                       /* nb_inplace_remainder */ | 
|  | NULL,                       /* nb_inplace_power */ | 
|  | NULL,                       /* nb_inplace_lshift */ | 
|  | NULL,                       /* nb_inplace_rshift */ | 
|  | NULL,                       /* nb_inplace_and */ | 
|  | NULL,                       /* nb_inplace_xor */ | 
|  | NULL,                       /* nb_inplace_or */ | 
|  | NULL,                       /* nb_floor_divide */ | 
|  | valpy_divide,               /* nb_true_divide */ | 
|  | NULL,			      /* nb_inplace_floor_divide */ | 
|  | NULL,			      /* nb_inplace_true_divide */ | 
|  | valpy_long,		      /* nb_index */ | 
|  | }; | 
|  |  | 
|  | static PyMappingMethods value_object_as_mapping = { | 
|  | valpy_length, | 
|  | valpy_getitem, | 
|  | valpy_setitem | 
|  | }; | 
|  |  | 
|  | PyTypeObject value_object_type = { | 
|  | PyVarObject_HEAD_INIT (NULL, 0) | 
|  | "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*/ | 
|  | &value_object_as_number,	  /*tp_as_number*/ | 
|  | 0,				  /*tp_as_sequence*/ | 
|  | &value_object_as_mapping,	  /*tp_as_mapping*/ | 
|  | valpy_hash,		          /*tp_hash*/ | 
|  | valpy_call,	                  /*tp_call*/ | 
|  | valpy_str,			  /*tp_str*/ | 
|  | 0,				  /*tp_getattro*/ | 
|  | 0,				  /*tp_setattro*/ | 
|  | 0,				  /*tp_as_buffer*/ | 
|  | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | 
|  | | Py_TPFLAGS_BASETYPE,	  /*tp_flags*/ | 
|  | "GDB value object",		  /* tp_doc */ | 
|  | 0,				  /* tp_traverse */ | 
|  | 0,				  /* tp_clear */ | 
|  | valpy_richcompare,		  /* tp_richcompare */ | 
|  | 0,				  /* tp_weaklistoffset */ | 
|  | 0,				  /* tp_iter */ | 
|  | 0,				  /* tp_iternext */ | 
|  | value_object_methods,		  /* tp_methods */ | 
|  | 0,				  /* tp_members */ | 
|  | value_object_getset,		  /* tp_getset */ | 
|  | 0,				  /* tp_base */ | 
|  | 0,				  /* tp_dict */ | 
|  | 0,				  /* tp_descr_get */ | 
|  | 0,				  /* tp_descr_set */ | 
|  | 0,				  /* tp_dictoffset */ | 
|  | valpy_init,			  /* tp_init */ | 
|  | 0,				  /* tp_alloc */ | 
|  | PyType_GenericNew,		  /* tp_new */ | 
|  | }; |