gdb: add support for Fortran's ASSUMED RANK arrays

This patch adds a new dynamic property DYN_PROP_RANK, this property is
read from the DW_AT_rank attribute and stored within the type just
like other dynamic properties.

As arrays with dynamic ranks make use of a single
DW_TAG_generic_subrange to represent all ranks of the array, support
for this tag has been added to dwarf2/read.c.

The final piece of this puzzle is to add support in gdbtypes.c so that
we can resolve an array type with dynamic rank.  To do this the
existing resolve_dynamic_array_or_string function is split into two,
there's a new resolve_dynamic_array_or_string_1 core that is
responsible for resolving each rank of the array, while the now outer
resolve_dynamic_array_or_string is responsible for figuring out the
array rank (which might require resolving a dynamic property) and then
calling the inner core.

The resolve_dynamic_range function now takes a rank, which is passed
on to the dwarf expression evaluator.  This rank will only be used in
the case where the array itself has dynamic rank, but we now pass the
rank in all cases, this should be harmless if the rank is not needed.

The only small nit is that resolve_dynamic_type_internal actually
handles resolving dynamic ranges itself, which now obviously requires
us to pass a rank value.  But what rank value to use?  In the end I
just passed '1' through here as a sane default, my thinking is that if
we are in resolve_dynamic_type_internal to resolve a range, then the
range isn't part of an array with dynamic rank, and so the range
should actually be using the rank value at all.

An alternative approach would be to make the rank value a
gdb::optional, however, this ends up adding a bunch of complexity to
the code (e.g. having to conditionally build the array to pass to
dwarf2_evaluate_property, and handling the 'rank - 1' in
resolve_dynamic_array_or_string_1) so I haven't done that, but could,
if people think that would be a better approach.

Finally, support for assumed rank arrays was only fixed very recently
in gcc, so you'll need the latest gcc in order to run the tests for
this.

Here's an example test program:

  PROGRAM arank
    REAL :: a1(10)
    CALL sub1(a1)

  CONTAINS

    SUBROUTINE sub1(a)
      REAL :: a(..)
      PRINT *, RANK(a)
    END SUBROUTINE sub1
  END PROGRAM arank

Compiler Version:
gcc (GCC) 12.0.0 20211122 (experimental)

Compilation command:
gfortran assumedrank.f90 -gdwarf-5 -o assumedrank

Without Patch:

  gdb -q assumedrank
  Reading symbols from assumedrank...
  (gdb) break sub1
  Breakpoint 1 at 0x4006ff: file assumedrank.f90, line 10.
  (gdb) run
  Starting program: /home/rupesh/STAGING-BUILD-2787/bin/assumedrank

  Breakpoint 1, arank::sub1 (a=<unknown type in /home/rupesh/STAGING-BUILD-2787
  /bin/assumedrank, CU 0x0, DIE 0xd5>) at assumedrank.f90:10
  10       PRINT *, RANK(a)
  (gdb) print RANK(a)
  'a' has unknown type; cast it to its declared type

With patch:

  gdb -q assumedrank
  Reading symbols from assumedrank...
  (gdb) break sub1
  Breakpoint 1 at 0x4006ff: file assumedrank.f90, line 10.
  (gdb) run
  Starting program: /home/rupesh/STAGING-BUILD-2787/bin/assumedrank

  Breakpoint 1, arank::sub1 (a=...) at assumedrank.f90:10
  10       PRINT *, RANK(a)
  (gdb) print RANK(a)
  $1 = 1
  (gdb) ptype a
  type = real(kind=4) (10)
  (gdb)

Co-Authored-By: Andrew Burgess <aburgess@redhat.com>
This commit is contained in:
rupothar 2022-03-17 18:56:23 +00:00 committed by Andrew Burgess
parent 1fb43cf759
commit df7a7bdd97
5 changed files with 263 additions and 15 deletions

View file

@ -2199,7 +2199,7 @@ static struct type *resolve_dynamic_type_internal
static struct type *
resolve_dynamic_range (struct type *dyn_range_type,
struct property_addr_info *addr_stack,
bool resolve_p = true)
int rank, bool resolve_p = true)
{
CORE_ADDR value;
struct type *static_range_type, *static_target_type;
@ -2208,13 +2208,15 @@ resolve_dynamic_range (struct type *dyn_range_type,
gdb_assert (dyn_range_type->code () == TYPE_CODE_RANGE);
const struct dynamic_prop *prop = &dyn_range_type->bounds ()->low;
if (resolve_p && dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
if (resolve_p && dwarf2_evaluate_property (prop, NULL, addr_stack, &value,
{ (CORE_ADDR) rank }))
low_bound.set_const_val (value);
else
low_bound.set_undefined ();
prop = &dyn_range_type->bounds ()->high;
if (resolve_p && dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
if (resolve_p && dwarf2_evaluate_property (prop, NULL, addr_stack, &value,
{ (CORE_ADDR) rank }))
{
high_bound.set_const_val (value);
@ -2227,7 +2229,8 @@ resolve_dynamic_range (struct type *dyn_range_type,
bool byte_stride_p = dyn_range_type->bounds ()->flag_is_byte_stride;
prop = &dyn_range_type->bounds ()->stride;
if (resolve_p && dwarf2_evaluate_property (prop, NULL, addr_stack, &value))
if (resolve_p && dwarf2_evaluate_property (prop, NULL, addr_stack, &value,
{ (CORE_ADDR) rank }))
{
stride.set_const_val (value);
@ -2258,18 +2261,29 @@ resolve_dynamic_range (struct type *dyn_range_type,
return static_range_type;
}
/* Resolves dynamic bound values of an array or string type TYPE to static
ones. ADDR_STACK is a stack of struct property_addr_info to be used if
needed during the dynamic resolution.
/* Helper function for resolve_dynamic_array_or_string. This function
resolves the properties for a single array at RANK within a nested array
of arrays structure. The RANK value is always greater than 0, and
starts at it's maximum value and goes down by 1 for each recursive call
to this function. So, for a 3-dimensional array, the first call to this
function has RANK == 3, then we call ourselves recursively with RANK ==
2, than again with RANK == 1, and at that point we should return.
TYPE is updated as the dynamic properties are resolved, and so, should
be a copy of the dynamic type, rather than the original dynamic type
itself.
ADDR_STACK is a stack of struct property_addr_info to be used if needed
during the dynamic resolution.
When RESOLVE_P is true then the dynamic properties of TYPE are
evaluated, otherwise the dynamic properties of TYPE are not evaluated,
instead we assume the array is not allocated/associated yet. */
static struct type *
resolve_dynamic_array_or_string (struct type *type,
struct property_addr_info *addr_stack,
bool resolve_p = true)
resolve_dynamic_array_or_string_1 (struct type *type,
struct property_addr_info *addr_stack,
int rank, bool resolve_p)
{
CORE_ADDR value;
struct type *elt_type;
@ -2283,7 +2297,9 @@ resolve_dynamic_array_or_string (struct type *type,
gdb_assert (type->code () == TYPE_CODE_ARRAY
|| type->code () == TYPE_CODE_STRING);
type = copy_type (type);
/* The outer resolve_dynamic_array_or_string should ensure we always have
a rank of at least 1 when we get here. */
gdb_assert (rank > 0);
/* Resolve the allocated and associated properties before doing anything
else. If an array is not allocated or not associated then (at least
@ -2313,11 +2329,16 @@ resolve_dynamic_array_or_string (struct type *type,
}
range_type = check_typedef (type->index_type ());
range_type = resolve_dynamic_range (range_type, addr_stack, resolve_p);
range_type
= resolve_dynamic_range (range_type, addr_stack, rank, resolve_p);
ary_dim = check_typedef (TYPE_TARGET_TYPE (type));
if (ary_dim != NULL && ary_dim->code () == TYPE_CODE_ARRAY)
elt_type = resolve_dynamic_array_or_string (ary_dim, addr_stack, resolve_p);
{
ary_dim = copy_type (ary_dim);
elt_type = resolve_dynamic_array_or_string_1 (ary_dim, addr_stack,
rank - 1, resolve_p);
}
else
elt_type = TYPE_TARGET_TYPE (type);
@ -2345,6 +2366,78 @@ resolve_dynamic_array_or_string (struct type *type,
bit_stride);
}
/* Resolve an array or string type with dynamic properties, return a new
type with the dynamic properties resolved to actual values. The
ADDR_STACK represents the location of the object being resolved. */
static struct type *
resolve_dynamic_array_or_string (struct type *type,
struct property_addr_info *addr_stack)
{
CORE_ADDR value;
int rank = 0;
/* For dynamic type resolution strings can be treated like arrays of
characters. */
gdb_assert (type->code () == TYPE_CODE_ARRAY
|| type->code () == TYPE_CODE_STRING);
type = copy_type (type);
/* Resolve the rank property to get rank value. */
struct dynamic_prop *prop = TYPE_RANK_PROP (type);
if (dwarf2_evaluate_property (prop, nullptr, addr_stack, &value))
{
prop->set_const_val (value);
rank = value;
if (rank == 0)
{
/* The dynamic property list juggling below was from the original
patch. I don't understand what this is all about, so I've
commented it out for now and added the following error. */
error (_("failed to resolve dynamic array rank"));
}
else if (type->code () == TYPE_CODE_STRING && rank != 1)
{
/* What would this even mean? A string with a dynamic rank
greater than 1. */
error (_("unable to handle string with dynamic rank greater than 1"));
}
else if (rank > 1)
{
/* Arrays with dynamic rank are initially just an array type
with a target type that is the array element.
However, now we know the rank of the array we need to build
the array of arrays structure that GDB expects, that is we
need an array type that has a target which is an array type,
and so on, until eventually, we have the element type at the
end of the chain. Create all the additional array types here
by copying the top level array type. */
struct type *element_type = TYPE_TARGET_TYPE (type);
struct type *rank_type = type;
for (int i = 1; i < rank; i++)
{
TYPE_TARGET_TYPE (rank_type) = copy_type (rank_type);
rank_type = TYPE_TARGET_TYPE (rank_type);
}
TYPE_TARGET_TYPE (rank_type) = element_type;
}
}
else
{
rank = 1;
for (struct type *tmp_type = check_typedef (TYPE_TARGET_TYPE (type));
tmp_type->code () == TYPE_CODE_ARRAY;
tmp_type = check_typedef (TYPE_TARGET_TYPE (tmp_type)))
++rank;
}
return resolve_dynamic_array_or_string_1 (type, addr_stack, rank, true);
}
/* Resolve dynamic bounds of members of the union TYPE to static
bounds. ADDR_STACK is a stack of struct property_addr_info
to be used if needed during the dynamic resolution. */
@ -2730,7 +2823,11 @@ resolve_dynamic_type_internal (struct type *type,
break;
case TYPE_CODE_RANGE:
resolved_type = resolve_dynamic_range (type, addr_stack);
/* Pass 1 for the rank value here. The assumption is that this
rank value is not actually required for the resolution of the
dynamic range, otherwise, we'd be resolving this range within
the context of a dynamic array. */
resolved_type = resolve_dynamic_range (type, addr_stack, 1);
break;
case TYPE_CODE_UNION: