mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 12:03:41 +08:00
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.
This commit is contained in:
parent
a3a5feccd2
commit
34b433203b
@ -1,3 +1,18 @@
|
||||
2017-03-16 Doug Evans <dje@google.com>
|
||||
|
||||
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.
|
||||
|
||||
2017-03-16 Doug Evans <dje@google.com>
|
||||
|
||||
* guile/guile-internal.h (tyscm_scm_to_type): Declare.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
str_obj = gdbpy_create_lazy_string_object (value_address (value), length,
|
||||
user_encoding,
|
||||
value_type (value));
|
||||
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 (addr, length, user_encoding,
|
||||
type);
|
||||
}
|
||||
CATCH (except, RETURN_MASK_ALL)
|
||||
{
|
||||
|
@ -1,7 +1,19 @@
|
||||
<<<<<<< HEAD
|
||||
2017-03-16 Thomas Preud'homme <thomas.preudhomme@arm.com>
|
||||
|
||||
* gdb.cp/m-static.exp: Fix expectation for prototype of
|
||||
test5.single_constructor and single_constructor::single_constructor.
|
||||
=======
|
||||
2017-03-15 Doug Evans <dje@google.com>
|
||||
|
||||
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.
|
||||
>>>>>>> Fix various python lazy string bugs.
|
||||
|
||||
2017-03-14 Anton Kolesov <anton.kolesov@synopsys.com>
|
||||
|
||||
|
@ -18,6 +18,9 @@
|
||||
int
|
||||
main ()
|
||||
{
|
||||
const char *ptr = "pointer";
|
||||
const char array[] = "array";
|
||||
pointer typedef_ptr = "typedef pointer";
|
||||
const char *null = 0;
|
||||
|
||||
return 0; /* break here */
|
||||
|
@ -34,9 +34,43 @@ if ![runto_main ] {
|
||||
gdb_breakpoint [gdb_get_line_number "break here"]
|
||||
gdb_continue_to_breakpoint "break here"
|
||||
|
||||
gdb_test_no_output "python null = gdb.parse_and_eval(\"null\")"
|
||||
gdb_py_test_silent_cmd "python null = gdb.parse_and_eval(\"null\")" "get null value" 1
|
||||
|
||||
gdb_test "python print(null.lazy_string(length=0).value())" \
|
||||
"gdb.MemoryError: Cannot create a value from NULL.*Error while executing Python code."
|
||||
gdb_py_test_silent_cmd "python nullstr = null.lazy_string(length=0)" "create a null lazy string" 1
|
||||
gdb_test "python print (nullstr.length)" "0" "null lazy string length"
|
||||
gdb_test "python print (nullstr.address)" "0" "null lazy string address"
|
||||
gdb_test "python print (nullstr.type)" "const char \\*" "null lazy string type"
|
||||
gdb_test "python print(nullstr.value())" \
|
||||
"gdb.MemoryError: Cannot create a value from NULL.*Error while executing Python code." \
|
||||
"create value from NULL"
|
||||
gdb_test "python print(null.lazy_string(length=3).value())" \
|
||||
"gdb.MemoryError: Cannot create a lazy string with address 0x0, and a non-zero length.*Error while executing Python code."
|
||||
"gdb.MemoryError: Cannot create a lazy string with address 0x0, and a non-zero length.*Error while executing Python code." \
|
||||
"null lazy string with non-zero length"
|
||||
gdb_test "python print(null.lazy_string(length=-2))" \
|
||||
"ValueError: Invalid length.*Error while executing Python code." \
|
||||
"bad length"
|
||||
|
||||
foreach var_spec { { "ptr" "pointer" "const char \\*" -1 } \
|
||||
{ "array" "array" "const char \\[6\\]" 6 } \
|
||||
{ "typedef_ptr" "typedef pointer" "pointer" -1 } } {
|
||||
set var [lindex $var_spec 0]
|
||||
set value [lindex $var_spec 1]
|
||||
set type [lindex $var_spec 2]
|
||||
set length [lindex $var_spec 3]
|
||||
with_test_prefix $var {
|
||||
gdb_test "print $var" "\"$value\""
|
||||
gdb_py_test_silent_cmd "python $var = gdb.history (0)" "get value from history" 1
|
||||
gdb_py_test_silent_cmd "python l$var = $var.lazy_string()" "acquire lazy string" 1
|
||||
gdb_test "python print ($var.type)" "$type" "string type name equality"
|
||||
gdb_test "python print (l$var.type)" "$type" "lazy-string type name equality"
|
||||
gdb_test "python print (l$var.length)" "$length" "lazy string length"
|
||||
gdb_test "python print (l$var.value())" "\"$value\"" "lazy string value"
|
||||
gdb_py_test_silent_cmd "python l2$var = $var.lazy_string(length=2)" "acquire lazy string, length 2" 1
|
||||
gdb_test "python print (l2$var.length)" "2" "lazy string length 2"
|
||||
gdb_test "python print (l2$var.value())" "\"[string range $value 0 1]\"" "lazy string length 2 value"
|
||||
# This test will have to wait until gdb can handle it. There's no way,
|
||||
# currently, to internally specify an array of length zero in the C
|
||||
# language support. PR 20786
|
||||
#gdb_test "python print ($var.lazy_string(length=0).value())" "\"\"" "empty lazy string value"
|
||||
}
|
||||
}
|
||||
|
@ -90,13 +90,11 @@ main (int argc, char *argv[])
|
||||
char nullst[17] = "divide\0et\0impera";
|
||||
void (*fp1) (void) = &func1;
|
||||
int (*fp2) (int, int) = &func2;
|
||||
const char *sptr = "pointer";
|
||||
const char *embed = "embedded x\201\202\203\204";
|
||||
int a[3] = {1,2,3};
|
||||
int *p = a;
|
||||
int i = 2;
|
||||
int *ptr_i = &i;
|
||||
const char *sn = 0;
|
||||
struct str *xstr;
|
||||
|
||||
/* Prevent gcc from optimizing argv[] out. */
|
||||
|
@ -317,29 +317,6 @@ proc test_value_in_inferior {} {
|
||||
"read string beyond declared size"
|
||||
}
|
||||
|
||||
proc test_lazy_strings {} {
|
||||
|
||||
global hex
|
||||
|
||||
gdb_test "print sptr" "\"pointer\""
|
||||
gdb_py_test_silent_cmd "python sptr = gdb.history (0)" "Get value from history" 1
|
||||
|
||||
gdb_py_test_silent_cmd "python lstr = sptr.lazy_string()" "Aquire lazy string" 1
|
||||
gdb_test "python print (lstr.type)" "const char \*." "test lazy-string type name equality"
|
||||
gdb_test "python print (sptr.type)" "const char \*." "test string type name equality"
|
||||
|
||||
# Prevent symbol on address 0x0 being printed.
|
||||
gdb_test_no_output "set print symbol off"
|
||||
gdb_test "print sn" "0x0"
|
||||
|
||||
gdb_py_test_silent_cmd "python snptr = gdb.history (0)" "Get value from history" 1
|
||||
gdb_test "python snstr = snptr.lazy_string(length=5)" ".*Cannot create a lazy string with address.*" "test lazy string"
|
||||
gdb_py_test_silent_cmd "python snstr = snptr.lazy_string(length=0)" "Succesfully create a lazy string" 1
|
||||
gdb_test "python print (snstr.length)" "0" "test lazy string length"
|
||||
gdb_test "python print (snstr.address)" "0" "test lazy string address"
|
||||
}
|
||||
|
||||
|
||||
proc test_inferior_function_call {} {
|
||||
global gdb_prompt hex decimal
|
||||
|
||||
@ -534,7 +511,6 @@ if ![runto_main] then {
|
||||
|
||||
test_value_in_inferior
|
||||
test_inferior_function_call
|
||||
test_lazy_strings
|
||||
test_value_after_death
|
||||
|
||||
# Test either C or C++ values.
|
||||
|
Loading…
Reference in New Issue
Block a user