Re: RFC: fix `gdb -write' case

Tom Tromey
2011-05-11T19:42:15Z

>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:

Jan> In that Bug I made a comment
Jan> # evaluate_subexp_c->OP_STRING ignores expect_type, GDB then tries to convert
Jan> # the non-matching type using malloc.
Jan> which I advocate below.

Jan> I believe if GDB adjusts the short/long types shouldn't it adjust also
Jan> char/whar_t types? That is now the user must know the type of string in
Jan> advance which wasn't the case for arrays before.

Ok, I understand now.

What do you think of this? It uses the expected type to construct the
array's values when it makes sense.

This version adds a test case for this too.

Tom

2011-05-11 Tom Tromey <tromey@redhat.com>

* c-lang.c (evaluate_subexp_c): Use expect_type if it is not
NULL.

2011-05-11 Tom Tromey <tromey@redhat.com>

* gdb.base/charset.exp (string_display): Add tests to assign to
arrays.
* gdb.base/charset.c (short_array, int_array, long_array): New.

diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index ad770bf..255fabe 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -978,6 +978,7 @@ evaluate_subexp_c (struct type *expect_type, struct expression *exp,
struct value *result;
enum c_string_type dest_type;
const char *dest_charset;
+ int satisfy_expected = 0;

obstack_init (&output);
cleanup = make_cleanup_obstack_free (&output);
@@ -1014,6 +1015,22 @@ evaluate_subexp_c (struct type *expect_type, struct expression *exp,
/* Ensure TYPE_LENGTH is valid for TYPE. */
check_typedef (type);

+ /* If the caller expects an array of some integral type,
+ satisfy them. If something odder is expected, rely on the
+ caller to cast. */
+ if (expect_type && TYPE_CODE (expect_type) == TYPE_CODE_ARRAY)
+ {
+ struct type *element_type
+ = check_typedef (TYPE_TARGET_TYPE (expect_type));
+
+ if (TYPE_CODE (element_type) == TYPE_CODE_INT
+ || TYPE_CODE (element_type) == TYPE_CODE_CHAR)
+ {
+ type = element_type;
+ satisfy_expected = 1;
+ }
+ }
+
dest_charset = charset_for_string_type (dest_type, exp->gdbarch);

++*pos;
@@ -1036,7 +1053,9 @@ evaluate_subexp_c (struct type *expect_type, struct expression *exp,
if (noside == EVAL_SKIP)
{
/* Return a dummy value of the appropriate type. */
- if ((dest_type & C_CHAR) != 0)
+ if (expect_type != NULL)
+ result = allocate_value (expect_type);
+ else if ((dest_type & C_CHAR) != 0)
result = allocate_value (type);
else
result = value_cstring ("", 0, type);
@@ -1061,9 +1080,30 @@ evaluate_subexp_c (struct type *expect_type, struct expression *exp,
/* Write the terminating character. */
for (i = 0; i < TYPE_LENGTH (type); ++i)
obstack_1grow (&output, 0);
- result = value_cstring (obstack_base (&output),
- obstack_object_size (&output),
- type);
+
+ if (satisfy_expected)
+ {
+ LONGEST low_bound, high_bound;
+ int element_size = TYPE_LENGTH (type);
+
+ if (get_discrete_bounds (TYPE_INDEX_TYPE (expect_type),
+ &low_bound, &high_bound) < 0)
+ {
+ low_bound = 0;
+ high_bound = (TYPE_LENGTH (expect_type) / element_size) - 1;
+ }
+ if (obstack_object_size (&output) / element_size
+ > (high_bound - low_bound + 1))
+ error (_("Too many array elements"));
+
+ result = allocate_value (expect_type);
+ memcpy (value_contents_raw (result), obstack_base (&output),
+ obstack_object_size (&output));
+ }
+ else
+ result = value_cstring (obstack_base (&output),
+ obstack_object_size (&output),
+ type);
}
do_cleanups (cleanup);
return result;
diff --git a/gdb/testsuite/gdb.base/charset.c b/gdb/testsuite/gdb.base/charset.c
index 644fe47..df56c45 100644
--- a/gdb/testsuite/gdb.base/charset.c
+++ b/gdb/testsuite/gdb.base/charset.c
@@ -73,6 +73,11 @@ char32_t *String32;
typedef wchar_t my_wchar_t;
my_wchar_t myvar;

+/* Some arrays for simple assignment tests. */
+short short_array[3];
+int int_array[3];
+long long_array[3];
+
void
init_string (char string[],
char x,
diff --git a/gdb/testsuite/gdb.base/charset.exp b/gdb/testsuite/gdb.base/charset.exp
index 4e4cf09..b558bb2 100644
--- a/gdb/testsuite/gdb.base/charset.exp
+++ b/gdb/testsuite/gdb.base/charset.exp
@@ -617,4 +617,13 @@ if {$wchar_size == 4} {
}

+foreach name {short int long} {
+ # We're really just checking to make sure this doesn't give an
+ # error.
+ gdb_test "print ${name}_array = \"hi\"" \
+ " = {.*}" \
+ "assign string to $name array"
+}
+
+
gdb_exit