Handle variable-sized fields in the interior of structure type
authorJoel Brobecker <brobecker@adacore.com>
Tue, 8 Jul 2014 15:15:35 +0000 (08:15 -0700)
committerJoel Brobecker <brobecker@adacore.com>
Fri, 1 Aug 2014 14:44:27 +0000 (07:44 -0700)
In Ada, variable-sized field can be located at any position of
a structure. Consider for instance the following declarations:

   Dyn_Size : Integer := 1;

   type Table is array (Positive range <>) of Integer;

   type Inner is record
      T1 : Table (1 .. Dyn_Size) := (others => 1);
      T2 : Table (1 .. Dyn_Size) := (others => 2);
   end record;

   type Inner_Array is array (1 .. 2) of Inner;

   type Outer is
      record
         I0 : Integer := 0;
         A1 : Inner_Array;
         Marker : Integer := 16#01020304#;
      end record;

   Rt : Outer;

What this does is declare a variable "Rt" of type Outer, which
contains 3 fields where the second (A1) is of type Inner_Array.
type Inner_Array is an array with 2 elements of type Inner.
Because type Inner contains two arrays whose upper bound depend
on a variable, the size of the array, and therefore the size of
type Inner is dynamic, thus making field A1 a dynamically-size
field.

When trying to print the value of Rt, we hit the following limitation:

    (gdb) print rt
    Attempt to resolve a variably-sized type which appears in the interior of
    a structure type

The limitation was somewhat making sense in C, but needs to be lifted
for Ada. This patch mostly lifts that limitation. As a result of this
patch, the type length computation had to be reworked a little bit.

gdb/ChangeLog:

        * gdbtypes.c (resolve_dynamic_struct): Do not generate an error
        if detecting a variable-sized field that is not the last field.
        Fix struct type length computation.

gdb/testsuite/ChangeLog:

        * gdb.base/vla-datatypes.c (vla_factory): Add new variable
        inner_vla_struct_object_size.
        * gdb.base/vla-datatypes.exp: Adjust last test, and mark it
        as xfail.

gdb/ChangeLog
gdb/gdbtypes.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/vla-datatypes.c
gdb/testsuite/gdb.base/vla-datatypes.exp

index 2d50d35029149b47035ab447c2d21201176259e5..af340f805e787c1484a0edb65e812326815240ba 100644 (file)
@@ -1,3 +1,9 @@
+2014-08-01  Joel Brobecker  <brobecker@adacore.com>
+
+       * gdbtypes.c (resolve_dynamic_struct): Do not generate an error
+       if detecting a variable-sized field that is not the last field.
+       Fix struct type length computation.
+
 2014-08-01  Joel Brobecker  <brobecker@adacore.com>
 
        * amd64-windows-tdep.c (amd64_windows_frame_decode_insns):
index e99a2f352017497c201c1a198b54dc9582d908a4..97d94f24a360af915b9436c9ccdd85714691b04a 100644 (file)
@@ -1790,7 +1790,7 @@ resolve_dynamic_struct (struct type *type, CORE_ADDR addr)
 {
   struct type *resolved_type;
   int i;
-  int vla_field = TYPE_NFIELDS (type) - 1;
+  unsigned resolved_type_bit_length = 0;
 
   gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT);
   gdb_assert (TYPE_NFIELDS (type) > 0);
@@ -1804,37 +1804,45 @@ resolve_dynamic_struct (struct type *type, CORE_ADDR addr)
          TYPE_NFIELDS (resolved_type) * sizeof (struct field));
   for (i = 0; i < TYPE_NFIELDS (resolved_type); ++i)
     {
-      struct type *t;
+      unsigned new_bit_length;
 
       if (field_is_static (&TYPE_FIELD (type, i)))
        continue;
 
-      t = resolve_dynamic_type_internal (TYPE_FIELD_TYPE (resolved_type, i),
+      TYPE_FIELD_TYPE (resolved_type, i)
+       = resolve_dynamic_type_internal (TYPE_FIELD_TYPE (resolved_type, i),
                                         addr, 0);
 
-      /* 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;
+      /* As we know this field is not a static field, the field's
+        field_loc_kind should be FIELD_LOC_KIND_BITPOS.  Verify
+        this is the case, but only trigger a simple error rather
+        than an internal error if that fails.  While failing
+        that verification indicates a bug in our code, the error
+        is not severe enough to suggest to the user he stops
+        his debugging session because of it.  */
+      if (TYPE_FIELD_LOC_KIND (resolved_type, i) != FIELD_LOC_KIND_BITPOS)
+       error (_("Cannot determine struct field location"
+                " (invalid location kind)"));
+      new_bit_length = TYPE_FIELD_BITPOS (resolved_type, i);
+      if (TYPE_FIELD_BITSIZE (resolved_type, i) != 0)
+       new_bit_length += TYPE_FIELD_BITSIZE (resolved_type, i);
+      else
+       new_bit_length += (TYPE_LENGTH (TYPE_FIELD_TYPE (resolved_type, i))
+                          * TARGET_CHAR_BIT);
+
+      /* Normally, we would use the position and size of the last field
+        to determine the size of the enclosing structure.  But GCC seems
+        to be encoding the position of some fields incorrectly when
+        the struct contains a dynamic field that is not placed last.
+        So we compute the struct size based on the field that has
+        the highest position + size - probably the best we can do.  */
+      if (new_bit_length > resolved_type_bit_length)
+       resolved_type_bit_length = new_bit_length;
     }
 
-  /* 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)));
+    = (resolved_type_bit_length + TARGET_CHAR_BIT - 1) / TARGET_CHAR_BIT;
+
   return resolved_type;
 }
 
index 6eb8f3eb97a6d432d428d8c699323ed3979ad1af..eeeab3e89ab0d07dbd465f702f9dce36659f901e 100644 (file)
@@ -1,3 +1,10 @@
+2014-08-01  Joel Brobecker  <brobecker@adacore.com>
+
+       * gdb.base/vla-datatypes.c (vla_factory): Add new variable
+       inner_vla_struct_object_size.
+       * gdb.base/vla-datatypes.exp: Adjust last test, and mark it
+       as xfail.
+
 2014-07-30  Pedro Alves  <palves@redhat.com>
 
        * gdb.threads/signal-command-handle-nopass.exp (test): Add
index 1ef30a5ffa1196b22b99c0958c26e07ef09d17cf..41f3fd3be3848a64926a8e3ff563fa49bfe32266 100644 (file)
@@ -100,6 +100,7 @@ vla_factory (int n)
   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);
+  size_t inner_vla_struct_object_size = sizeof(inner_vla_struct_object);
 
   return;                                 /* break_end_of_vla_factory */
 }
index 0e56bd709aae8c74e2a0b71c92f67bef06af4221..15135a30fe878999265e82e104460a4b53993cf2 100644 (file)
@@ -152,6 +152,8 @@ 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"
+# Fails due to incorrect debugging information generated by GCC.
+setup_xfail "*-*-*"
+gdb_test \
+    "print inner_vla_struct_object_size == sizeof(inner_vla_struct_object)" \
+    " = 1" "size of inner_vla_struct_object"