print PTR.all where PTR is an Ada thin pointer
authorJoel Brobecker <brobecker@adacore.com>
Fri, 29 Aug 2014 15:50:13 +0000 (17:50 +0200)
committerJoel Brobecker <brobecker@adacore.com>
Wed, 10 Sep 2014 13:24:25 +0000 (06:24 -0700)
Consider the following declaration:

   type Array_Type is array (Natural range <>) of Integer;
   type Array_Ptr is access all Array_Type;
   for Array_Ptr'Size use 64;
   Three_Ptr : Array_Ptr := new Array_Type'(1 => 1, 2 => 2, 3 => 3);

This creates a pointer to an array where the bounds are stored
in a memory region just before the array itself (aka a "thin pointer").
In DWARF, this is described as a the usual pointer type to an array
whose subrange has dynamic values for its bounds:

    <1><25>: Abbrev Number: 4 (DW_TAG_array_type)
       <26>   DW_AT_name        : foo__array_type
    [...]
    <2><3b>: Abbrev Number: 5 (DW_TAG_subrange_type)
       [...]
       <40>   DW_AT_lower_bound : 5 byte block: 97 38 1c 94 4
              (DW_OP_push_object_address; DW_OP_lit8; DW_OP_minus;
               DW_OP_deref_size: 4)
       <46>   DW_AT_upper_bound : 5 byte block: 97 34 1c 94 4
              (DW_OP_push_object_address; DW_OP_lit4; DW_OP_minus;
               DW_OP_deref_size: 4)

GDB is currently printing the value of the array incorrectly:

    (gdb) p foo.three_ptr.all
    $1 = (26629472 => 1, 2,
    value.c:819: internal-error: value_contents_bits_eq: [...]

The dereferencing (".all" operator) is done by calling ada_value_ind,
which itself calls value_ind. It first produces a new value where
the bounds of the array were correctly resolved to their actual value,
but then calls readjust_indirect_value_type which replaces the resolved
type by the original type.

The problem starts when ada_value_print does not take this situation
into account, and starts using the type of the resulting value, which
has unresolved array bounds, instead of using the value's enclosing
type.

After fixing this issue, the debugger now correctly prints:

    (gdb) p foo.three_ptr.all
    $1 = (1, 2, 3)

gdb/ChangeLog:

        * ada-valprint.c (ada_value_print): Use VAL's enclosing type
        instead of VAL's type.

gdb/testsuite/ChangeLog:

        * gdb.dwarf2/dynarr-ptr.c: New file.
        * gdb.dwarf2/dynarr-ptr.exp: New file.

gdb/ChangeLog
gdb/ada-valprint.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.dwarf2/dynarr-ptr.c [new file with mode: 0644]
gdb/testsuite/gdb.dwarf2/dynarr-ptr.exp [new file with mode: 0644]

index 2d20b1c6cf609255c7f52f9fa59014cec8073dcc..82e36229877fe36b30f79047079eb5b918cf173f 100644 (file)
@@ -1,3 +1,8 @@
+2014-09-10  Joel Brobecker  <brobecker@adacore.com>
+
+       * ada-valprint.c (ada_value_print): Use VAL's enclosing type
+       instead of VAL's type.
+
 2014-09-10  Joel Brobecker  <brobecker@adacore.com>
 
        * amd64-linux-nat.c: Add <sys/uio.h> #include.
index ae07cc21319ff089c6c190b77728a1cbbe0386d7..ade0a65f67cdc73493789ac7fee97f51a5d7ef22 100644 (file)
@@ -1171,7 +1171,7 @@ ada_value_print (struct value *val0, struct ui_file *stream,
 {
   struct value *val = ada_to_fixed_value (val0);
   CORE_ADDR address = value_address (val);
-  struct type *type = ada_check_typedef (value_type (val));
+  struct type *type = ada_check_typedef (value_enclosing_type (val));
   struct value_print_options opts;
 
   /* If it is a pointer, indicate what it points to.  */
index 37fe6a101986e2ac60c54f701d93190d4fb9c092..e7bba7790f0b5209878bcc053608dbc7522db3dc 100644 (file)
@@ -1,3 +1,8 @@
+2014-09-10  Joel Brobecker  <brobecker@adacore.com>
+
+       * gdb.dwarf2/dynarr-ptr.c: New file.
+       * gdb.dwarf2/dynarr-ptr.exp: New file.
+
 2014-09-09  Maciej W. Rozycki  <macro@codesourcery.com>
 
        * gdb.base/watchpoint-solib.exp: Increase the timeout by a factor
diff --git a/gdb/testsuite/gdb.dwarf2/dynarr-ptr.c b/gdb/testsuite/gdb.dwarf2/dynarr-ptr.c
new file mode 100644 (file)
index 0000000..2bdf254
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright 2014 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 table_1_data[] = {1, 3, 1, 2, 3};
+int *table_1_ptr = &table_1_data[2];
+
+int table_2_data[] = {2, 6, 5, 8, 13, 21, 34};
+int *table_2_ptr = &table_2_data[2];
+
+int
+main (void)
+{
+  *table_1_ptr = 2;
+  *table_2_ptr = 3;
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.dwarf2/dynarr-ptr.exp b/gdb/testsuite/gdb.dwarf2/dynarr-ptr.exp
new file mode 100644 (file)
index 0000000..501f129
--- /dev/null
@@ -0,0 +1,153 @@
+# 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 dynarr-ptr.c dynarr-ptr-dw.S
+
+# We need to know the size of integer and address types in order
+# to write some of the debugging info we'd like to generate.
+#
+# For that, we ask GDB by debugging our dynarr-ptr.c program.
+# Any program would do, but since we already have dynarr-ptr.c
+# specifically for this testcase, might as well use that.
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
+    untested ${testfile}.exp
+    return -1
+}
+
+# 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_label array_ptr_label \
+                array_typedef_label
+            set ptr_size [get_sizeof "void *" 96]
+
+            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_label: DW_TAG_array_type {
+               {DW_AT_name foo__array_type}
+               {DW_AT_type :$integer_label}
+                {external 1 flag}
+           } {
+               DW_TAG_subrange_type {
+                   {DW_AT_type        :$integer_label}
+                    {DW_AT_lower_bound {
+                        DW_OP_push_object_address
+                        DW_OP_lit8
+                        DW_OP_minus
+                        DW_OP_deref_size 4
+                    } SPECIAL_expr}
+                    {DW_AT_upper_bound {
+                        DW_OP_push_object_address
+                        DW_OP_lit4
+                        DW_OP_minus
+                        DW_OP_deref_size 4
+                    } SPECIAL_expr}
+               }
+           }
+            array_ptr_label: DW_TAG_pointer_type {
+                {DW_AT_byte_size :$ptr_size }
+                {DW_AT_type :$array_label}
+            }
+            array_typedef_label: DW_TAG_typedef {
+                {DW_AT_name "foo__array_ptr"}
+                {DW_AT_type :$array_ptr_label}
+            }
+            DW_TAG_variable {
+                {DW_AT_name foo__three_ptr}
+                {DW_AT_type :$array_ptr_label}
+                {DW_AT_location {
+                    DW_OP_addr table_1_ptr
+                } SPECIAL_expr}
+                {external 1 flag}
+            }
+            DW_TAG_variable {
+                {DW_AT_name foo__three_ptr_tdef}
+                {DW_AT_type :$array_typedef_label}
+                {DW_AT_location {
+                    DW_OP_addr table_1_ptr
+                } SPECIAL_expr}
+                {external 1 flag}
+            }
+            DW_TAG_variable {
+                {DW_AT_name foo__five_ptr}
+                {DW_AT_type :$array_ptr_label}
+                {DW_AT_location {
+                    DW_OP_addr table_2_ptr
+                } SPECIAL_expr}
+                {external 1 flag}
+            }
+            DW_TAG_variable {
+                {DW_AT_name foo__five_ptr_tdef}
+                {DW_AT_type :$array_typedef_label}
+                {DW_AT_location {
+                    DW_OP_addr table_2_ptr
+                } SPECIAL_expr}
+                {external 1 flag}
+            }
+       }
+    }
+}
+
+# Now that we've generated the DWARF debugging info, rebuild our
+# program using our debug info instead of the info generated by
+# the compiler.
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} \
+         [list $srcfile $asm_file] {nodebug}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+gdb_test_no_output "set language ada"
+
+# foo.three_ptr.all
+
+gdb_test "print foo.three_ptr.all" \
+         " = \\(1, 2, 3\\)"
+
+# foo.three_ptr_tdef.all
+
+gdb_test "print foo.three_ptr_tdef.all" \
+         " = \\(1, 2, 3\\)"
+
+# foo.five_ptr.all
+
+gdb_test "print foo.five_ptr.all" \
+         " = \\(2 => 5, 8, 13, 21, 34\\)"
+
+# foo.five_ptr_tdef.all
+
+gdb_test "print foo.five_ptr_tdef.all" \
+         " = \\(2 => 5, 8, 13, 21, 34\\)"