This is the mail archive of the gdb-cvs@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb] Array indexed by non-contiguous enumeration types


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=aa7151351ed16c5a4eb1334c9a1af1b06dbb7a99

commit aa7151351ed16c5a4eb1334c9a1af1b06dbb7a99
Author: Jerome Guitton <guitton@adacore.com>
Date:   Fri Mar 27 14:45:08 2015 +0100

    Array indexed by non-contiguous enumeration types
    
    In Ada, index types of arrays can be enumeration types, and enumeration
    types can be non-contiguous. In which case the address of elements is
    not given by the value of the index, but by its position in the enumeration
    type.
    
    In other words, in this example:
    
     type Color is (Blue, Red);
     for Color use (Blue => 8, Red => 12, Green => 16);
    
     type A is array (Color) of Integer;
     type B is array (1 .. 3) of Integer;
    
    Arrays of type A and B will have the same layout in memory, even if
    the enumeration Color has a hole in its set of integer value.
    
    Since recently support for such a feature was in ada-lang.c, where the
    array was casted to a regular continuous index range. We were losing
    the information of index type. And this was not quite working for
    subranges in variable-length fields; their bounds are expressed using
    the integer value of the bounds, not its position in the enumeration,
    and there was some confusion all over ada-lang.c as to whether we had
    the position or the integer value was used for indexes.
    
    The idea behind this patch is to clean this up by keeping the real
    representation of these array index types and bounds when representing
    the value, and only use the position when accessing the elements or
    computing the length. This first patch fixes the printing of such
    an array.
    
    To the best of my knowledge, this feature only exists in Ada so it
    should only affect this language.
    
    gdb/ChangeLog:
    
            Jerome Guitton  <guitton@adacore.com>:
            * ada-lang.c (ada_value_ptr_subscript): Use enum position of
            index to get element instead of enum value.
            (ada_value_slice_from_ptr, ada_value_slice): Use enum position
            of index to compute length, but enum values to compute bounds.
            (ada_array_length): Use enum position of index instead of enum value.
            (pos_atr): Move position computation to...
            (ada_evaluate_subexp): Use enum values to compute bounds.
            * gdbtypes.c (discrete_position): ...this new function.
            * gdbtypes.h (discrete_position): New function declaration.
            * valprint.c (val_print_array_elements): Call discrete_position
            to handle array indexed by non-contiguous enumeration types.
    
    gdb/testsuite/ChangeLog:
    
            * gdb.ada/arr_enum_with_gap: New testcase.

Diff:
---
 gdb/ChangeLog           | 14 ++++++++
 gdb/ada-lang.c          | 96 +++++++++++++++++++++++++++++++++----------------
 gdb/gdbtypes.c          | 39 ++++++++++++++++++++
 gdb/gdbtypes.h          |  2 ++
 gdb/testsuite/ChangeLog |  4 +++
 gdb/valprint.c          | 29 ++++++++++++---
 6 files changed, 148 insertions(+), 36 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index c1dc2d0..711f6a8 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,19 @@
 2015-05-15  Jerome Guitton  <guitton@adacore.com>
 
+	* ada-lang.c (ada_value_ptr_subscript): Use enum position of
+	index to get element instead of enum value.
+	(ada_value_slice_from_ptr, ada_value_slice): Use enum position
+	of index to compute length, but enum values to compute bounds.
+	(ada_array_length): Use enum position of index instead of enum value.
+	(pos_atr): Move position computation to...
+	(ada_evaluate_subexp): Use enum values to compute bounds.
+	* gdbtypes.c (discrete_position): ...this new function.
+	* gdbtypes.h (discrete_position): New function declaration.
+	* valprint.c (val_print_array_elements): Call discrete_position
+	to handle array indexed by non-contiguous enumeration types.
+
+2015-05-15  Jerome Guitton  <guitton@adacore.com>
+
 	* ada-lang.c (find_parallel_type_by_descriptive_type):
 	Go through typedefs during lookup.
 	(to_fixed_array_type): Add support for non-bit packed arrays
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 02d82ef..f789108 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -2765,13 +2765,15 @@ ada_value_ptr_subscript (struct value *arr, int arity, struct value **ind)
   for (k = 0; k < arity; k += 1)
     {
       LONGEST lwb, upb;
+      struct value *lwb_value;
 
       if (TYPE_CODE (type) != TYPE_CODE_ARRAY)
         error (_("too many subscripts (%d expected)"), k);
       arr = value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
                         value_copy (arr));
       get_discrete_bounds (TYPE_INDEX_TYPE (type), &lwb, &upb);
-      arr = value_ptradd (arr, pos_atr (ind[k]) - lwb);
+      lwb_value = value_from_longest (value_type(ind[k]), lwb);
+      arr = value_ptradd (arr, pos_atr (ind[k]) - pos_atr (lwb_value));
       type = TYPE_TARGET_TYPE (type);
     }
 
@@ -2779,24 +2781,34 @@ ada_value_ptr_subscript (struct value *arr, int arity, struct value **ind)
 }
 
 /* Given that ARRAY_PTR is a pointer or reference to an array of type TYPE (the
-   actual type of ARRAY_PTR is ignored), returns the Ada slice of HIGH-LOW+1
-   elements starting at index LOW.  The lower bound of this array is LOW, as
-   per Ada rules.  */
+   actual type of ARRAY_PTR is ignored), returns the Ada slice of
+   HIGH'Pos-LOW'Pos+1 elements starting at index LOW.  The lower bound of
+   this array is LOW, as per Ada rules.  */
 static struct value *
 ada_value_slice_from_ptr (struct value *array_ptr, struct type *type,
                           int low, int high)
 {
   struct type *type0 = ada_check_typedef (type);
-  CORE_ADDR base = value_as_address (array_ptr)
-    + ((low - ada_discrete_type_low_bound (TYPE_INDEX_TYPE (type0)))
-       * TYPE_LENGTH (TYPE_TARGET_TYPE (type0)));
+  struct type *base_index_type = TYPE_TARGET_TYPE (TYPE_INDEX_TYPE (type0));
   struct type *index_type
-    = create_static_range_type (NULL,
-				TYPE_TARGET_TYPE (TYPE_INDEX_TYPE (type0)),
-				low, high);
+    = create_static_range_type (NULL, base_index_type, low, high);
   struct type *slice_type =
     create_array_type (NULL, TYPE_TARGET_TYPE (type0), index_type);
+  int base_low =  ada_discrete_type_low_bound (TYPE_INDEX_TYPE (type0));
+  LONGEST base_low_pos, low_pos;
+  CORE_ADDR base;
+
+  if (!discrete_position (base_index_type, low, &low_pos)
+      || !discrete_position (base_index_type, base_low, &base_low_pos))
+    {
+      warning (_("unable to get positions in slice, use bounds instead"));
+      low_pos = low;
+      base_low_pos = base_low;
+    }
 
+  base = value_as_address (array_ptr)
+    + ((low_pos - base_low_pos)
+       * TYPE_LENGTH (TYPE_TARGET_TYPE (type0)));
   return value_at_lazy (slice_type, base);
 }
 
@@ -2805,12 +2817,23 @@ static struct value *
 ada_value_slice (struct value *array, int low, int high)
 {
   struct type *type = ada_check_typedef (value_type (array));
+  struct type *base_index_type = TYPE_TARGET_TYPE (TYPE_INDEX_TYPE (type));
   struct type *index_type
     = create_static_range_type (NULL, TYPE_INDEX_TYPE (type), low, high);
   struct type *slice_type =
     create_array_type (NULL, TYPE_TARGET_TYPE (type), index_type);
+  LONGEST low_pos, high_pos;
 
-  return value_cast (slice_type, value_slice (array, low, high - low + 1));
+  if (!discrete_position (base_index_type, low, &low_pos)
+      || !discrete_position (base_index_type, high, &high_pos))
+    {
+      warning (_("unable to get positions in slice, use bounds instead"));
+      low_pos = low;
+      high_pos = high;
+    }
+
+  return value_cast (slice_type,
+		     value_slice (array, low, high_pos - low_pos + 1));
 }
 
 /* If type is a record type in the form of a standard GNAT array
@@ -3012,7 +3035,8 @@ ada_array_bound (struct value *arr, int n, int which)
 static LONGEST
 ada_array_length (struct value *arr, int n)
 {
-  struct type *arr_type;
+  struct type *arr_type, *index_type;
+  int low, high;
 
   if (TYPE_CODE (check_typedef (value_type (arr))) == TYPE_CODE_PTR)
     arr = value_ind (arr);
@@ -3022,11 +3046,30 @@ ada_array_length (struct value *arr, int n)
     return ada_array_length (decode_constrained_packed_array (arr), n);
 
   if (ada_is_simple_array_type (arr_type))
-    return (ada_array_bound_from_type (arr_type, n, 1)
-	    - ada_array_bound_from_type (arr_type, n, 0) + 1);
+    {
+      low = ada_array_bound_from_type (arr_type, n, 0);
+      high = ada_array_bound_from_type (arr_type, n, 1);
+    }
   else
-    return (value_as_long (desc_one_bound (desc_bounds (arr), n, 1))
-	    - value_as_long (desc_one_bound (desc_bounds (arr), n, 0)) + 1);
+    {
+      low = value_as_long (desc_one_bound (desc_bounds (arr), n, 0));
+      high = value_as_long (desc_one_bound (desc_bounds (arr), n, 1));
+    }
+
+  CHECK_TYPEDEF (arr_type);
+  index_type = TYPE_INDEX_TYPE (arr_type);
+  if (index_type != NULL)
+    {
+      struct type *base_type;
+      if (TYPE_CODE (index_type) == TYPE_CODE_RANGE)
+	base_type = TYPE_TARGET_TYPE (index_type);
+      else
+	base_type = index_type;
+
+      low = pos_atr (value_from_longest (base_type, low));
+      high = pos_atr (value_from_longest (base_type, high));
+    }
+  return high - low + 1;
 }
 
 /* An empty array whose type is that of ARR_TYPE (an array type),
@@ -8995,24 +9038,15 @@ pos_atr (struct value *arg)
 {
   struct value *val = coerce_ref (arg);
   struct type *type = value_type (val);
+  LONGEST result;
 
   if (!discrete_type_p (type))
     error (_("'POS only defined on discrete types"));
 
-  if (TYPE_CODE (type) == TYPE_CODE_ENUM)
-    {
-      int i;
-      LONGEST v = value_as_long (val);
+  if (!discrete_position (type, value_as_long (val), &result))
+    error (_("enumeration value is invalid: can't find 'POS"));
 
-      for (i = 0; i < TYPE_NFIELDS (type); i += 1)
-        {
-          if (v == TYPE_FIELD_ENUMVAL (type, i))
-            return i;
-        }
-      error (_("enumeration value is invalid: can't find 'POS"));
-    }
-  else
-    return value_as_long (val);
+  return result;
 }
 
 static struct value *
@@ -10613,8 +10647,8 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
 
         low_bound_val = coerce_ref (low_bound_val);
         high_bound_val = coerce_ref (high_bound_val);
-        low_bound = pos_atr (low_bound_val);
-        high_bound = pos_atr (high_bound_val);
+        low_bound = value_as_long (low_bound_val);
+        high_bound = value_as_long (high_bound_val);
 
         if (noside == EVAL_SKIP)
           goto nosideret;
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 4bbfc75..ca86fbd 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -1004,6 +1004,45 @@ get_array_bounds (struct type *type, LONGEST *low_bound, LONGEST *high_bound)
   return 1;
 }
 
+/* Assuming that TYPE is a discrete type and VAL is a valid integer
+   representation of a value of this type, save the corresponding
+   position number in POS.
+
+   Its differs from VAL only in the case of enumeration types.  In
+   this case, the position number of the value of the first listed
+   enumeration literal is zero; the position number of the value of
+   each subsequent enumeration literal is one more than that of its
+   predecessor in the list.
+
+   Return 1 if the operation was successful.  Return zero otherwise,
+   in which case the value of POS is unmodified.
+*/
+
+int
+discrete_position (struct type *type, LONGEST val, LONGEST *pos)
+{
+  if (TYPE_CODE (type) == TYPE_CODE_ENUM)
+    {
+      int i;
+
+      for (i = 0; i < TYPE_NFIELDS (type); i += 1)
+        {
+          if (val == TYPE_FIELD_ENUMVAL (type, i))
+	    {
+	      *pos = i;
+	      return 1;
+	    }
+        }
+      /* Invalid enumeration value.  */
+      return 0;
+    }
+  else
+    {
+      *pos = val;
+      return 1;
+    }
+}
+
 /* Create an array type using either a blank type supplied in
    RESULT_TYPE, or creating a new type, inheriting the objfile from
    RANGE_TYPE.
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 4275ee0..fd3bc0e 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1837,6 +1837,8 @@ extern int get_discrete_bounds (struct type *, LONGEST *, LONGEST *);
 extern int get_array_bounds (struct type *type, LONGEST *low_bound,
 			     LONGEST *high_bound);
 
+extern int discrete_position (struct type *type, LONGEST val, LONGEST *pos);
+
 extern int class_types_same_p (const struct type *, const struct type *);
 
 extern int is_ancestor (struct type *, struct type *);
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 74559f4..e14630e 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2015-05-15  Joel Brobecker  <brobecker@adacore.com>
 
+	* gdb.ada/arr_enum_with_gap: New testcase.
+
+2015-05-15  Joel Brobecker  <brobecker@adacore.com>
+
 	* gdb.ada/byte_packed_arr: New testcase.
 
 2015-05-15  Joel Brobecker  <brobecker@adacore.com>
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 9a70b2f..294c6a8 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -1626,7 +1626,7 @@ val_print_array_elements (struct type *type,
 {
   unsigned int things_printed = 0;
   unsigned len;
-  struct type *elttype, *index_type;
+  struct type *elttype, *index_type, *base_index_type;
   unsigned eltlen;
   /* Position of the array element we are examining to see
      whether it is repeated.  */
@@ -1634,6 +1634,7 @@ val_print_array_elements (struct type *type,
   /* Number of repetitions we have detected so far.  */
   unsigned int reps;
   LONGEST low_bound, high_bound;
+  LONGEST low_pos, high_pos;
 
   elttype = TYPE_TARGET_TYPE (type);
   eltlen = TYPE_LENGTH (check_typedef (elttype));
@@ -1641,15 +1642,33 @@ val_print_array_elements (struct type *type,
 
   if (get_array_bounds (type, &low_bound, &high_bound))
     {
-      /* The array length should normally be HIGH_BOUND - LOW_BOUND + 1.
+      if (TYPE_CODE (index_type) == TYPE_CODE_RANGE)
+	base_index_type = TYPE_TARGET_TYPE (index_type);
+      else
+	base_index_type = index_type;
+
+      /* Non-contiguous enumerations types can by used as index types
+	 in some languages (e.g. Ada).  In this case, the array length
+	 shall be computed from the positions of the first and last
+	 literal in the enumeration type, and not from the values
+	 of these literals.  */
+      if (!discrete_position (base_index_type, low_bound, &low_pos)
+	  || !discrete_position (base_index_type, high_bound, &high_pos))
+	{
+	  warning (_("unable to get positions in array, use bounds instead"));
+	  low_pos = low_bound;
+	  high_pos = high_bound;
+	}
+
+      /* The array length should normally be HIGH_POS - LOW_POS + 1.
          But we have to be a little extra careful, because some languages
-	 such as Ada allow LOW_BOUND to be greater than HIGH_BOUND for
+	 such as Ada allow LOW_POS to be greater than HIGH_POS for
 	 empty arrays.  In that situation, the array length is just zero,
 	 not negative!  */
-      if (low_bound > high_bound)
+      if (low_pos > high_pos)
 	len = 0;
       else
-	len = high_bound - low_bound + 1;
+	len = high_pos - low_pos + 1;
     }
   else
     {


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]