DWARF: Add array DW_AT_bit_stride and DW_AT_byte_stride support
authorJoel Brobecker <brobecker@adacore.com>
Wed, 29 Jan 2014 13:39:56 +0000 (17:39 +0400)
committerJoel Brobecker <brobecker@adacore.com>
Wed, 26 Feb 2014 14:32:39 +0000 (06:32 -0800)
Consider the following declarations in Ada...

   type Item is range -32 .. 31;
   for Item'Size use 6;

   type Table is array (Natural range 0 .. 4) of Item;
   pragma Pack (Table);

... which declare a packed array whose elements are 6 bits long.
The debugger currently does not notice that the array is packed,
and thus prints values of this type incorrectly. This can be seen
in the "ptype" output:

    (gdb) ptype table
    type = array (0 .. 4) of foo.item

Normally, the debugger should print:

    (gdb) ptype table
    type = array (0 .. 4) of foo.item <packed: 6-bit elements>

The debugging information for this array looks like this:

        .uleb128 0xf    # (DIE (0x15c) DW_TAG_array_type)
        .long   .LASF9  # DW_AT_name: "pck__table"
        .byte   0x6     # DW_AT_bit_stride
        .long   0x1a9   # DW_AT_type
        .uleb128 0x10   # (DIE (0x16a) DW_TAG_subrange_type)
        .long   0x3b    # DW_AT_type
        .byte   0       # DW_AT_lower_bound
        .byte   0x4     # DW_AT_upper_bound
        .byte   0       # end of children of DIE 0x15c

The interesting part is the DW_AT_bit_stride attribute, which tells
the size of the array elements is 6 bits, rather than the normal
element type's size.

This patch adds support for this attribute by first creating
gdbtypes.c::create_array_type_with_stride, which is an enhanced
version of create_array_type taking an extra parameter as the stride.
The old create_array_type can then be re-implemented very simply
by calling the new create_array_type_with_stride.

We can then use this new function from dwarf2read, to create
arrays with or without stride.

gdb/ChangeLog:

        * gdbtypes.h (create_array_type_with_stride): Add declaration.
        * gdbtypes.c (create_array_type_with_stride): New function,
        renaming create_array_type, but with an added parameter
        called "bit_stride".
        (create_array_type): Re-implement using
        create_array_type_with_stride.
        * dwarf2read.c (read_array_type): Add support for DW_AT_byte_stride
        and DW_AT_bit_stride attributes.

gdb/testsuite/ChangeLog:

        * gdb.dwarf2/arr-stride.c: New file.
        * gdb.dwarf2/arr-stride.exp: New file.

The test, relying purely on generating an assembly file, only
verifies the type description of our array. But I was also
able to verify manually that the debugger print values of these
types correctly as well (which was not the case prior to this
patch).

gdb/ChangeLog
gdb/dwarf2read.c
gdb/gdbtypes.c
gdb/gdbtypes.h
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.dwarf2/arr-stride.c [new file with mode: 0644]
gdb/testsuite/gdb.dwarf2/arr-stride.exp [new file with mode: 0644]

index 3a02a49057a3610516eb10553900c58247266cef..a4377a9e696c8f3df5d14765f33abebb332f261e 100644 (file)
@@ -1,3 +1,14 @@
+2014-02-26  Joel Brobecker  <brobecker@adacore.com>
+
+       * gdbtypes.h (create_array_type_with_stride): Add declaration.
+       * gdbtypes.c (create_array_type_with_stride): New function,
+       renaming create_array_type, but with an added parameter
+       called "bit_stride".
+       (create_array_type): Re-implement using
+       create_array_type_with_stride.
+       * dwarf2read.c (read_array_type): Add support for DW_AT_byte_stride
+       and DW_AT_bit_stride attributes.
+
 2014-02-26  Pedro Alves  <palves@redhat.com>
 
        * breakpoint.c (bpstat_check_breakpoint_conditions): Handle
index 3eaa0b182361e4406a42333d0f560d50a6463ba0..d7dc38cdec65734bf1a80bc633dae43ee92a8493 100644 (file)
@@ -13281,6 +13281,7 @@ read_array_type (struct die_info *die, struct dwarf2_cu *cu)
   int ndim = 0;
   struct cleanup *back_to;
   const char *name;
+  unsigned int bit_stride = 0;
 
   element_type = die_type (die, cu);
 
@@ -13289,13 +13290,22 @@ read_array_type (struct die_info *die, struct dwarf2_cu *cu)
   if (type)
     return type;
 
+  attr = dwarf2_attr (die, DW_AT_byte_stride, cu);
+  if (attr != NULL)
+    bit_stride = DW_UNSND (attr) * 8;
+
+  attr = dwarf2_attr (die, DW_AT_bit_stride, cu);
+  if (attr != NULL)
+    bit_stride = DW_UNSND (attr);
+
   /* Irix 6.2 native cc creates array types without children for
      arrays with unspecified length.  */
   if (die->child == NULL)
     {
       index_type = objfile_type (objfile)->builtin_int;
       range_type = create_range_type (NULL, index_type, 0, -1);
-      type = create_array_type (NULL, element_type, range_type);
+      type = create_array_type_with_stride (NULL, element_type, range_type,
+                                           bit_stride);
       return set_die_type (die, type, cu);
     }
 
@@ -13335,12 +13345,14 @@ read_array_type (struct die_info *die, struct dwarf2_cu *cu)
       int i = 0;
 
       while (i < ndim)
-       type = create_array_type (NULL, type, range_types[i++]);
+       type = create_array_type_with_stride (NULL, type, range_types[i++],
+                                             bit_stride);
     }
   else
     {
       while (ndim-- > 0)
-       type = create_array_type (NULL, type, range_types[ndim]);
+       type = create_array_type_with_stride (NULL, type, range_types[ndim],
+                                             bit_stride);
     }
 
   /* Understand Dwarf2 support for vector types (like they occur on
index 622eff08bc20f70b107eea0b1d752052b3b71e14..98cb873ee8ac36e5003e1c8476fec4f0b1902f60 100644 (file)
@@ -951,14 +951,18 @@ get_array_bounds (struct type *type, LONGEST *low_bound, LONGEST *high_bound)
    Elements will be of type ELEMENT_TYPE, the indices will be of type
    RANGE_TYPE.
 
+   If BIT_STRIDE is not zero, build a packed array type whose element
+   size is BIT_STRIDE.  Otherwise, ignore this parameter.
+
    FIXME: Maybe we should check the TYPE_CODE of RESULT_TYPE to make
    sure it is TYPE_CODE_UNDEF before we bash it into an array
    type?  */
 
 struct type *
-create_array_type (struct type *result_type, 
-                  struct type *element_type,
-                  struct type *range_type)
+create_array_type_with_stride (struct type *result_type,
+                              struct type *element_type,
+                              struct type *range_type,
+                              unsigned int bit_stride)
 {
   LONGEST low_bound, high_bound;
 
@@ -975,6 +979,9 @@ create_array_type (struct type *result_type,
      In such cases, the array length should be zero.  */
   if (high_bound < low_bound)
     TYPE_LENGTH (result_type) = 0;
+  else if (bit_stride > 0)
+    TYPE_LENGTH (result_type) =
+      (bit_stride * (high_bound - low_bound + 1) + 7) / 8;
   else
     TYPE_LENGTH (result_type) =
       TYPE_LENGTH (element_type) * (high_bound - low_bound + 1);
@@ -983,6 +990,8 @@ create_array_type (struct type *result_type,
     (struct field *) TYPE_ZALLOC (result_type, sizeof (struct field));
   TYPE_INDEX_TYPE (result_type) = range_type;
   TYPE_VPTR_FIELDNO (result_type) = -1;
+  if (bit_stride > 0)
+    TYPE_FIELD_BITSIZE (result_type, 0) = bit_stride;
 
   /* TYPE_FLAG_TARGET_STUB will take care of zero length arrays.  */
   if (TYPE_LENGTH (result_type) == 0)
@@ -991,6 +1000,18 @@ create_array_type (struct type *result_type,
   return result_type;
 }
 
+/* Same as create_array_type_with_stride but with no bit_stride
+   (BIT_STRIDE = 0), thus building an unpacked array.  */
+
+struct type *
+create_array_type (struct type *result_type,
+                  struct type *element_type,
+                  struct type *range_type)
+{
+  return create_array_type_with_stride (result_type, element_type,
+                                       range_type, 0);
+}
+
 struct type *
 lookup_array_range_type (struct type *element_type,
                         LONGEST low_bound, LONGEST high_bound)
index 643c61006befb298011c488e72885b2dc878dd75..080c3eb84ed892220300df6dcb0e64567aa1f9fa 100644 (file)
@@ -1529,8 +1529,12 @@ extern struct type *lookup_function_type_with_arguments (struct type *,
 extern struct type *create_range_type (struct type *, struct type *, LONGEST,
                                       LONGEST);
 
+extern struct type *create_array_type_with_stride
+  (struct type *, struct type *, struct type *, unsigned int);
+
 extern struct type *create_array_type (struct type *, struct type *,
                                       struct type *);
+
 extern struct type *lookup_array_range_type (struct type *, LONGEST, LONGEST);
 
 extern struct type *create_string_type (struct type *, struct type *,
index 09cc8a3228367ca4592dc5a153f2dbcfb4bdc8dd..476e1a34e0e88c1787f38b46923c9301ad0f48b4 100644 (file)
@@ -1,3 +1,8 @@
+2014-02-26  Joel Brobecker  <brobecker@adacore.com>
+
+       * gdb.dwarf2/arr-stride.c: New file.
+       * gdb.dwarf2/arr-stride.exp: New file.
+
 2014-02-26  Pedro Alves  <palves@redhat.com>
 
        * gdb.ada/tasks.exp: Set a task-specific breakpoint at break_me
diff --git a/gdb/testsuite/gdb.dwarf2/arr-stride.c b/gdb/testsuite/gdb.dwarf2/arr-stride.c
new file mode 100644 (file)
index 0000000..978ef8d
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright 2014 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.dwarf2/arr-stride.exp b/gdb/testsuite/gdb.dwarf2/arr-stride.exp
new file mode 100644 (file)
index 0000000..f2a1f39
--- /dev/null
@@ -0,0 +1,108 @@
+# Copyright 2014 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+    return 0
+}
+
+standard_testfile arr-stride.c arr-stride-dw.S
+
+# Make some DWARF for the test.
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    cu {} {
+       DW_TAG_compile_unit {
+                {DW_AT_language @DW_LANG_Ada95}
+                {DW_AT_name     foo.adb}
+                {DW_AT_comp_dir /tmp}
+        } {
+           declare_labels integer_label array_elt_label array_label \
+                big_array_label
+
+            integer_label: DW_TAG_base_type {
+                {DW_AT_byte_size 4 DW_FORM_sdata}
+                {DW_AT_encoding  @DW_ATE_signed}
+                {DW_AT_name      integer}
+            }
+
+            array_elt_label: DW_TAG_subrange_type {
+                {DW_AT_lower_bound 0xe0 DW_FORM_data1}
+                {DW_AT_upper_bound 0x1f DW_FORM_data1}
+                {DW_AT_name        pck__item}
+                {DW_AT_type        :$integer_label}
+            }
+
+            DW_TAG_typedef {
+                {DW_AT_name pck__table}
+                {DW_AT_type :$array_label}
+            }
+
+           array_label: DW_TAG_array_type {
+               {DW_AT_name pck__table}
+                {DW_AT_bit_stride 6 DW_FORM_data1}
+               {DW_AT_type :$array_elt_label}
+           } {
+               DW_TAG_subrange_type {
+                   {DW_AT_type        :$integer_label}
+                   {DW_AT_lower_bound 0 DW_FORM_data1}
+                   {DW_AT_upper_bound 4 DW_FORM_data1}
+               }
+           }
+
+            DW_TAG_typedef {
+                {DW_AT_name pck__big_table}
+                {DW_AT_type :$big_array_label}
+            }
+
+           big_array_label: DW_TAG_array_type {
+               {DW_AT_name pck__big_table}
+                {DW_AT_byte_stride 1 DW_FORM_data1}
+               {DW_AT_type :$array_elt_label}
+           } {
+               DW_TAG_subrange_type {
+                   {DW_AT_type        :$integer_label}
+                   {DW_AT_lower_bound 0 DW_FORM_data1}
+                   {DW_AT_upper_bound 4 DW_FORM_data1}
+               }
+           }
+       }
+    }
+}
+
+if  {[gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile}1.o \
+         object {nodebug}] != ""} {
+    return -1
+}
+
+if  {[gdb_compile $asm_file ${binfile}2.o object {nodebug}] != ""} {
+    return -1
+}
+
+if  {[gdb_compile [list ${binfile}1.o ${binfile}2.o] \
+         "${binfile}" executable {}] != ""} {
+    return -1
+}
+
+clean_restart ${testfile}
+
+gdb_test_no_output "set language ada"
+
+gdb_test "ptype pck.table" \
+         "type = array \\(0 \\.\\. 4\\) of pck\\.item <packed: 6-bit elements>"
+
+gdb_test "ptype pck.big_table" \
+         "type = array \\(0 \\.\\. 4\\) of pck\\.item <packed: 8-bit elements>"