Add support for printing value of DWARF-based fixed-point type objects

This commit introduces a new kind of type, meant to describe
fixed-point types, using a new code added specifically for
this purpose (TYPE_CODE_FIXED_POINT).

It then adds handling of fixed-point base types in the DWARF reader.

And finally, as a first step, this commit adds support for printing
the value of fixed-point type objects.

Note that this commit has a known issue: Trying to print the value
of a fixed-point object with a format letter (e.g. "print /x NAME")
causes the wrong value to be printed because the scaling factor
is not applied. Since the fix for this issue is isolated, and
this is not a regression, the fix will be made in a pach of its own.
This is meant to simplify review and archeology.

Also, other functionalities related to fixed-point type handling
(ptype, arithmetics, etc), will be added piecemeal as well, for
the same reasons (faciliate reviews and archeology). Related to this,
the testcase gdb.ada/fixed_cmp.exp is adjusted to compile the test
program with -fgnat-encodings=all, so as to force the use of GNAT
encodings, rather than rely on the compiler's default to use them.
The intent is to enhance this testcase to also test the pure DWARF
approach using -fgnat-encodings=minimal as soon as the corresponding
suport gets added in. Thus, the modification to the testcase is made
in a way that it prepares this testcase to be tested in both modes.

gdb/ChangeLog:

        * ada-valprint.c (ada_value_print_1): Add fixed-point type handling.
        * dwarf2/read.c (get_dwarf2_rational_constant)
        (get_dwarf2_unsigned_rational_constant, finish_fixed_point_type)
        (has_zero_over_zero_small_attribute): New functions.
        read_base_type, set_die_type): Add fixed-point type handling.
        * gdb-gdb.py.in: Add fixed-point type handling.
        * gdbtypes.c: #include "gmp-utils.h".
        (create_range_type, set_type_code): Add fixed-point type handling.
        (init_fixed_point_type): New function.
        (is_integral_type, is_scalar_type): Add fixed-point type handling.
        (print_fixed_point_type_info): New function.
        (recursive_dump_type, copy_type_recursive): Add fixed-point type
        handling.
        (fixed_point_type_storage): New typedef.
        (fixed_point_objfile_key): New static global.
        (allocate_fixed_point_type_info, is_fixed_point_type): New functions.
        (fixed_point_type_base_type, fixed_point_scaling_factor): New
        functions.
        * gdbtypes.h: #include "gmp-utils.h".
        (enum type_code) <TYPE_SPECIFIC_FIXED_POINT>: New enum.
        (union type_specific) <fixed_point_info>: New field.
        (struct fixed_point_type_info): New struct.
        (INIT_FIXED_POINT_SPECIFIC, TYPE_FIXED_POINT_INFO): New macros.
        (init_fixed_point_type, is_fixed_point_type)
        (fixed_point_type_base_type, fixed_point_scaling_factor)
        (allocate_fixed_point_type_info): Add declarations.
        * valprint.c (generic_val_print_fixed_point): New function.
        (generic_value_print): Add fixed-point type handling.
        * value.c (value_as_address, unpack_long): Add fixed-point type
        handling.

gdb/testsuite/ChangeLog:

        * gdb.ada/fixed_cmp.exp: Force compilation to use -fgnat-encodings=all.
        * gdb.ada/fixed_points.exp: Add fixed-point variables printing tests.
        * gdb.ada/fixed_points/pck.ads, gdb.ada/fixed_points/pck.adb:
        New files.
        * gdb.ada/fixed_points/fixed_points.adb: Add use of package Pck.

        * gdb.dwarf2/dw2-fixed-point.c, gdb.dwarf2/dw2-fixed-point.exp:
        New files.
This commit is contained in:
Joel Brobecker
2020-11-15 03:12:52 -05:00
parent e55c6530db
commit 0958441403
16 changed files with 766 additions and 24 deletions

View File

@@ -40,6 +40,7 @@
#include "gdbcore.h"
#include "floatformat.h"
#include <algorithm>
#include "gmp-utils.h"
/* Initialize BADNESS constants. */
@@ -950,6 +951,8 @@ create_range_type (struct type *result_type, struct type *index_type,
result_type->set_bounds (bounds);
if (index_type->code () == TYPE_CODE_FIXED_POINT)
result_type->set_is_unsigned (index_type->is_unsigned ());
/* Note that the signed-ness of a range type can't simply be copied
from the underlying type. Consider a case where the underlying
type is 'int', but the range type can hold 0..65535, and where
@@ -957,7 +960,7 @@ create_range_type (struct type *result_type, struct type *index_type,
case, if we copy the underlying type's sign, then reading some
range values will cause an unwanted sign extension. So, we have
some heuristics here instead. */
if (low_bound->kind () == PROP_CONST && low_bound->const_val () >= 0)
else if (low_bound->kind () == PROP_CONST && low_bound->const_val () >= 0)
result_type->set_is_unsigned (true);
/* Ada allows the declaration of range types whose upper bound is
less than the lower bound, so checking the lower bound is not
@@ -3136,6 +3139,9 @@ set_type_code (struct type *type, enum type_code code)
break;
case TYPE_CODE_FUNC:
INIT_FUNC_SPECIFIC (type);
break;
case TYPE_CODE_FIXED_POINT:
INIT_FIXED_POINT_SPECIFIC (type);
break;
}
}
@@ -3352,6 +3358,24 @@ init_pointer_type (struct objfile *objfile,
return t;
}
/* Allocate a TYPE_CODE_FIXED_POINT type structure associated with OBJFILE.
BIT is the pointer type size in bits.
UNSIGNED_P should be nonzero if the type is unsigned.
NAME is the type name. */
struct type *
init_fixed_point_type (struct objfile *objfile,
int bit, int unsigned_p, const char *name)
{
struct type *t;
t = init_type (objfile, TYPE_CODE_FIXED_POINT, bit, name);
if (unsigned_p)
t->set_is_unsigned (true);
return t;
}
/* See gdbtypes.h. */
unsigned
@@ -3498,6 +3522,7 @@ is_integral_type (struct type *t)
t = check_typedef (t);
return
((t != NULL)
&& !is_fixed_point_type (t)
&& ((t->code () == TYPE_CODE_INT)
|| (t->code () == TYPE_CODE_ENUM)
|| (t->code () == TYPE_CODE_FLAGS)
@@ -3523,6 +3548,9 @@ is_scalar_type (struct type *type)
{
type = check_typedef (type);
if (is_fixed_point_type (type))
return 0; /* Implemented as a scalar, but more like a floating point. */
switch (type->code ())
{
case TYPE_CODE_ARRAY:
@@ -4887,6 +4915,16 @@ print_gnat_stuff (struct type *type, int spaces)
}
}
/* Print the contents of the TYPE's type_specific union, assuming that
its type-specific kind is TYPE_SPECIFIC_FIXED_POINT. */
static void
print_fixed_point_type_info (struct type *type, int spaces)
{
printfi_filtered (spaces + 2, "scaling factor: %s\n",
fixed_point_scaling_factor (type).str ().get ());
}
static struct obstack dont_print_type_obstack;
/* Print the dynamic_prop PROP. */
@@ -5025,6 +5063,9 @@ recursive_dump_type (struct type *type, int spaces)
case TYPE_CODE_NAMESPACE:
printf_filtered ("(TYPE_CODE_NAMESPACE)");
break;
case TYPE_CODE_FIXED_POINT:
printf_filtered ("(TYPE_CODE_FIXED_POINT)");
break;
default:
printf_filtered ("(UNKNOWN TYPE CODE)");
break;
@@ -5217,6 +5258,12 @@ recursive_dump_type (struct type *type, int spaces)
puts_filtered ("\n");
break;
case TYPE_SPECIFIC_FIXED_POINT:
printfi_filtered (spaces, "fixed_point_info ");
print_fixed_point_type_info (type, spaces);
puts_filtered ("\n");
break;
case TYPE_SPECIFIC_INT:
if (type->bit_size_differs_p ())
{
@@ -5449,6 +5496,11 @@ copy_type_recursive (struct objfile *objfile,
copy_type_recursive (objfile, TYPE_SELF_TYPE (type),
copied_types));
break;
case TYPE_SPECIFIC_FIXED_POINT:
INIT_FIXED_POINT_SPECIFIC (new_type);
TYPE_FIXED_POINT_INFO (new_type)->scaling_factor
= TYPE_FIXED_POINT_INFO (type)->scaling_factor;
break;
case TYPE_SPECIFIC_INT:
TYPE_SPECIFIC_FIELD (new_type) = TYPE_SPECIFIC_INT;
TYPE_MAIN_TYPE (new_type)->type_specific.int_stuff
@@ -5752,6 +5804,85 @@ append_composite_type_field (struct type *t, const char *name,
append_composite_type_field_aligned (t, name, field, 0);
}
/* We manage the lifetimes of fixed_point_type_info objects by
attaching them to the objfile. Currently, these objects are
modified during construction, and GMP does not provide a way to
hash the contents of an mpq_t; so it's a bit of a pain to hash-cons
them. If we did do this, they could be moved to the per-BFD and
shared across objfiles. */
typedef std::vector<std::unique_ptr<fixed_point_type_info>>
fixed_point_type_storage;
/* Key used for managing the storage of fixed-point type info. */
static const struct objfile_key<fixed_point_type_storage>
fixed_point_objfile_key;
/* See gdbtypes.h. */
fixed_point_type_info *
allocate_fixed_point_type_info (struct type *type)
{
std::unique_ptr<fixed_point_type_info> up (new fixed_point_type_info);
fixed_point_type_info *result;
if (TYPE_OBJFILE_OWNED (type))
{
fixed_point_type_storage *storage
= fixed_point_objfile_key.get (TYPE_OBJFILE (type));
if (storage == nullptr)
storage = fixed_point_objfile_key.emplace (TYPE_OBJFILE (type));
result = up.get ();
storage->push_back (std::move (up));
}
else
{
/* We just leak the memory, because that's what we do generally
for non-objfile-attached types. */
result = up.release ();
}
return result;
}
/* See gdbtypes.h. */
bool
is_fixed_point_type (struct type *type)
{
while (check_typedef (type)->code () == TYPE_CODE_RANGE)
type = TYPE_TARGET_TYPE (check_typedef (type));
type = check_typedef (type);
return type->code () == TYPE_CODE_FIXED_POINT;
}
/* See gdbtypes.h. */
struct type *
fixed_point_type_base_type (struct type *type)
{
while (check_typedef (type)->code () == TYPE_CODE_RANGE)
type = TYPE_TARGET_TYPE (check_typedef (type));
type = check_typedef (type);
gdb_assert (type->code () == TYPE_CODE_FIXED_POINT);
return type;
}
/* See gdbtypes.h. */
const gdb_mpq &
fixed_point_scaling_factor (struct type *type)
{
type = fixed_point_type_base_type (type);
return TYPE_FIXED_POINT_INFO (type)->scaling_factor;
}
static struct gdbarch_data *gdbtypes_data;
const struct builtin_type *