summaryrefslogtreecommitdiff
path: root/gdb/python
diff options
context:
space:
mode:
authorDoug Evans <dje@google.com>2017-03-15 15:35:13 -0700
committerDoug Evans <dje@google.com>2017-03-16 09:28:11 -0700
commit34b433203b5f56149c27a8dfea21a921392cb158 (patch)
treec45039a326c7863be84bcbe3e552b2a28ee209ae /gdb/python
parenta3a5feccd26be653efbdf1408874b98962baaa50 (diff)
downloadbinutils-gdb-34b433203b5f56149c27a8dfea21a921392cb158.tar.gz
Fix various python lazy string bugs.
gdb/ChangeLog: PR python/17728, python/18439, python/18779 * python/py-lazy-string.c (lazy_string_object): Clarify use of LENGTH member. Change type of TYPE member to PyObject *. All uses updated. (stpy_convert_to_value): Fix handling of TYPE_CODE_PTR. (gdbpy_create_lazy_string_object): Flag bad length values. Handle TYPE_CODE_ARRAY with possibly different user-provided length. Handle typedefs in incoming type. (stpy_lazy_string_elt_type): New function. (gdbpy_extract_lazy_string): Call it. * python/py-value.c (valpy_lazy_string): Flag bad length values. Fix handling of TYPE_CODE_PTR. Handle TYPE_CODE_ARRAY. Handle typedefs in incoming type. gdb/testsuite/ChangeLog: PR python/17728, python/18439, python/18779 * gdb.python/py-value.c (main) Delete locals sptr, sn. * gdb.python/py-lazy-string.c (pointer): New typedef. (main): New locals ptr, array, typedef_ptr. * gdb.python/py-value.exp: Move lazy string tests to ... * gdb.python/py-lazy-string.exp: ... here. Add more tests for pointer, array, typedef lazy strings.
Diffstat (limited to 'gdb/python')
-rw-r--r--gdb/python/py-lazy-string.c117
-rw-r--r--gdb/python/py-value.c76
2 files changed, 172 insertions, 21 deletions
diff --git a/gdb/python/py-lazy-string.c b/gdb/python/py-lazy-string.c
index 4af4566ef64..ab3f4117439 100644
--- a/gdb/python/py-lazy-string.c
+++ b/gdb/python/py-lazy-string.c
@@ -26,6 +26,7 @@
typedef struct {
PyObject_HEAD
+
/* Holds the address of the lazy string. */
CORE_ADDR address;
@@ -35,14 +36,21 @@ 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;
+ /* 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;
} lazy_string_object;
extern PyTypeObject lazy_string_object_type
@@ -88,11 +96,12 @@ 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 = NULL;
@@ -106,7 +115,32 @@ stpy_convert_to_value (PyObject *self, PyObject *args)
TRY
{
- val = value_at_lazy (self_string->type, self_string->address);
+ struct type *type = type_object_to_type (self_string->type);
+ struct type *realtype;
+
+ gdb_assert (type != NULL);
+ realtype = check_typedef (type);
+ switch (TYPE_CODE (realtype))
+ {
+ 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 (except, RETURN_MASK_ALL)
{
@@ -125,11 +159,24 @@ stpy_dealloc (PyObject *self)
xfree (self_string->encoding);
}
+/* Low level routine to create a <gdb.LazyString> 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)
{
@@ -146,6 +193,27 @@ gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
return NULL;
}
+ realtype = check_typedef (type);
+ switch (TYPE_CODE (realtype))
+ {
+ 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;
@@ -156,7 +224,7 @@ 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;
}
@@ -179,12 +247,35 @@ gdbpy_is_lazy_string (PyObject *result)
return PyObject_TypeCheck (result, &lazy_string_object_type);
}
+/* Return the type of a character in lazy string LAZY. */
+
+static struct type *
+stpy_lazy_string_elt_type (lazy_string_object *lazy)
+{
+ struct type *type = type_object_to_type (lazy->type);
+ struct type *realtype;
+
+ gdb_assert (type != NULL);
+ realtype = check_typedef (type);
+
+ switch (TYPE_CODE (realtype))
+ {
+ 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;
+ }
+}
+
/* 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_type,
+ struct type **str_elt_type,
long *length,
gdb::unique_xmalloc_ptr<char> *encoding)
{
@@ -195,7 +286,7 @@ gdbpy_extract_lazy_string (PyObject *string, CORE_ADDR *addr,
lazy = (lazy_string_object *) string;
*addr = lazy->address;
- *str_type = lazy->type;
+ *str_elt_type = stpy_lazy_string_elt_type (lazy);
*length = lazy->length;
encoding->reset (lazy->encoding ? xstrdup (lazy->encoding) : NULL);
}
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
index eb3d307b19b..124d3980139 100644
--- a/gdb/python/py-value.c
+++ b/gdb/python/py-value.c
@@ -400,9 +400,19 @@ valpy_get_dynamic_type (PyObject *self, void *closure)
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 length will be set to -1 (first
- null of appropriate with). */
+ 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)
{
@@ -416,16 +426,66 @@ valpy_lazy_string (PyObject *self, PyObject *args, PyObject *kw)
&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;
- if (TYPE_CODE (value_type (value)) == TYPE_CODE_PTR)
- value = value_ind (value);
+ type = value_type (value);
+ realtype = check_typedef (type);
+
+ switch (TYPE_CODE (realtype))
+ {
+ 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 (TYPE_TARGET_TYPE (realtype),
+ 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 (TYPE_TARGET_TYPE (realtype),
+ 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 (value_address (value), length,
- user_encoding,
- value_type (value));
+ str_obj = gdbpy_create_lazy_string_object (addr, length, user_encoding,
+ type);
}
CATCH (except, RETURN_MASK_ALL)
{