Fix decoding of multi-dimensional constrained packed arrays
authorTom Tromey <tromey@adacore.com>
Wed, 4 Nov 2020 15:49:16 +0000 (08:49 -0700)
committerTom Tromey <tromey@adacore.com>
Wed, 4 Nov 2020 15:49:17 +0000 (08:49 -0700)
Printing a multi-dimensional constrained packed array in Ada would not
show the correct values.  The bug here is that, when decoding the type
of such an array, only the innermost dimension's element bitsize would
be correct.  For outer dimensions, the bitsize must account for the
size of each sub-array, but this was not done.

This patch fixes the problem by arranging to compute these sizes after
decoding the array type.  I've included a bit more test case than is
strictly necessary -- the current test here was derived from an
internal test, and this patch brings the two into sync.

gdb/ChangeLog
2020-11-04  Tom Tromey  <tromey@adacore.com>

* ada-lang.c (recursively_update_array_bitsize): New function.
(decode_constrained_packed_array_type): Call it.

gdb/testsuite/ChangeLog
2020-11-04  Tom Tromey  <tromey@adacore.com>

* gdb.ada/enum_idx_packed.exp: Add tests.
* gdb.ada/enum_idx_packed/foo.adb: Add variables.
* gdb.ada/enum_idx_packed/pck.adb: Add functions.
* gdb.ada/enum_idx_packed/pck.ads: Add types, function
declarations.

gdb/ChangeLog
gdb/ada-lang.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.ada/enum_idx_packed.exp
gdb/testsuite/gdb.ada/enum_idx_packed/foo.adb
gdb/testsuite/gdb.ada/enum_idx_packed/pck.adb
gdb/testsuite/gdb.ada/enum_idx_packed/pck.ads

index 9b905ee091bf0b4bc4119b2fa138ba2e8742e947..27950c390e4a8b6398962ae45cecaddb293790a4 100644 (file)
@@ -1,3 +1,8 @@
+2020-11-04  Tom Tromey  <tromey@adacore.com>
+
+       * ada-lang.c (recursively_update_array_bitsize): New function.
+       (decode_constrained_packed_array_type): Call it.
+
 2020-11-04  Tom Tromey  <tromey@adacore.com>
 
        * ada-lang.c (to_fixed_array_type): Error if
index 941b35f60815344f189b4b91603c23e24191b302..93d8225ad2d39bd1981638b88f75463e3b4eb2d2 100644 (file)
@@ -2139,6 +2139,35 @@ decode_constrained_packed_array_type (struct type *type)
   return constrained_packed_array_type (shadow_type, &bits);
 }
 
+/* Helper function for decode_constrained_packed_array.  Set the field
+   bitsize on a series of packed arrays.  Returns the number of
+   elements in TYPE.  */
+
+static LONGEST
+recursively_update_array_bitsize (struct type *type)
+{
+  gdb_assert (type->code () == TYPE_CODE_ARRAY);
+
+  LONGEST low, high;
+  if (get_discrete_bounds (type->index_type (), &low, &high) < 0
+      || low > high)
+    return 0;
+  LONGEST our_len = high - low + 1;
+
+  struct type *elt_type = TYPE_TARGET_TYPE (type);
+  if (elt_type->code () == TYPE_CODE_ARRAY)
+    {
+      LONGEST elt_len = recursively_update_array_bitsize (elt_type);
+      LONGEST elt_bitsize = elt_len * TYPE_FIELD_BITSIZE (elt_type, 0);
+      TYPE_FIELD_BITSIZE (type, 0) = elt_bitsize;
+
+      TYPE_LENGTH (type) = ((our_len * elt_bitsize + HOST_CHAR_BIT - 1)
+                           / HOST_CHAR_BIT);
+    }
+
+  return our_len;
+}
+
 /* Given that ARR is a struct value *indicating a GNAT constrained packed
    array, returns a simple array that denotes that array.  Its type is a
    standard GDB array type except that the BITSIZEs of the array
@@ -2168,6 +2197,18 @@ decode_constrained_packed_array (struct value *arr)
       return NULL;
     }
 
+  /* Decoding the packed array type could not correctly set the field
+     bitsizes for any dimension except the innermost, because the
+     bounds may be variable and were not passed to that function.  So,
+     we further resolve the array bounds here and then update the
+     sizes.  */
+  const gdb_byte *valaddr = value_contents_for_printing (arr);
+  CORE_ADDR address = value_address (arr);
+  gdb::array_view<const gdb_byte> view
+    = gdb::make_array_view (valaddr, TYPE_LENGTH (type));
+  type = resolve_dynamic_type (type, view, address);
+  recursively_update_array_bitsize (type);
+
   if (type_byte_order (value_type (arr)) == BFD_ENDIAN_BIG
       && ada_is_modular_type (value_type (arr)))
     {
index 0659c246f34d3f6cd9f8a54d8c2c275d110a7023..e9d5a23a1ed5f2ddc234d872404820c7a93ec8b6 100644 (file)
@@ -1,3 +1,11 @@
+2020-11-04  Tom Tromey  <tromey@adacore.com>
+
+       * gdb.ada/enum_idx_packed.exp: Add tests.
+       * gdb.ada/enum_idx_packed/foo.adb: Add variables.
+       * gdb.ada/enum_idx_packed/pck.adb: Add functions.
+       * gdb.ada/enum_idx_packed/pck.ads: Add types, function
+       declarations.
+
 2020-11-03  Tom de Vries  <tdevries@suse.de>
 
        * lib/dwarf.exp (Dwarf::_handle_DW_TAG): Improve attribute list
index bfa091ec9a6c66d974c9541fc10e84eda31bd246..480de71b7c4675fb0eb74815a2e1d4a9d6925344 100644 (file)
@@ -28,7 +28,55 @@ clean_restart ${testfile}
 set bp_location [gdb_get_line_number "STOP" ${testdir}/foo.adb]
 runto "foo.adb:$bp_location"
 
+gdb_test "ptype full" \
+    "type = array \\(black \\.\\. white\\) of boolean <packed: 1-bit elements>"
+
 gdb_test "print full" " = \\(false, true, false, true, false\\)"
 
 gdb_test "print full'first" " = black"
 
+gdb_test "ptype primary" \
+    "type = array \\(red \\.\\. blue\\) of boolean <packed: 1-bit elements>"
+
+gdb_test "print primary" " = \\(red => false, true, false\\)"
+
+gdb_test "print primary'first" " = red"
+
+gdb_test "ptype cold" \
+    "type = array \\(green \\.\\. blue\\) of boolean <packed: 1-bit elements>"
+
+gdb_test "print cold" " = \\(green => false, true\\)"
+
+gdb_test "print cold'first" " = green"
+
+# Note the bounds values are still not correctly displayed.  So we get
+# the enum equivalent of "1 .. 0" (empty range) as the array ranges.
+# Accept that for now.
+gdb_test "ptype small" \
+    "array \\(red \\.\\. green\\) of boolean <packed: 1-bit elements>"
+
+gdb_test "print small" " = \\(red => false, true\\)"
+
+gdb_test "print small'first" " = red"
+
+gdb_test "ptype multi" \
+    "array \\(red \\.\\. green, low .. medium\\) of boolean <packed: 1-bit elements>"
+
+gdb_test "print multi" \
+    " = \\(red => \\(low => true, false\\), \\(low => true, false\\)\\)"
+
+gdb_test "print multi'first" " = red"
+
+set base "\\(true, false, true, false, true, false, true, false, true, false\\)"
+set matrix "\\("
+foreach x {1 2 3 4 5 6 7} {
+    if {$x > 1} {
+       append matrix ", "
+    }
+    append matrix $base
+}
+append matrix "\\)"
+
+gdb_test "print multi_multi" " = \\($matrix, $matrix\\)"
+gdb_test "print multi_multi(1,3)" " = $base"
+gdb_test "print multi_multi(2)" " = $matrix"
index 6f142a18b0064ae919664e5c67ae1b6f96edc631..e9f30747167627004655ffbe0fd86f3436dfd68b 100644 (file)
@@ -17,8 +17,16 @@ with Pck; use Pck;
 
 procedure Foo is
    Full : Full_Table := (False, True, False, True, False);
+   Primary : Primary_Table := (False, True, False);
+   Cold : Cold_Table := (False, True);
+   Small : Small_Table := New_Small_Table (Low => Red, High => Green);
+   Multi : Multi_Table := New_Multi_Table (Red, Green, Low, Medium);
+   Multi_Multi : Multi_Multi_Table := New_Multi_Multi_Table (1, 2, 1, 7, 1, 10);
 begin
    Do_Nothing (Full'Address);  -- STOP
+   Do_Nothing (Primary'Address);
+   Do_Nothing (Cold'Address);
+   Do_Nothing (Small'Address);
+   Do_Nothing (Multi'Address);
+   Do_Nothing (Multi_Multi'Address);
 end Foo;
-
-
index 5b18de9952b7129d38cd243d7a84d165a1631e54..a4e04747526eed42e2417f1a03838ac18b1a4845 100644 (file)
 --  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 package body Pck is
+
+   function New_Small_Table (Low: Color; High: Color) return Small_Table is
+      Result : Small_Table (Low .. High);
+   begin
+      for J in Low .. High loop
+         Result (J) := (J = Black or J = Green or J = White);
+      end loop;
+      return Result;
+   end New_Small_Table;
+
+   function New_Multi_Table (Low, High: Color; LS, HS: Strength)
+     return Multi_Table is
+      Result : Multi_Table (Low .. High, LS .. HS);
+      Next : Boolean := True;
+   begin
+      for J in Low .. High loop
+         for K in LS .. HS loop
+            Result (J, K) := Next;
+            Next := not Next;
+         end loop;
+      end loop;
+      return Result;
+   end New_Multi_Table;
+
+   function New_Multi_Multi_Table (L1, H1, L2, H2, L3, H3: Positive)
+     return Multi_Multi_Table is
+      Result : Multi_Multi_Table (L1 .. H1, L2 .. H2, L3 .. H3);
+      Next : Boolean := True;
+   begin
+      for J in L1 .. H1 loop
+         for K in L2 .. H2 loop
+           for L in L3 .. H3 loop
+              Result (J, K, L) := Next;
+               Next := not Next;
+            end loop;
+         end loop;
+      end loop;
+      return Result;
+   end New_Multi_Multi_Table;
+
    procedure Do_Nothing (A : System.Address) is
    begin
       null;
index c8f5b00d5c0af8bfba211cde73da8936f7235a6f..fdfd8bbc4c6052f751d95a276037a861a186b1c3 100644 (file)
 with System;
 package Pck is
    type Color is (Black, Red, Green, Blue, White);
+   type Strength is (None, Low, Medium, High);
+
    type Full_Table is array (Color) of Boolean;
    pragma Pack (Full_Table);
 
+   subtype Primary_Color is Color range Red .. Blue;
+   type Primary_Table is array (Primary_Color) of Boolean;
+   pragma Pack (Primary_Table);
+
+   type Cold_Color is new Color range Green .. Blue;
+   type Cold_Table is array (Cold_Color) of Boolean;
+   pragma Pack (Cold_Table);
+
+   type Small_Table is array (Color range <>) of Boolean;
+   pragma Pack (Small_Table);
+   function New_Small_Table (Low: Color; High: Color) return Small_Table;
+
+   type Multi_Table is array (Color range <>, Strength range <>) of Boolean;
+   pragma Pack (Multi_Table);
+   function New_Multi_Table (Low, High: Color; LS, HS: Strength)
+      return Multi_Table;
+
+   type Multi_Multi_Table is array (Positive range <>, Positive range <>, Positive range <>) of Boolean;
+   pragma Pack (Multi_Multi_Table);
+   function New_Multi_Multi_Table (L1, H1, L2, H2, L3, H3: Positive)
+      return Multi_Multi_Table;
+
    procedure Do_Nothing (A : System.Address);
 end Pck;