]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Handling of arrays with optimized-out bounds
authorTom Tromey <tromey@adacore.com>
Thu, 21 Dec 2023 15:24:18 +0000 (08:24 -0700)
committerTom Tromey <tromey@adacore.com>
Mon, 5 Feb 2024 14:13:37 +0000 (07:13 -0700)
In Ada, sometimes the compiler must emit array bounds by referencing
an artificial variable that's created for this purpose.  However, with
optimization enabled, these variables can be optimized away.

Currently this can result in displays like:

    (gdb) print mumble
    $1 = (warning: unable to get bounds of array, assuming null array
    )

This patch changes this to report that the array is optimized-out,
instead, which is closer to the truth, and more generally useful.  For
example, Python pretty-printers can now recognize this situation.

In order to accomplish this, I introduced a new PROP_OPTIMIZED_OUT
enumerator and changed one place to use it.  Reusing the "unknown"
state wouldn't work properly, because in C it is normal for array
bounds to be unknown.

gdb/ada-lang.c
gdb/c-varobj.c
gdb/eval.c
gdb/f-lang.c
gdb/gdbtypes.c
gdb/gdbtypes.h
gdb/testsuite/gdb.dwarf2/arr-opt-out.c [new file with mode: 0644]
gdb/testsuite/gdb.dwarf2/arr-opt-out.exp [new file with mode: 0644]
gdb/value.c

index 52bae581af65d10eab27a16d935ac1163ec10e7f..a3fd695e00348f8b9f2296efb64339197d65f889 100644 (file)
@@ -679,7 +679,7 @@ ada_discrete_type_high_bound (struct type *type)
          return high.const_val ();
        else
          {
-           gdb_assert (high.kind () == PROP_UNDEFINED);
+           gdb_assert (!high.is_available ());
 
            /* This happens when trying to evaluate a type's dynamic bound
               without a live target.  There is nothing relevant for us to
@@ -714,7 +714,7 @@ ada_discrete_type_low_bound (struct type *type)
          return low.const_val ();
        else
          {
-           gdb_assert (low.kind () == PROP_UNDEFINED);
+           gdb_assert (!low.is_available ());
 
            /* This happens when trying to evaluate a type's dynamic bound
               without a live target.  There is nothing relevant for us to
index ac840c694937d2083f8b5b8dbefe802d10c53548..4a7476449097efd165a1ad26549d36e947cfa6e8 100644 (file)
@@ -192,7 +192,7 @@ c_number_of_children (const struct varobj *var)
     {
     case TYPE_CODE_ARRAY:
       if (type->length () > 0 && target->length () > 0
-         && (type->bounds ()->high.kind () != PROP_UNDEFINED))
+         && type->bounds ()->high.is_available ())
        children = type->length () / target->length ();
       else
        /* If we don't know how many elements there are, don't display
index fae76a04097c975573aef401599a183a93137c7a..4c438f927c044ff790dbaedef7a2b1a6e6cba1c2 100644 (file)
@@ -2828,7 +2828,7 @@ var_value_operation::evaluate_for_sizeof (struct expression *exp,
          if (type_not_allocated (type) || type_not_associated (type))
            return value::zero (size_type, not_lval);
          else if (is_dynamic_type (type->index_type ())
-                  && type->bounds ()->high.kind () == PROP_UNDEFINED)
+                  && !type->bounds ()->high.is_available ())
            return value::allocate_optimized_out (size_type);
        }
     }
index d573c4f2fbb81ce34d3fb37ef846dbd96685fea3..96d4ed821c657693bd6b885623031b56f6d3c917 100644 (file)
@@ -1372,7 +1372,7 @@ fortran_undetermined::value_subarray (value *array,
             have a known upper bound, so don't error check in that
             situation.  */
          if (index < lb
-             || (dim_type->index_type ()->bounds ()->high.kind () != PROP_UNDEFINED
+             || (dim_type->index_type ()->bounds ()->high.is_available ()
                  && index > ub)
              || (array->lval () != lval_memory
                  && dim_type->index_type ()->bounds ()->high.kind () == PROP_UNDEFINED))
index ece161d6e4d8326310577e045763ae1309c1646d..dcd7321d9799f2a6d81b8212cf3fb6a94b231b06 100644 (file)
@@ -2179,21 +2179,35 @@ resolve_dynamic_range (struct type *dyn_range_type,
   gdb_assert (rank >= 0);
 
   const struct dynamic_prop *prop = &dyn_range_type->bounds ()->low;
-  if (resolve_p && dwarf2_evaluate_property (prop, frame, addr_stack, &value,
-                                            { (CORE_ADDR) rank }))
-    low_bound.set_const_val (value);
+  if (resolve_p)
+    {
+      if (dwarf2_evaluate_property (prop, frame, addr_stack, &value,
+                                   { (CORE_ADDR) rank }))
+       low_bound.set_const_val (value);
+      else if (prop->kind () == PROP_UNDEFINED)
+       low_bound.set_undefined ();
+      else
+       low_bound.set_optimized_out ();
+    }
   else
     low_bound.set_undefined ();
 
   prop = &dyn_range_type->bounds ()->high;
-  if (resolve_p && dwarf2_evaluate_property (prop, frame, addr_stack, &value,
-                                            { (CORE_ADDR) rank }))
+  if (resolve_p)
     {
-      high_bound.set_const_val (value);
+      if (dwarf2_evaluate_property (prop, frame, addr_stack, &value,
+                                   { (CORE_ADDR) rank }))
+       {
+         high_bound.set_const_val (value);
 
-      if (dyn_range_type->bounds ()->flag_upper_bound_is_count)
-       high_bound.set_const_val
-         (low_bound.const_val () + high_bound.const_val () - 1);
+         if (dyn_range_type->bounds ()->flag_upper_bound_is_count)
+           high_bound.set_const_val
+             (low_bound.const_val () + high_bound.const_val () - 1);
+       }
+      else if (prop->kind () == PROP_UNDEFINED)
+       high_bound.set_undefined ();
+      else
+       high_bound.set_optimized_out ();
     }
   else
     high_bound.set_undefined ();
index 2afcf163a814420227c2c1553f9a1ab7dd2e5a52..20f68885d6a67a9c67030eb09d32b847bb1350f4 100644 (file)
@@ -271,6 +271,7 @@ enum dynamic_prop_kind
   PROP_VARIANT_PARTS, /* Variant parts.  */
   PROP_TYPE,      /* Type.  */
   PROP_VARIABLE_NAME, /* Variable name.  */
+  PROP_OPTIMIZED_OUT, /* Optimized out.  */
 };
 
 union dynamic_prop_data
@@ -318,6 +319,18 @@ struct dynamic_prop
     m_kind = PROP_UNDEFINED;
   }
 
+  void set_optimized_out ()
+  {
+    m_kind = PROP_OPTIMIZED_OUT;
+  }
+
+  /* Return true if this property is "available", at least in theory
+     -- meaning it is neither undefined nor optimized out.  */
+  bool is_available () const
+  {
+    return m_kind != PROP_UNDEFINED && m_kind != PROP_OPTIMIZED_OUT;
+  }
+
   LONGEST const_val () const
   {
     gdb_assert (m_kind == PROP_CONST);
@@ -760,6 +773,13 @@ struct range_bounds
       return this->stride.const_val ();
   }
 
+  /* Return true if either bounds is optimized out.  */
+  bool optimized_out () const
+  {
+    return (low.kind () == PROP_OPTIMIZED_OUT
+           || high.kind () == PROP_OPTIMIZED_OUT);
+  }
+
   /* * Low bound of range.  */
 
   struct dynamic_prop low;
@@ -1135,6 +1155,12 @@ struct type
     this->main_type->flds_bnds.bounds = bounds;
   }
 
+  /* Return true if this type's bounds were optimized out.  */
+  bool bound_optimized_out () const
+  {
+    return bounds ()->optimized_out ();
+  }
+
   ULONGEST bit_stride () const
   {
     if (this->code () == TYPE_CODE_ARRAY && this->field (0).bitsize () != 0)
diff --git a/gdb/testsuite/gdb.dwarf2/arr-opt-out.c b/gdb/testsuite/gdb.dwarf2/arr-opt-out.c
new file mode 100644 (file)
index 0000000..5397911
--- /dev/null
@@ -0,0 +1,22 @@
+/* Copyright 2023 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 global_array[] = {0, 0};
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.dwarf2/arr-opt-out.exp b/gdb/testsuite/gdb.dwarf2/arr-opt-out.exp
new file mode 100644 (file)
index 0000000..387ac0c
--- /dev/null
@@ -0,0 +1,95 @@
+# Copyright 2023 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/>.
+
+# Test that an array whose bounds are optimized out is itself marked
+# as optimized out.
+
+load_lib dwarf.exp
+load_lib gdb-python.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+require dwarf2_support
+
+standard_testfile .c -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_label \
+               low_bound_label high_bound_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}
+           }
+
+           # Note that the bounds don't have a location -- they are
+           # optimized out.  This mimics what it is seen sometimes in
+           # the wild with optimized Ada code.
+           low_bound_label: DW_TAG_variable {
+               {DW_AT_name pck__table___L}
+               {DW_AT_type :$integer_label}
+               {DW_AT_declaration 1 flag}
+           }
+           high_bound_label: DW_TAG_variable {
+               {DW_AT_name pck__table___U}
+               {DW_AT_type :$integer_label}
+               {DW_AT_declaration 1 flag}
+           }
+
+           array_label: DW_TAG_array_type {
+               {DW_AT_name pck__table}
+               {DW_AT_type :$integer_label}
+           } {
+               DW_TAG_subrange_type {
+                   {DW_AT_type        :$integer_label}
+                   {DW_AT_lower_bound :$low_bound_label}
+                   {DW_AT_upper_bound :$high_bound_label}
+               }
+           }
+
+           DW_TAG_variable {
+               {DW_AT_name the_table}
+               {DW_AT_type :$array_label}
+               {DW_AT_location {
+                   DW_OP_addr [gdb_target_symbol global_array]
+               } SPECIAL_expr}
+               {DW_AT_external 1 flag}
+           }
+       }
+    }
+}
+
+if {[prepare_for_testing "failed to prepare" ${testfile} \
+        [list $srcfile $asm_file] {nodebug}]} {
+    return -1
+}
+
+gdb_test_no_output "set language ada"
+
+gdb_test "print the_table" " = <optimized out>"
+
+# The same but in Python.
+if {[allow_python_tests]} {
+    gdb_test "python print(gdb.parse_and_eval('the_table').is_optimized_out)" \
+       True
+}
index ccaef9fd80fa6bb81e3c440f3d1b9f8b905462af..8840aa41a332cd8cc0f34602d047238617bdc279 100644 (file)
@@ -3603,9 +3603,16 @@ value_from_contents_and_address (struct type *type,
   struct type *resolved_type = resolve_dynamic_type (type, view, address,
                                                     &frame);
   struct type *resolved_type_no_typedef = check_typedef (resolved_type);
-  struct value *v;
 
-  if (valaddr == NULL)
+  struct value *v;
+  if (resolved_type_no_typedef->code () == TYPE_CODE_ARRAY
+      && resolved_type_no_typedef->bound_optimized_out ())
+    {
+      /* Resolution found that the bounds are optimized out.  In this
+        case, mark the array itself as optimized-out.  */
+      v = value::allocate_optimized_out (resolved_type);
+    }
+  else if (valaddr == nullptr)
     v = value::allocate_lazy (resolved_type);
   else
     v = value_from_contents (resolved_type, valaddr);