From 14c09924a070918034b465b8ca78282afee62839 Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Wed, 9 Dec 2020 13:52:03 -0500 Subject: [PATCH] gdb: split get_discrete_bounds in two get_discrete_bounds is not flexible for ranges (TYPE_CODE_RANGE), in the sense that it returns true (success) only if both bounds are present and constant values. This is a problem for code that only needs to know the low bound and fails unnecessarily if the high bound is unknown. Split the function in two, get_discrete_low_bound and get_discrete_high_bound, that both return an optional. Provide a new implementation of get_discrete_bounds based on the two others, so the callers don't have to be changed. gdb/ChangeLog: * gdbtypes.c (get_discrete_bounds): Implement with get_discrete_low_bound and get_discrete_high_bound. (get_discrete_low_bound): New. (get_discrete_high_bound): New. Change-Id: I986b5e9c0dd969800e3fb9546af9c827d52e80d0 --- gdb/ChangeLog | 7 ++ gdb/gdbtypes.c | 187 ++++++++++++++++++++++++++++++++++--------------- 2 files changed, 137 insertions(+), 57 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index e7f083ca58..3b022c1813 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +2020-12-09 Simon Marchi + + * gdbtypes.c (get_discrete_bounds): Implement with + get_discrete_low_bound and get_discrete_high_bound. + (get_discrete_low_bound): New. + (get_discrete_high_bound): New. + 2020-12-09 Simon Marchi * gdbtypes.h (get_discrete_bounds): Return bool, adjust all diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index f1b19b58aa..367ca5f311 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -1036,71 +1036,127 @@ has_static_range (const struct range_bounds *bounds) && bounds->stride.kind () == PROP_CONST); } -/* See gdbtypes.h. */ +/* If TYPE's low bound is a known constant, return it, else return nullopt. */ -bool -get_discrete_bounds (struct type *type, LONGEST *lowp, LONGEST *highp) +static gdb::optional +get_discrete_low_bound (struct type *type) { type = check_typedef (type); switch (type->code ()) { case TYPE_CODE_RANGE: - /* This function currently only works for ranges with two defined, - constant bounds. */ - if (type->bounds ()->low.kind () != PROP_CONST - || type->bounds ()->high.kind () != PROP_CONST) + { + /* This function only works for ranges with a constant low bound. */ + if (type->bounds ()->low.kind () != PROP_CONST) + return {}; + + LONGEST low = type->bounds ()->low.const_val (); + + if (TYPE_TARGET_TYPE (type)->code () == TYPE_CODE_ENUM) + { + gdb::optional low_pos + = discrete_position (TYPE_TARGET_TYPE (type), low); + + if (low_pos.has_value ()) + low = *low_pos; + } + + return low; + } + + case TYPE_CODE_ENUM: + { + if (type->num_fields () > 0) + { + /* The enums may not be sorted by value, so search all + entries. */ + LONGEST low = TYPE_FIELD_ENUMVAL (type, 0); + + for (int i = 0; i < type->num_fields (); i++) + { + if (TYPE_FIELD_ENUMVAL (type, i) < low) + low = TYPE_FIELD_ENUMVAL (type, i); + } + + /* Set unsigned indicator if warranted. */ + if (low >= 0) + type->set_is_unsigned (true); + + return low; + } + else + return 0; + } + + case TYPE_CODE_BOOL: + return 0; + + case TYPE_CODE_INT: + if (TYPE_LENGTH (type) > sizeof (LONGEST)) /* Too big */ return false; - *lowp = type->bounds ()->low.const_val (); - *highp = type->bounds ()->high.const_val (); + if (!type->is_unsigned ()) + return -(1 << (TYPE_LENGTH (type) * TARGET_CHAR_BIT - 1)); - if (TYPE_TARGET_TYPE (type)->code () == TYPE_CODE_ENUM) - { - gdb::optional low_pos - = discrete_position (TYPE_TARGET_TYPE (type), *lowp); + /* fall through */ + case TYPE_CODE_CHAR: + return 0; - if (low_pos.has_value ()) - *lowp = *low_pos; + default: + return false; + } +} - gdb::optional high_pos - = discrete_position (TYPE_TARGET_TYPE (type), *highp); +/* If TYPE's high bound is a known constant, return it, else return nullopt. */ - if (high_pos.has_value ()) - *highp = *high_pos; - } - return true; +static gdb::optional +get_discrete_high_bound (struct type *type) +{ + type = check_typedef (type); + switch (type->code ()) + { + case TYPE_CODE_RANGE: + { + /* This function only works for ranges with a constant high bound. */ + if (type->bounds ()->high.kind () != PROP_CONST) + return {}; + + LONGEST high = type->bounds ()->high.const_val (); + + if (TYPE_TARGET_TYPE (type)->code () == TYPE_CODE_ENUM) + { + gdb::optional high_pos + = discrete_position (TYPE_TARGET_TYPE (type), high); + + if (high_pos.has_value ()) + high = *high_pos; + } + + return high; + } case TYPE_CODE_ENUM: - if (type->num_fields () > 0) - { - /* The enums may not be sorted by value, so search all - entries. */ - int i; + { + if (type->num_fields () > 0) + { + /* The enums may not be sorted by value, so search all + entries. */ + LONGEST high = TYPE_FIELD_ENUMVAL (type, 0); - *lowp = *highp = TYPE_FIELD_ENUMVAL (type, 0); - for (i = 0; i < type->num_fields (); i++) - { - if (TYPE_FIELD_ENUMVAL (type, i) < *lowp) - *lowp = TYPE_FIELD_ENUMVAL (type, i); - if (TYPE_FIELD_ENUMVAL (type, i) > *highp) - *highp = TYPE_FIELD_ENUMVAL (type, i); - } + for (int i = 0; i < type->num_fields (); i++) + { + if (TYPE_FIELD_ENUMVAL (type, i) > high) + high = TYPE_FIELD_ENUMVAL (type, i); + } - /* Set unsigned indicator if warranted. */ - if (*lowp >= 0) - type->set_is_unsigned (true); - } - else - { - *lowp = 0; - *highp = -1; - } - return true; + return high; + } + else + return -1; + } case TYPE_CODE_BOOL: - *lowp = 0; - *highp = 1; - return true; + return 1; case TYPE_CODE_INT: if (TYPE_LENGTH (type) > sizeof (LONGEST)) /* Too big */ @@ -1108,25 +1164,42 @@ get_discrete_bounds (struct type *type, LONGEST *lowp, LONGEST *highp) if (!type->is_unsigned ()) { - *lowp = -(1 << (TYPE_LENGTH (type) * TARGET_CHAR_BIT - 1)); - *highp = -*lowp - 1; - return true; + LONGEST low = -(1 << (TYPE_LENGTH (type) * TARGET_CHAR_BIT - 1)); + return -low - 1; } + /* fall through */ case TYPE_CODE_CHAR: - *lowp = 0; - /* This round-about calculation is to avoid shifting by - TYPE_LENGTH (type) * TARGET_CHAR_BIT, which will not work - if TYPE_LENGTH (type) == sizeof (LONGEST). */ - *highp = 1 << (TYPE_LENGTH (type) * TARGET_CHAR_BIT - 1); - *highp = (*highp - 1) | *highp; - return true; + { + /* This round-about calculation is to avoid shifting by + TYPE_LENGTH (type) * TARGET_CHAR_BIT, which will not work + if TYPE_LENGTH (type) == sizeof (LONGEST). */ + LONGEST high = 1 << (TYPE_LENGTH (type) * TARGET_CHAR_BIT - 1); + return (high - 1) | high; + } default: return false; } } +/* See gdbtypes.h. */ + +bool +get_discrete_bounds (struct type *type, LONGEST *lowp, LONGEST *highp) +{ + gdb::optional low = get_discrete_low_bound (type); + gdb::optional high = get_discrete_high_bound (type); + + if (!low.has_value () || !high.has_value ()) + return false; + + *lowp = *low; + *highp = *high; + + return true; +} + /* See gdbtypes.h */ bool -- 2.34.1