X-Git-Url: https://repo.jachan.dev/binutils.git/blobdiff_plain/f5f8b5baf4e8df45804583c7a8494b1f257cc0ed..66d7f48f8045adf266046df7ceb84161d5678cfa:/gdb/python/py-lazy-string.c diff --git a/gdb/python/py-lazy-string.c b/gdb/python/py-lazy-string.c index ebe0a99a3b..69b1bc52ab 100644 --- a/gdb/python/py-lazy-string.c +++ b/gdb/python/py-lazy-string.c @@ -1,6 +1,6 @@ /* Python interface to lazy strings. - Copyright (C) 2010 Free Software Foundation, Inc. + Copyright (C) 2010-2022 Free Software Foundation, Inc. This file is part of GDB. @@ -21,12 +21,12 @@ #include "python-internal.h" #include "charset.h" #include "value.h" -#include "exceptions.h" #include "valprint.h" #include "language.h" -typedef struct { +struct lazy_string_object { PyObject_HEAD + /* Holds the address of the lazy string. */ CORE_ADDR address; @@ -36,23 +36,32 @@ typedef struct { encoding when the sting is printed. */ char *encoding; - /* Holds the length of the string in characters. If the - length is -1, then the string will be fetched and encoded up to - the first null of appropriate width. */ + /* If TYPE is an array: If the length is known, then this value is the + array's length, otherwise it is -1. + If TYPE is not an array: Then this value represents the string's length. + In either case, if the value is -1 then the string will be fetched and + encoded up to the first null of appropriate width. */ long length; - /* This attribute holds the type that is represented by the lazy - string's type. */ - struct type *type; -} lazy_string_object; + /* This attribute holds the type of the string. + For example if the lazy string was created from a C "char*" then TYPE + represents a C "char*". + To get the type of the character in the string call + stpy_lazy_string_elt_type. + This is recorded as a PyObject so that we take advantage of support for + preserving the type should its owning objfile go away. */ + PyObject *type; +}; -static PyTypeObject lazy_string_object_type; +extern PyTypeObject lazy_string_object_type + CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("lazy_string_object"); static PyObject * stpy_get_address (PyObject *self, void *closure) { lazy_string_object *self_string = (lazy_string_object *) self; - return PyLong_FromUnsignedLongLong (self_string->address); + + return gdb_py_object_from_ulongest (self_string->address).release (); } static PyObject * @@ -78,30 +87,66 @@ static PyObject * stpy_get_length (PyObject *self, void *closure) { lazy_string_object *self_string = (lazy_string_object *) self; - return PyLong_FromLong (self_string->length); + + return gdb_py_object_from_longest (self_string->length).release (); } -PyObject * +static PyObject * stpy_get_type (PyObject *self, void *closure) { lazy_string_object *str_obj = (lazy_string_object *) self; - return type_to_type_object (str_obj->type); + + Py_INCREF (str_obj->type); + return str_obj->type; } static PyObject * -stpy_convert_to_value (PyObject *self, PyObject *args) +stpy_convert_to_value (PyObject *self, PyObject *args) { lazy_string_object *self_string = (lazy_string_object *) self; - struct value *val; + struct value *val = NULL; if (self_string->address == 0) { - PyErr_SetString (PyExc_MemoryError, - _("Cannot create a value from NULL")); + PyErr_SetString (gdbpy_gdb_memory_error, + _("Cannot create a value from NULL.")); return NULL; } - val = value_at_lazy (self_string->type, self_string->address); + try + { + struct type *type = type_object_to_type (self_string->type); + struct type *realtype; + + gdb_assert (type != NULL); + realtype = check_typedef (type); + switch (realtype->code ()) + { + case TYPE_CODE_PTR: + /* If a length is specified we need to convert this to an array + of the specified size. */ + if (self_string->length != -1) + { + /* 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 is one possible solution. */ + type = lookup_array_range_type (TYPE_TARGET_TYPE (realtype), + 0, self_string->length - 1); + val = value_at_lazy (type, self_string->address); + } + else + val = value_from_pointer (type, self_string->address); + break; + default: + val = value_at_lazy (type, self_string->address); + break; + } + } + catch (const gdb_exception &except) + { + GDB_PY_HANDLE_EXCEPTION (except); + } + return value_to_value_object (val); } @@ -109,18 +154,33 @@ static void stpy_dealloc (PyObject *self) { lazy_string_object *self_string = (lazy_string_object *) self; + xfree (self_string->encoding); + Py_TYPE (self)->tp_free (self); } +/* Low level routine to create a object. + + Note: If TYPE is an array, LENGTH either must be -1 (meaning to use the + size of the array, which may itself be unknown in which case a length of + -1 is still used) or must be the length of the array. */ + PyObject * gdbpy_create_lazy_string_object (CORE_ADDR address, long length, - const char *encoding, struct type *type) + const char *encoding, struct type *type) { lazy_string_object *str_obj = NULL; + struct type *realtype; + + if (length < -1) + { + PyErr_SetString (PyExc_ValueError, _("Invalid length.")); + return NULL; + } if (address == 0 && length != 0) { - PyErr_SetString (PyExc_MemoryError, + PyErr_SetString (gdbpy_gdb_memory_error, _("Cannot create a lazy string with address 0x0, " \ "and a non-zero length.")); return NULL; @@ -129,10 +189,31 @@ gdbpy_create_lazy_string_object (CORE_ADDR address, long length, if (!type) { PyErr_SetString (PyExc_RuntimeError, - "A lazy string's type cannot be NULL."); + _("A lazy string's type cannot be NULL.")); return NULL; } + realtype = check_typedef (type); + switch (realtype->code ()) + { + case TYPE_CODE_ARRAY: + { + LONGEST array_length = -1; + LONGEST low_bound, high_bound; + + if (get_array_bounds (realtype, &low_bound, &high_bound)) + array_length = high_bound - low_bound + 1; + if (length == -1) + length = array_length; + else if (length != array_length) + { + PyErr_SetString (PyExc_ValueError, _("Invalid length.")); + return NULL; + } + break; + } + } + str_obj = PyObject_New (lazy_string_object, &lazy_string_object_type); if (!str_obj) return NULL; @@ -143,18 +224,19 @@ gdbpy_create_lazy_string_object (CORE_ADDR address, long length, str_obj->encoding = NULL; else str_obj->encoding = xstrdup (encoding); - str_obj->type = type; + str_obj->type = type_to_type_object (type); return (PyObject *) str_obj; } -void +int gdbpy_initialize_lazy_string (void) { if (PyType_Ready (&lazy_string_object_type) < 0) - return; + return -1; Py_INCREF (&lazy_string_object_type); + return 0; } /* Determine whether the printer object pointed to by OBJ is a @@ -165,86 +247,48 @@ gdbpy_is_lazy_string (PyObject *result) return PyObject_TypeCheck (result, &lazy_string_object_type); } -/* Extract and return the actual string from the lazy string object - STRING. Addtionally, the string type is written to *STR_TYPE, the - string length is written to *LENGTH, and the string encoding is - written to *ENCODING. On error, NULL is returned. The caller is - responsible for freeing the returned buffer. */ -gdb_byte * -gdbpy_extract_lazy_string (PyObject *string, struct type **str_type, - long *length, char **encoding) +/* Return the type of a character in lazy string LAZY. */ + +static struct type * +stpy_lazy_string_elt_type (lazy_string_object *lazy) { - int width; - int bytes_read; - gdb_byte *buffer = NULL; - int errcode = 0; - CORE_ADDR addr; - struct gdbarch *gdbarch; - enum bfd_endian byte_order; - PyObject *py_len = NULL, *py_encoding = NULL; - PyObject *py_addr = NULL, *py_type = NULL; - volatile struct gdb_exception except; - - py_len = PyObject_GetAttrString (string, "length"); - py_encoding = PyObject_GetAttrString (string, "encoding"); - py_addr = PyObject_GetAttrString (string, "address"); - py_type = PyObject_GetAttrString (string, "type"); - - /* A NULL encoding, length, address or type is not ok. */ - if (!py_len || !py_encoding || !py_addr || !py_type) - goto error; - - *length = PyLong_AsLong (py_len); - addr = PyLong_AsUnsignedLongLong (py_addr); - - /* If the user supplies Py_None an encoding, set encoding to NULL. - This will trigger the resulting LA_PRINT_CALL to automatically - select an encoding. */ - if (py_encoding == Py_None) - *encoding = NULL; - else - *encoding = xstrdup (PyString_AsString (py_encoding)); + struct type *type = type_object_to_type (lazy->type); + struct type *realtype; - *str_type = type_object_to_type (py_type); - gdbarch = get_type_arch (*str_type); - byte_order = gdbarch_byte_order (gdbarch); - width = TYPE_LENGTH (*str_type); + gdb_assert (type != NULL); + realtype = check_typedef (type); - TRY_CATCH (except, RETURN_MASK_ALL) + switch (realtype->code ()) { - errcode = read_string (addr, *length, width, - *length, byte_order, &buffer, - &bytes_read); + case TYPE_CODE_PTR: + case TYPE_CODE_ARRAY: + return TYPE_TARGET_TYPE (realtype); + default: + /* This is done to preserve existing behaviour. PR 20769. + E.g., gdb.parse_and_eval("my_int_variable").lazy_string().type. */ + return realtype; } - if (except.reason < 0) - { - PyErr_Format (except.reason == RETURN_QUIT \ - ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, \ - "%s", except.message); \ - goto error; +} - } +/* Extract the parameters from the lazy string object STRING. + ENCODING may be set to NULL, if no encoding is found. */ + +void +gdbpy_extract_lazy_string (PyObject *string, CORE_ADDR *addr, + struct type **str_elt_type, + long *length, + gdb::unique_xmalloc_ptr *encoding) +{ + lazy_string_object *lazy; + + gdb_assert (gdbpy_is_lazy_string (string)); + + lazy = (lazy_string_object *) string; - if (errcode) - goto error; - - *length = bytes_read / width; - - Py_DECREF (py_encoding); - Py_DECREF (py_len); - Py_DECREF (py_addr); - Py_DECREF (py_type); - return buffer; - - error: - Py_XDECREF (py_encoding); - Py_XDECREF (py_len); - Py_XDECREF (py_addr); - Py_XDECREF (py_type); - xfree (buffer); - *length = 0; - *str_type = NULL; - return NULL; + *addr = lazy->address; + *str_elt_type = stpy_lazy_string_elt_type (lazy); + *length = lazy->length; + encoding->reset (lazy->encoding ? xstrdup (lazy->encoding) : NULL); } @@ -256,7 +300,7 @@ static PyMethodDef lazy_string_object_methods[] = { }; -static PyGetSetDef lazy_string_object_getset[] = { +static gdb_PyGetSetDef lazy_string_object_getset[] = { { "address", stpy_get_address, NULL, "Address of the string.", NULL }, { "encoding", stpy_get_encoding, NULL, "Encoding of the string.", NULL }, { "length", stpy_get_length, NULL, "Length of the string.", NULL }, @@ -264,9 +308,8 @@ static PyGetSetDef lazy_string_object_getset[] = { { NULL } /* Sentinel */ }; -static PyTypeObject lazy_string_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ +PyTypeObject lazy_string_object_type = { + PyVarObject_HEAD_INIT (NULL, 0) "gdb.LazyString", /*tp_name*/ sizeof (lazy_string_object), /*tp_basicsize*/ 0, /*tp_itemsize*/