handle VLA in a struct or union
authorTom Tromey <tromey@redhat.com>
Thu, 8 May 2014 17:26:44 +0000 (11:26 -0600)
committerTom Tromey <tromey@redhat.com>
Wed, 4 Jun 2014 20:28:22 +0000 (14:28 -0600)
It is valid in GNU C to have a VLA in a struct or union type, but gdb
did not handle this.

This patch adds support for these cases in the obvious way.

Built and regtested on x86-64 Fedora 20.
New tests included.

2014-06-04  Tom Tromey  <tromey@redhat.com>

* ada-lang.c (ada_template_to_fixed_record_type_1): Use
value_from_contents_and_address_unresolved.
(ada_template_to_fixed_record_type_1): Likewise.
(ada_which_variant_applies): Likewise.
* value.h (value_from_contents_and_address_unresolved): Declare.
* value.c (value_from_contents_and_address_unresolved): New
function.
* gdbtypes.c (is_dynamic_type, resolve_dynamic_type)
<TYPE_CODE_STRUCT, TYPE_CODE_UNION>: New cases.
(resolve_dynamic_struct, resolve_dynamic_union): New functions.

2014-06-04  Tom Tromey  <tromey@redhat.com>

* gdb.base/vla-datatypes.exp: Add tests for VLA-in-structure and
VLA-in-union.
* gdb.base/vla-datatypes.c (vla_factory): Add vla_struct,
inner_vla_struct, vla_union types.  Initialize objects of those
types and compute their sizes.

gdb/ChangeLog
gdb/ada-lang.c
gdb/gdbtypes.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/vla-datatypes.c
gdb/testsuite/gdb.base/vla-datatypes.exp
gdb/value.c
gdb/value.h

index ba04857..1803f81 100644 (file)
@@ -1,5 +1,18 @@
 2014-06-04  Tom Tromey  <tromey@redhat.com>
 
+       * ada-lang.c (ada_template_to_fixed_record_type_1): Use
+       value_from_contents_and_address_unresolved.
+       (ada_template_to_fixed_record_type_1): Likewise.
+       (ada_which_variant_applies): Likewise.
+       * value.h (value_from_contents_and_address_unresolved): Declare.
+       * value.c (value_from_contents_and_address_unresolved): New
+       function.
+       * gdbtypes.c (is_dynamic_type, resolve_dynamic_type)
+       <TYPE_CODE_STRUCT, TYPE_CODE_UNION>: New cases.
+       (resolve_dynamic_struct, resolve_dynamic_union): New functions.
+
+2014-06-04  Tom Tromey  <tromey@redhat.com>
+
        * gdbtypes.c (is_dynamic_type): Remove unneeded "break"s.
 
 2014-06-04  Tom Tromey  <tromey@redhat.com>
index 38972c6..c12fbb8 100644 (file)
@@ -7385,7 +7385,11 @@ ada_which_variant_applies (struct type *var_type, struct type *outer_type,
   struct value *discrim;
   LONGEST discrim_val;
 
-  outer = value_from_contents_and_address (outer_type, outer_valaddr, 0);
+  /* Using plain value_from_contents_and_address here causes problems
+     because we will end up trying to resolve a type that is currently
+     being constructed.  */
+  outer = value_from_contents_and_address_unresolved (outer_type,
+                                                     outer_valaddr, 0);
   discrim = ada_value_struct_elt (outer, discrim_name, 1);
   if (discrim == NULL)
     return -1;
@@ -7925,7 +7929,13 @@ ada_template_to_fixed_record_type_1 (struct type *type,
                 GDB may fail to allocate a value for it.  So check the
                 size first before creating the value.  */
              check_size (rtype);
-             dval = value_from_contents_and_address (rtype, valaddr, address);
+             /* Using plain value_from_contents_and_address here
+                causes problems because we will end up trying to
+                resolve a type that is currently being
+                constructed.  */
+             dval = value_from_contents_and_address_unresolved (rtype,
+                                                                valaddr,
+                                                                address);
              rtype = value_type (dval);
            }
           else
@@ -8030,7 +8040,11 @@ ada_template_to_fixed_record_type_1 (struct type *type,
 
       if (dval0 == NULL)
        {
-         dval = value_from_contents_and_address (rtype, valaddr, address);
+         /* Using plain value_from_contents_and_address here causes
+            problems because we will end up trying to resolve a type
+            that is currently being constructed.  */
+         dval = value_from_contents_and_address_unresolved (rtype, valaddr,
+                                                            address);
          rtype = value_type (dval);
        }
       else
index ba35883..bbb3fe9 100644 (file)
@@ -1636,6 +1636,18 @@ is_dynamic_type (struct type *type)
          return 1;
        return is_dynamic_type (TYPE_TARGET_TYPE (type));
       }
+
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+      {
+       int i;
+
+       for (i = 0; i < TYPE_NFIELDS (type); ++i)
+         if (!field_is_static (&TYPE_FIELD (type, i))
+             && is_dynamic_type (TYPE_FIELD_TYPE (type, i)))
+           return 1;
+      }
+      break;
     }
 
   return 0;
@@ -1717,6 +1729,97 @@ resolve_dynamic_array (struct type *type)
                            range_type);
 }
 
+/* Resolve dynamic bounds of members of the union TYPE to static
+   bounds.  */
+
+static struct type *
+resolve_dynamic_union (struct type *type, CORE_ADDR addr)
+{
+  struct type *resolved_type;
+  int i;
+  unsigned int max_len = 0;
+
+  gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION);
+
+  resolved_type = copy_type (type);
+  TYPE_FIELDS (resolved_type)
+    = TYPE_ALLOC (resolved_type,
+                 TYPE_NFIELDS (resolved_type) * sizeof (struct field));
+  memcpy (TYPE_FIELDS (resolved_type),
+         TYPE_FIELDS (type),
+         TYPE_NFIELDS (resolved_type) * sizeof (struct field));
+  for (i = 0; i < TYPE_NFIELDS (resolved_type); ++i)
+    {
+      struct type *t;
+
+      if (field_is_static (&TYPE_FIELD (type, i)))
+       continue;
+
+      t = resolve_dynamic_type (TYPE_FIELD_TYPE (resolved_type, i), addr);
+      TYPE_FIELD_TYPE (resolved_type, i) = t;
+      if (TYPE_LENGTH (t) > max_len)
+       max_len = TYPE_LENGTH (t);
+    }
+
+  TYPE_LENGTH (resolved_type) = max_len;
+  return resolved_type;
+}
+
+/* Resolve dynamic bounds of members of the struct TYPE to static
+   bounds.  */
+
+static struct type *
+resolve_dynamic_struct (struct type *type, CORE_ADDR addr)
+{
+  struct type *resolved_type;
+  int i;
+  int vla_field = TYPE_NFIELDS (type) - 1;
+
+  gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT);
+  gdb_assert (TYPE_NFIELDS (type) > 0);
+
+  resolved_type = copy_type (type);
+  TYPE_FIELDS (resolved_type)
+    = TYPE_ALLOC (resolved_type,
+                 TYPE_NFIELDS (resolved_type) * sizeof (struct field));
+  memcpy (TYPE_FIELDS (resolved_type),
+         TYPE_FIELDS (type),
+         TYPE_NFIELDS (resolved_type) * sizeof (struct field));
+  for (i = 0; i < TYPE_NFIELDS (resolved_type); ++i)
+    {
+      struct type *t;
+
+      if (field_is_static (&TYPE_FIELD (type, i)))
+       continue;
+
+      t = resolve_dynamic_type (TYPE_FIELD_TYPE (resolved_type, i), addr);
+
+      /* This is a bit odd.  We do not support a VLA in any position
+        of a struct except for the last.  GCC does have an extension
+        that allows a VLA in the middle of a structure, but the DWARF
+        it emits is relatively useless to us, so we can't represent
+        such a type properly -- and even if we could, we do not have
+        enough information to redo structure layout anyway.
+        Nevertheless, we check all the fields in case something odd
+        slips through, since it's better to see an error than
+        incorrect results.  */
+      if (t != TYPE_FIELD_TYPE (resolved_type, i)
+         && i != vla_field)
+       error (_("Attempt to resolve a variably-sized type which appears "
+                "in the interior of a structure type"));
+
+      TYPE_FIELD_TYPE (resolved_type, i) = t;
+    }
+
+  /* Due to the above restrictions we can successfully compute
+     the size of the resulting structure here, as the offset of
+     the final field plus its size.  */
+  TYPE_LENGTH (resolved_type)
+    = (TYPE_FIELD_BITPOS (resolved_type, vla_field) / TARGET_CHAR_BIT
+       + TYPE_LENGTH (TYPE_FIELD_TYPE (resolved_type, vla_field)));
+  return resolved_type;
+}
+
 /* See gdbtypes.h  */
 
 struct type *
@@ -1753,6 +1856,14 @@ resolve_dynamic_type (struct type *type, CORE_ADDR addr)
       case TYPE_CODE_RANGE:
        resolved_type = resolve_dynamic_range (type);
        break;
+
+    case TYPE_CODE_UNION:
+      resolved_type = resolve_dynamic_union (type, addr);
+      break;
+
+    case TYPE_CODE_STRUCT:
+      resolved_type = resolve_dynamic_struct (type, addr);
+      break;
     }
 
   return resolved_type;
index 2720d70..3bc33b4 100644 (file)
@@ -1,3 +1,11 @@
+2014-06-04  Tom Tromey  <tromey@redhat.com>
+
+       * gdb.base/vla-datatypes.exp: Add tests for VLA-in-structure and
+       VLA-in-union.
+       * gdb.base/vla-datatypes.c (vla_factory): Add vla_struct,
+       inner_vla_struct, vla_union types.  Initialize objects of those
+       types and compute their sizes.
+
 2014-06-04  Nathan Sidwell  <nathan@codesourcery.com>
            Hui Zhu  <hui@codesourcery.com>
 
index 51e342e..1ef30a5 100644 (file)
@@ -46,6 +46,27 @@ vla_factory (int n)
   BAR             bar_vla[n];
   int i;
 
+  struct vla_struct
+  {
+    int something;
+    int vla_field[n];
+  } vla_struct_object;
+
+  struct inner_vla_struct
+  {
+    int something;
+    int vla_field[n];
+    int after;
+  } inner_vla_struct_object;
+
+  union vla_union
+  {
+    int vla_field[n];
+  } vla_union_object;
+
+  vla_struct_object.something = n;
+  inner_vla_struct_object.something = n;
+  inner_vla_struct_object.after = n;
   for (i = 0; i < n; i++)
     {
       int_vla[i] = i*2;
@@ -61,6 +82,9 @@ vla_factory (int n)
       foo_vla[i].a = i*2;
       bar_vla[i].x = i*2;
       bar_vla[i].y.a = i*2;
+      vla_struct_object.vla_field[i] = i*2;
+      vla_union_object.vla_field[i] = i*2;
+      inner_vla_struct_object.vla_field[i] = i*2;
     }
 
   size_t int_size        = sizeof(int_vla);     /* vlas_filled */
@@ -74,6 +98,8 @@ vla_factory (int n)
   size_t uchar_size      = sizeof(unsigned_char_vla);
   size_t foo_size        = sizeof(foo_vla);
   size_t bar_size        = sizeof(bar_vla);
+  size_t vla_struct_object_size = sizeof(vla_struct_object);
+  size_t vla_union_object_size = sizeof(vla_union_object);
 
   return;                                 /* break_end_of_vla_factory */
 }
index 8247658..0e56bd7 100644 (file)
@@ -53,6 +53,10 @@ gdb_test "print foo_vla" \
 gdb_test "print bar_vla" \
          "\\\{\\\{x = 0, y = \\\{a = 0\\\}\\\}, \\\{x = 2, y = \\\{a = 2\\\}\\\}, \\\{x = 4, y = \\\{a = 4\\\}\\\}, \\\{x = 6, y = \\\{a = 6\\\}\\\}, \\\{x = 8, y = \\\{a = 8\\\}\\\}\\\}" \
          "print bar_vla"
+gdb_test "print vla_struct_object" \
+    "\\\{something = 5, vla_field = \\\{0, 2, 4, 6, 8\\\}\\\}"
+gdb_test "print vla_union_object" \
+    "\\\{vla_field = \\\{0, 2, 4, 6, 8\\\}\\\}"
 
 # Check whatis of VLA's.
 gdb_test "whatis int_vla" "type = int \\\[5\\\]" "whatis int_vla"
@@ -74,6 +78,8 @@ gdb_test "whatis unsigned_char_vla" "type = unsigned char \\\[5\\\]" \
          "whatis unsigned_char_vla"
 gdb_test "whatis foo_vla" "type = struct foo \\\[5\\\]" "whatis foo_vla"
 gdb_test "whatis bar_vla" "type = BAR \\\[5\\\]" "whatis bar_vla"
+gdb_test "whatis vla_struct_object" "type = struct vla_struct"
+gdb_test "whatis vla_union_object" "type = union vla_union"
 
 # Check ptype of VLA's.
 gdb_test "ptype int_vla" "type = int \\\[5\\\]" "ptype int_vla"
@@ -96,6 +102,10 @@ gdb_test "ptype foo_vla" "type = struct foo {\r\n\\s+int a;\r\n} \\\[5\\\]" \
 gdb_test "ptype bar_vla" \
          "type = struct bar {\r\n\\s+int x;\r\n\\s+struct foo y;\r\n} \\\[5\\\]" \
          "ptype bar_vla"
+gdb_test "ptype vla_struct_object" \
+    "type = struct vla_struct {\r\n\\s+int something;\r\n\\s+int vla_field\\\[5\\\];\r\n}"
+gdb_test "ptype vla_union_object" \
+    "type = union vla_union {\r\n\\s+int vla_field\\\[5\\\];\r\n}"
 
 # Check the size of the VLA's.
 gdb_breakpoint [gdb_get_line_number "break_end_of_vla_factory"]
@@ -119,6 +129,10 @@ gdb_test "print uchar_size == sizeof(unsigned_char_vla)" " = 1" \
          "size of unsigned_char_vla"
 gdb_test "print foo_size == sizeof(foo_vla)" " = 1" "size of foo_vla"
 gdb_test "print bar_size == sizeof(bar_vla)" " = 1" "size of bar_vla"
+gdb_test "print vla_struct_object_size == sizeof(vla_struct_object)" \
+    " = 1" "size of vla_struct_object"
+gdb_test "print vla_union_object_size == sizeof(vla_union_object)" \
+    " = 1" "size of vla_union_object"
 
 # Check side effects for sizeof argument.
 set sizeof_int [get_sizeof "int" 4]
@@ -137,3 +151,7 @@ gdb_test "print int_vla\[0\]" " = 42" \
 gdb_test "whatis ++int_vla\[0\]" "type = int" "whatis ++int_vla\[0\]"
 gdb_test "print int_vla\[0\]" " = 42" \
          "print int_vla\[0\] - whatis no side effects"
+
+# This gives an error for now.
+gdb_test "print sizeof(inner_vla_struct_object)" \
+    "appears in the interior of a structure type"
index 1cdb109..557056f 100644 (file)
@@ -3379,6 +3379,29 @@ value_from_pointer (struct type *type, CORE_ADDR addr)
 /* Create a value of type TYPE whose contents come from VALADDR, if it
    is non-null, and whose memory address (in the inferior) is
    ADDRESS.  The type of the created value may differ from the passed
+   type TYPE.  Make sure to retrieve values new type after this call.
+   Note that TYPE is not passed through resolve_dynamic_type; this is
+   a special API intended for use only by Ada.  */
+
+struct value *
+value_from_contents_and_address_unresolved (struct type *type,
+                                           const gdb_byte *valaddr,
+                                           CORE_ADDR address)
+{
+  struct value *v;
+
+  if (valaddr == NULL)
+    v = allocate_value_lazy (type);
+  else
+    v = value_from_contents (type, valaddr);
+  set_value_address (v, address);
+  VALUE_LVAL (v) = lval_memory;
+  return v;
+}
+
+/* Create a value of type TYPE whose contents come from VALADDR, if it
+   is non-null, and whose memory address (in the inferior) is
+   ADDRESS.  The type of the created value may differ from the passed
    type TYPE.  Make sure to retrieve values new type after this call.  */
 
 struct value *
index 65fd203..c2e9faf 100644 (file)
@@ -575,6 +575,8 @@ extern struct value *value_from_history_ref (char *, char **);
 extern struct value *value_at (struct type *type, CORE_ADDR addr);
 extern struct value *value_at_lazy (struct type *type, CORE_ADDR addr);
 
+extern struct value *value_from_contents_and_address_unresolved
+     (struct type *, const gdb_byte *, CORE_ADDR);
 extern struct value *value_from_contents_and_address (struct type *,
                                                      const gdb_byte *,
                                                      CORE_ADDR);