mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 18:14:13 +08:00
Handling of arrays with optimized-out bounds
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.
This commit is contained in:
parent
bae2a57f4c
commit
a8b1650962
@ -679,7 +679,7 @@ ada_discrete_type_high_bound (struct type *type)
|
|||||||
return high.const_val ();
|
return high.const_val ();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gdb_assert (high.kind () == PROP_UNDEFINED);
|
gdb_assert (!high.is_available ());
|
||||||
|
|
||||||
/* This happens when trying to evaluate a type's dynamic bound
|
/* This happens when trying to evaluate a type's dynamic bound
|
||||||
without a live target. There is nothing relevant for us to
|
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 ();
|
return low.const_val ();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gdb_assert (low.kind () == PROP_UNDEFINED);
|
gdb_assert (!low.is_available ());
|
||||||
|
|
||||||
/* This happens when trying to evaluate a type's dynamic bound
|
/* This happens when trying to evaluate a type's dynamic bound
|
||||||
without a live target. There is nothing relevant for us to
|
without a live target. There is nothing relevant for us to
|
||||||
|
@ -192,7 +192,7 @@ c_number_of_children (const struct varobj *var)
|
|||||||
{
|
{
|
||||||
case TYPE_CODE_ARRAY:
|
case TYPE_CODE_ARRAY:
|
||||||
if (type->length () > 0 && target->length () > 0
|
if (type->length () > 0 && target->length () > 0
|
||||||
&& (type->bounds ()->high.kind () != PROP_UNDEFINED))
|
&& type->bounds ()->high.is_available ())
|
||||||
children = type->length () / target->length ();
|
children = type->length () / target->length ();
|
||||||
else
|
else
|
||||||
/* If we don't know how many elements there are, don't display
|
/* If we don't know how many elements there are, don't display
|
||||||
|
@ -2828,7 +2828,7 @@ var_value_operation::evaluate_for_sizeof (struct expression *exp,
|
|||||||
if (type_not_allocated (type) || type_not_associated (type))
|
if (type_not_allocated (type) || type_not_associated (type))
|
||||||
return value::zero (size_type, not_lval);
|
return value::zero (size_type, not_lval);
|
||||||
else if (is_dynamic_type (type->index_type ())
|
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);
|
return value::allocate_optimized_out (size_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1372,7 +1372,7 @@ fortran_undetermined::value_subarray (value *array,
|
|||||||
have a known upper bound, so don't error check in that
|
have a known upper bound, so don't error check in that
|
||||||
situation. */
|
situation. */
|
||||||
if (index < lb
|
if (index < lb
|
||||||
|| (dim_type->index_type ()->bounds ()->high.kind () != PROP_UNDEFINED
|
|| (dim_type->index_type ()->bounds ()->high.is_available ()
|
||||||
&& index > ub)
|
&& index > ub)
|
||||||
|| (array->lval () != lval_memory
|
|| (array->lval () != lval_memory
|
||||||
&& dim_type->index_type ()->bounds ()->high.kind () == PROP_UNDEFINED))
|
&& dim_type->index_type ()->bounds ()->high.kind () == PROP_UNDEFINED))
|
||||||
|
@ -2179,21 +2179,35 @@ resolve_dynamic_range (struct type *dyn_range_type,
|
|||||||
gdb_assert (rank >= 0);
|
gdb_assert (rank >= 0);
|
||||||
|
|
||||||
const struct dynamic_prop *prop = &dyn_range_type->bounds ()->low;
|
const struct dynamic_prop *prop = &dyn_range_type->bounds ()->low;
|
||||||
if (resolve_p && dwarf2_evaluate_property (prop, frame, addr_stack, &value,
|
if (resolve_p)
|
||||||
{ (CORE_ADDR) rank }))
|
{
|
||||||
low_bound.set_const_val (value);
|
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
|
else
|
||||||
low_bound.set_undefined ();
|
low_bound.set_undefined ();
|
||||||
|
|
||||||
prop = &dyn_range_type->bounds ()->high;
|
prop = &dyn_range_type->bounds ()->high;
|
||||||
if (resolve_p && dwarf2_evaluate_property (prop, frame, addr_stack, &value,
|
if (resolve_p)
|
||||||
{ (CORE_ADDR) rank }))
|
|
||||||
{
|
{
|
||||||
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)
|
if (dyn_range_type->bounds ()->flag_upper_bound_is_count)
|
||||||
high_bound.set_const_val
|
high_bound.set_const_val
|
||||||
(low_bound.const_val () + high_bound.const_val () - 1);
|
(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
|
else
|
||||||
high_bound.set_undefined ();
|
high_bound.set_undefined ();
|
||||||
|
@ -271,6 +271,7 @@ enum dynamic_prop_kind
|
|||||||
PROP_VARIANT_PARTS, /* Variant parts. */
|
PROP_VARIANT_PARTS, /* Variant parts. */
|
||||||
PROP_TYPE, /* Type. */
|
PROP_TYPE, /* Type. */
|
||||||
PROP_VARIABLE_NAME, /* Variable name. */
|
PROP_VARIABLE_NAME, /* Variable name. */
|
||||||
|
PROP_OPTIMIZED_OUT, /* Optimized out. */
|
||||||
};
|
};
|
||||||
|
|
||||||
union dynamic_prop_data
|
union dynamic_prop_data
|
||||||
@ -318,6 +319,18 @@ struct dynamic_prop
|
|||||||
m_kind = PROP_UNDEFINED;
|
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
|
LONGEST const_val () const
|
||||||
{
|
{
|
||||||
gdb_assert (m_kind == PROP_CONST);
|
gdb_assert (m_kind == PROP_CONST);
|
||||||
@ -760,6 +773,13 @@ struct range_bounds
|
|||||||
return this->stride.const_val ();
|
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. */
|
/* * Low bound of range. */
|
||||||
|
|
||||||
struct dynamic_prop low;
|
struct dynamic_prop low;
|
||||||
@ -1135,6 +1155,12 @@ struct type
|
|||||||
this->main_type->flds_bnds.bounds = bounds;
|
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
|
ULONGEST bit_stride () const
|
||||||
{
|
{
|
||||||
if (this->code () == TYPE_CODE_ARRAY && this->field (0).bitsize () != 0)
|
if (this->code () == TYPE_CODE_ARRAY && this->field (0).bitsize () != 0)
|
||||||
|
22
gdb/testsuite/gdb.dwarf2/arr-opt-out.c
Normal file
22
gdb/testsuite/gdb.dwarf2/arr-opt-out.c
Normal file
@ -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;
|
||||||
|
}
|
95
gdb/testsuite/gdb.dwarf2/arr-opt-out.exp
Normal file
95
gdb/testsuite/gdb.dwarf2/arr-opt-out.exp
Normal file
@ -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
|
||||||
|
}
|
11
gdb/value.c
11
gdb/value.c
@ -3603,9 +3603,16 @@ value_from_contents_and_address (struct type *type,
|
|||||||
struct type *resolved_type = resolve_dynamic_type (type, view, address,
|
struct type *resolved_type = resolve_dynamic_type (type, view, address,
|
||||||
&frame);
|
&frame);
|
||||||
struct type *resolved_type_no_typedef = check_typedef (resolved_type);
|
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);
|
v = value::allocate_lazy (resolved_type);
|
||||||
else
|
else
|
||||||
v = value_from_contents (resolved_type, valaddr);
|
v = value_from_contents (resolved_type, valaddr);
|
||||||
|
Loading…
Reference in New Issue
Block a user