mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 18:14:13 +08:00
cf88be6855
Getting the bounds of an array (or string) type is a common operation, and is currently done through its index type: my_array_type->index_type ()->bounds () I think it would make sense to let the `type::bounds` methods work for arrays and strings, as a shorthand for this. It's natural that when asking for the bounds of an array, we get the bounds of the range type used as its index type. In a way, it's equivalent as the now-removed TYPE_ARRAY_{LOWER,UPPER}_BOUND_IS_UNDEFINED and TYPE_ARRAY_{LOWER,UPPER}_BOUND_VALUE, except it returns the `range_bounds` object. The caller is then responsible for getting the property it needs in it. I updated all the spots I could find that could take advantage of this. Note that this also makes `type::bit_stride` work on array types, since `type::bit_stride` uses `type::bounds`. `my_array_type->bit_stride ()` now returns the bit stride of the array's index type. So some spots are also changed to take advantage of this. gdb/ChangeLog: * gdbtypes.h (struct type) <bounds>: Handle array and string types. * ada-lang.c (assign_aggregate): Use type::bounds on array/string type. * c-typeprint.c (c_type_print_varspec_suffix): Likewise. * c-varobj.c (c_number_of_children): Likewise. (c_describe_child): Likewise. * eval.c (evaluate_subexp_for_sizeof): Likewise. * f-typeprint.c (f_type_print_varspec_suffix): Likewise. (f_type_print_base): Likewise. * f-valprint.c (f77_array_offset_tbl): Likewise. (f77_get_upperbound): Likewise. (f77_print_array_1): Likewise. * guile/scm-type.c (gdbscm_type_range): Likewise. * m2-typeprint.c (m2_array): Likewise. (m2_is_long_set_of_type): Likewise. * m2-valprint.c (get_long_set_bounds): Likewise. * p-typeprint.c (pascal_type_print_varspec_prefix): Likewise. * python/py-type.c (typy_range): Likewise. * rust-lang.c (rust_internal_print_type): Likewise. * type-stack.c (type_stack::follow_types): Likewise. * valarith.c (value_subscripted_rvalue): Likewise. * valops.c (value_cast): Likewise. Change-Id: I5c0c08930bffe42fd69cb4bfcece28944dd88d1f
495 lines
14 KiB
C
495 lines
14 KiB
C
/* Support for printing Fortran values for GDB, the GNU debugger.
|
||
|
||
Copyright (C) 1993-2020 Free Software Foundation, Inc.
|
||
|
||
Contributed by Motorola. Adapted from the C definitions by Farooq Butt
|
||
(fmbutt@engage.sps.mot.com), additionally worked over by Stan Shebs.
|
||
|
||
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/>. */
|
||
|
||
#include "defs.h"
|
||
#include "symtab.h"
|
||
#include "gdbtypes.h"
|
||
#include "expression.h"
|
||
#include "value.h"
|
||
#include "valprint.h"
|
||
#include "language.h"
|
||
#include "f-lang.h"
|
||
#include "frame.h"
|
||
#include "gdbcore.h"
|
||
#include "command.h"
|
||
#include "block.h"
|
||
#include "dictionary.h"
|
||
#include "cli/cli-style.h"
|
||
#include "gdbarch.h"
|
||
|
||
static void f77_get_dynamic_length_of_aggregate (struct type *);
|
||
|
||
int f77_array_offset_tbl[MAX_FORTRAN_DIMS + 1][2];
|
||
|
||
/* Array which holds offsets to be applied to get a row's elements
|
||
for a given array. Array also holds the size of each subarray. */
|
||
|
||
LONGEST
|
||
f77_get_lowerbound (struct type *type)
|
||
{
|
||
if (type->bounds ()->low.kind () == PROP_UNDEFINED)
|
||
error (_("Lower bound may not be '*' in F77"));
|
||
|
||
return type->bounds ()->low.const_val ();
|
||
}
|
||
|
||
LONGEST
|
||
f77_get_upperbound (struct type *type)
|
||
{
|
||
if (type->bounds ()->high.kind () == PROP_UNDEFINED)
|
||
{
|
||
/* We have an assumed size array on our hands. Assume that
|
||
upper_bound == lower_bound so that we show at least 1 element.
|
||
If the user wants to see more elements, let him manually ask for 'em
|
||
and we'll subscript the array and show him. */
|
||
|
||
return f77_get_lowerbound (type);
|
||
}
|
||
|
||
return type->bounds ()->high.const_val ();
|
||
}
|
||
|
||
/* Obtain F77 adjustable array dimensions. */
|
||
|
||
static void
|
||
f77_get_dynamic_length_of_aggregate (struct type *type)
|
||
{
|
||
int upper_bound = -1;
|
||
int lower_bound = 1;
|
||
|
||
/* Recursively go all the way down into a possibly multi-dimensional
|
||
F77 array and get the bounds. For simple arrays, this is pretty
|
||
easy but when the bounds are dynamic, we must be very careful
|
||
to add up all the lengths correctly. Not doing this right
|
||
will lead to horrendous-looking arrays in parameter lists.
|
||
|
||
This function also works for strings which behave very
|
||
similarly to arrays. */
|
||
|
||
if (TYPE_TARGET_TYPE (type)->code () == TYPE_CODE_ARRAY
|
||
|| TYPE_TARGET_TYPE (type)->code () == TYPE_CODE_STRING)
|
||
f77_get_dynamic_length_of_aggregate (TYPE_TARGET_TYPE (type));
|
||
|
||
/* Recursion ends here, start setting up lengths. */
|
||
lower_bound = f77_get_lowerbound (type);
|
||
upper_bound = f77_get_upperbound (type);
|
||
|
||
/* Patch in a valid length value. */
|
||
|
||
TYPE_LENGTH (type) =
|
||
(upper_bound - lower_bound + 1)
|
||
* TYPE_LENGTH (check_typedef (TYPE_TARGET_TYPE (type)));
|
||
}
|
||
|
||
/* Actual function which prints out F77 arrays, Valaddr == address in
|
||
the superior. Address == the address in the inferior. */
|
||
|
||
static void
|
||
f77_print_array_1 (int nss, int ndimensions, struct type *type,
|
||
const gdb_byte *valaddr,
|
||
int embedded_offset, CORE_ADDR address,
|
||
struct ui_file *stream, int recurse,
|
||
const struct value *val,
|
||
const struct value_print_options *options,
|
||
int *elts)
|
||
{
|
||
struct type *range_type = check_typedef (type)->index_type ();
|
||
CORE_ADDR addr = address + embedded_offset;
|
||
LONGEST lowerbound, upperbound;
|
||
LONGEST i;
|
||
|
||
get_discrete_bounds (range_type, &lowerbound, &upperbound);
|
||
|
||
if (nss != ndimensions)
|
||
{
|
||
struct gdbarch *gdbarch = get_type_arch (type);
|
||
size_t dim_size = type_length_units (TYPE_TARGET_TYPE (type));
|
||
int unit_size = gdbarch_addressable_memory_unit_size (gdbarch);
|
||
size_t byte_stride = type->bit_stride () / (unit_size * 8);
|
||
if (byte_stride == 0)
|
||
byte_stride = dim_size;
|
||
size_t offs = 0;
|
||
|
||
for (i = lowerbound;
|
||
(i < upperbound + 1 && (*elts) < options->print_max);
|
||
i++)
|
||
{
|
||
struct value *subarray = value_from_contents_and_address
|
||
(TYPE_TARGET_TYPE (type), value_contents_for_printing_const (val)
|
||
+ offs, addr + offs);
|
||
|
||
fprintf_filtered (stream, "( ");
|
||
f77_print_array_1 (nss + 1, ndimensions, value_type (subarray),
|
||
value_contents_for_printing (subarray),
|
||
value_embedded_offset (subarray),
|
||
value_address (subarray),
|
||
stream, recurse, subarray, options, elts);
|
||
offs += byte_stride;
|
||
fprintf_filtered (stream, ") ");
|
||
}
|
||
if (*elts >= options->print_max && i < upperbound)
|
||
fprintf_filtered (stream, "...");
|
||
}
|
||
else
|
||
{
|
||
for (i = lowerbound; i < upperbound + 1 && (*elts) < options->print_max;
|
||
i++, (*elts)++)
|
||
{
|
||
struct value *elt = value_subscript ((struct value *)val, i);
|
||
|
||
common_val_print (elt, stream, recurse, options, current_language);
|
||
|
||
if (i != upperbound)
|
||
fprintf_filtered (stream, ", ");
|
||
|
||
if ((*elts == options->print_max - 1)
|
||
&& (i != upperbound))
|
||
fprintf_filtered (stream, "...");
|
||
}
|
||
}
|
||
}
|
||
|
||
/* This function gets called to print an F77 array, we set up some
|
||
stuff and then immediately call f77_print_array_1(). */
|
||
|
||
static void
|
||
f77_print_array (struct type *type, const gdb_byte *valaddr,
|
||
int embedded_offset,
|
||
CORE_ADDR address, struct ui_file *stream,
|
||
int recurse,
|
||
const struct value *val,
|
||
const struct value_print_options *options)
|
||
{
|
||
int ndimensions;
|
||
int elts = 0;
|
||
|
||
ndimensions = calc_f77_array_dims (type);
|
||
|
||
if (ndimensions > MAX_FORTRAN_DIMS || ndimensions < 0)
|
||
error (_("\
|
||
Type node corrupt! F77 arrays cannot have %d subscripts (%d Max)"),
|
||
ndimensions, MAX_FORTRAN_DIMS);
|
||
|
||
f77_print_array_1 (1, ndimensions, type, valaddr, embedded_offset,
|
||
address, stream, recurse, val, options, &elts);
|
||
}
|
||
|
||
|
||
/* Decorations for Fortran. */
|
||
|
||
static const struct generic_val_print_decorations f_decorations =
|
||
{
|
||
"(",
|
||
",",
|
||
")",
|
||
".TRUE.",
|
||
".FALSE.",
|
||
"void",
|
||
"{",
|
||
"}"
|
||
};
|
||
|
||
/* See f-lang.h. */
|
||
|
||
void
|
||
f_value_print_inner (struct value *val, struct ui_file *stream, int recurse,
|
||
const struct value_print_options *options)
|
||
{
|
||
struct type *type = check_typedef (value_type (val));
|
||
struct gdbarch *gdbarch = get_type_arch (type);
|
||
int printed_field = 0; /* Number of fields printed. */
|
||
struct type *elttype;
|
||
CORE_ADDR addr;
|
||
int index;
|
||
const gdb_byte *valaddr = value_contents_for_printing (val);
|
||
const CORE_ADDR address = value_address (val);
|
||
|
||
switch (type->code ())
|
||
{
|
||
case TYPE_CODE_STRING:
|
||
f77_get_dynamic_length_of_aggregate (type);
|
||
LA_PRINT_STRING (stream, builtin_type (gdbarch)->builtin_char,
|
||
valaddr, TYPE_LENGTH (type), NULL, 0, options);
|
||
break;
|
||
|
||
case TYPE_CODE_ARRAY:
|
||
if (TYPE_TARGET_TYPE (type)->code () != TYPE_CODE_CHAR)
|
||
{
|
||
fprintf_filtered (stream, "(");
|
||
f77_print_array (type, valaddr, 0,
|
||
address, stream, recurse, val, options);
|
||
fprintf_filtered (stream, ")");
|
||
}
|
||
else
|
||
{
|
||
struct type *ch_type = TYPE_TARGET_TYPE (type);
|
||
|
||
f77_get_dynamic_length_of_aggregate (type);
|
||
LA_PRINT_STRING (stream, ch_type, valaddr,
|
||
TYPE_LENGTH (type) / TYPE_LENGTH (ch_type),
|
||
NULL, 0, options);
|
||
}
|
||
break;
|
||
|
||
case TYPE_CODE_PTR:
|
||
if (options->format && options->format != 's')
|
||
{
|
||
value_print_scalar_formatted (val, options, 0, stream);
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
int want_space = 0;
|
||
|
||
addr = unpack_pointer (type, valaddr);
|
||
elttype = check_typedef (TYPE_TARGET_TYPE (type));
|
||
|
||
if (elttype->code () == TYPE_CODE_FUNC)
|
||
{
|
||
/* Try to print what function it points to. */
|
||
print_function_pointer_address (options, gdbarch, addr, stream);
|
||
return;
|
||
}
|
||
|
||
if (options->symbol_print)
|
||
want_space = print_address_demangle (options, gdbarch, addr,
|
||
stream, demangle);
|
||
else if (options->addressprint && options->format != 's')
|
||
{
|
||
fputs_filtered (paddress (gdbarch, addr), stream);
|
||
want_space = 1;
|
||
}
|
||
|
||
/* For a pointer to char or unsigned char, also print the string
|
||
pointed to, unless pointer is null. */
|
||
if (TYPE_LENGTH (elttype) == 1
|
||
&& elttype->code () == TYPE_CODE_INT
|
||
&& (options->format == 0 || options->format == 's')
|
||
&& addr != 0)
|
||
{
|
||
if (want_space)
|
||
fputs_filtered (" ", stream);
|
||
val_print_string (TYPE_TARGET_TYPE (type), NULL, addr, -1,
|
||
stream, options);
|
||
}
|
||
return;
|
||
}
|
||
break;
|
||
|
||
case TYPE_CODE_INT:
|
||
if (options->format || options->output_format)
|
||
{
|
||
struct value_print_options opts = *options;
|
||
|
||
opts.format = (options->format ? options->format
|
||
: options->output_format);
|
||
value_print_scalar_formatted (val, &opts, 0, stream);
|
||
}
|
||
else
|
||
value_print_scalar_formatted (val, options, 0, stream);
|
||
break;
|
||
|
||
case TYPE_CODE_STRUCT:
|
||
case TYPE_CODE_UNION:
|
||
/* Starting from the Fortran 90 standard, Fortran supports derived
|
||
types. */
|
||
fprintf_filtered (stream, "( ");
|
||
for (index = 0; index < type->num_fields (); index++)
|
||
{
|
||
struct value *field = value_field (val, index);
|
||
|
||
struct type *field_type = check_typedef (type->field (index).type ());
|
||
|
||
|
||
if (field_type->code () != TYPE_CODE_FUNC)
|
||
{
|
||
const char *field_name;
|
||
|
||
if (printed_field > 0)
|
||
fputs_filtered (", ", stream);
|
||
|
||
field_name = TYPE_FIELD_NAME (type, index);
|
||
if (field_name != NULL)
|
||
{
|
||
fputs_styled (field_name, variable_name_style.style (),
|
||
stream);
|
||
fputs_filtered (" = ", stream);
|
||
}
|
||
|
||
common_val_print (field, stream, recurse + 1,
|
||
options, current_language);
|
||
|
||
++printed_field;
|
||
}
|
||
}
|
||
fprintf_filtered (stream, " )");
|
||
break;
|
||
|
||
case TYPE_CODE_BOOL:
|
||
if (options->format || options->output_format)
|
||
{
|
||
struct value_print_options opts = *options;
|
||
opts.format = (options->format ? options->format
|
||
: options->output_format);
|
||
value_print_scalar_formatted (val, &opts, 0, stream);
|
||
}
|
||
else
|
||
{
|
||
LONGEST longval = value_as_long (val);
|
||
/* The Fortran standard doesn't specify how logical types are
|
||
represented. Different compilers use different non zero
|
||
values to represent logical true. */
|
||
if (longval == 0)
|
||
fputs_filtered (f_decorations.false_name, stream);
|
||
else
|
||
fputs_filtered (f_decorations.true_name, stream);
|
||
}
|
||
break;
|
||
|
||
case TYPE_CODE_REF:
|
||
case TYPE_CODE_FUNC:
|
||
case TYPE_CODE_FLAGS:
|
||
case TYPE_CODE_FLT:
|
||
case TYPE_CODE_VOID:
|
||
case TYPE_CODE_ERROR:
|
||
case TYPE_CODE_RANGE:
|
||
case TYPE_CODE_UNDEF:
|
||
case TYPE_CODE_COMPLEX:
|
||
case TYPE_CODE_CHAR:
|
||
default:
|
||
generic_value_print (val, stream, recurse, options, &f_decorations);
|
||
break;
|
||
}
|
||
}
|
||
|
||
static void
|
||
info_common_command_for_block (const struct block *block, const char *comname,
|
||
int *any_printed)
|
||
{
|
||
struct block_iterator iter;
|
||
struct symbol *sym;
|
||
struct value_print_options opts;
|
||
|
||
get_user_print_options (&opts);
|
||
|
||
ALL_BLOCK_SYMBOLS (block, iter, sym)
|
||
if (SYMBOL_DOMAIN (sym) == COMMON_BLOCK_DOMAIN)
|
||
{
|
||
const struct common_block *common = SYMBOL_VALUE_COMMON_BLOCK (sym);
|
||
size_t index;
|
||
|
||
gdb_assert (SYMBOL_CLASS (sym) == LOC_COMMON_BLOCK);
|
||
|
||
if (comname && (!sym->linkage_name ()
|
||
|| strcmp (comname, sym->linkage_name ()) != 0))
|
||
continue;
|
||
|
||
if (*any_printed)
|
||
putchar_filtered ('\n');
|
||
else
|
||
*any_printed = 1;
|
||
if (sym->print_name ())
|
||
printf_filtered (_("Contents of F77 COMMON block '%s':\n"),
|
||
sym->print_name ());
|
||
else
|
||
printf_filtered (_("Contents of blank COMMON block:\n"));
|
||
|
||
for (index = 0; index < common->n_entries; index++)
|
||
{
|
||
struct value *val = NULL;
|
||
|
||
printf_filtered ("%s = ",
|
||
common->contents[index]->print_name ());
|
||
|
||
try
|
||
{
|
||
val = value_of_variable (common->contents[index], block);
|
||
value_print (val, gdb_stdout, &opts);
|
||
}
|
||
|
||
catch (const gdb_exception_error &except)
|
||
{
|
||
fprintf_styled (gdb_stdout, metadata_style.style (),
|
||
"<error reading variable: %s>",
|
||
except.what ());
|
||
}
|
||
|
||
putchar_filtered ('\n');
|
||
}
|
||
}
|
||
}
|
||
|
||
/* This function is used to print out the values in a given COMMON
|
||
block. It will always use the most local common block of the
|
||
given name. */
|
||
|
||
static void
|
||
info_common_command (const char *comname, int from_tty)
|
||
{
|
||
struct frame_info *fi;
|
||
const struct block *block;
|
||
int values_printed = 0;
|
||
|
||
/* We have been told to display the contents of F77 COMMON
|
||
block supposedly visible in this function. Let us
|
||
first make sure that it is visible and if so, let
|
||
us display its contents. */
|
||
|
||
fi = get_selected_frame (_("No frame selected"));
|
||
|
||
/* The following is generally ripped off from stack.c's routine
|
||
print_frame_info(). */
|
||
|
||
block = get_frame_block (fi, 0);
|
||
if (block == NULL)
|
||
{
|
||
printf_filtered (_("No symbol table info available.\n"));
|
||
return;
|
||
}
|
||
|
||
while (block)
|
||
{
|
||
info_common_command_for_block (block, comname, &values_printed);
|
||
/* After handling the function's top-level block, stop. Don't
|
||
continue to its superblock, the block of per-file symbols. */
|
||
if (BLOCK_FUNCTION (block))
|
||
break;
|
||
block = BLOCK_SUPERBLOCK (block);
|
||
}
|
||
|
||
if (!values_printed)
|
||
{
|
||
if (comname)
|
||
printf_filtered (_("No common block '%s'.\n"), comname);
|
||
else
|
||
printf_filtered (_("No common blocks.\n"));
|
||
}
|
||
}
|
||
|
||
void _initialize_f_valprint ();
|
||
void
|
||
_initialize_f_valprint ()
|
||
{
|
||
add_info ("common", info_common_command,
|
||
_("Print out the values contained in a Fortran COMMON block."));
|
||
}
|