[RFC/RFA] print arrays with indexes

Joel Brobecker
2005-09-06T20:20:30Z

[-- Attachment #1: Type: text/plain, Size: 2864 bytes --]

Hello,

This is a suggestion to enhance GDB when printing arrays. The idea is
that the default and currently only way for GDB to print arrays is to
print them as a sequence of elements, separated by a coma, like this:

(gdb) p array
$1 = {1, 2, 3, 4}

The idea is that, for large arrays, it's sometimes convenient to print
them in a form where the index of each element is printed prior to the
array element itself. In Ada, the notation for doing is

<index> => <array element>

So, the idea would be for GDB to print the above array as:

(gdb) p array
$2 = {0 => 1, 1 => 2, 2 => 3, 3 => 4}

For my personal usage, I find this to be very convenient when dealing
with super large arrays such as the regnum-to-regname arrays that we
frequently have in GDB. I'm always concerned about being off by one
when counting. Having the index simplifies the process a little bit.

So, the suggestion is to have the feature being controled by a set/show
command; I suggest:

(gdb) set/show print array-indexes

With a default of "off", to preserve the current behavior.

For the moment, the patch I am submitting here is using the Ada notation,
because C/C++/ObjC don't provide this way of "qualifying" each element.
Not sure about Fortran or Pascal. We can certainly make this a language
method, with a default method.

Testcase and documentation will come shortly after we've agreed on
the principle and the design.

2005-09-06 Joel Brobecker <brobecker@adacore.com>

* valprint.c (print_array_indexes): New variable.
(show_print_array_indexes): New function.
(print_array_indexes_p): New function.
(maybe_print_array_index): New function.
(val_print_array_elements): Add new parameter real_index_offset.
Print the index of each element if required by the user.
(_initialize_valprint): Add new print-array-indexes set/show command.
* valprint.h (print_array_indexes_p): Add declaration.
(maybe_print_array_index): Likewise.
(val_print_array_elements): Update parameter list.
* c-valprint.c (c_val_print): Update call to val_print_array_elements.
* p-valprint.c (pascal_val_print): Likewise.
* ada-valprint.c (ada_get_array_low_bound_and_type): New function,
mostly extracted from print_optional_low_bound().
(print_optional_low_bound): Replace extracted code by call to
ada_get_array_low_bound_and_type(). Stop printing the low bound
if indexes will be printed for all elements of the array.
(val_print_packed_array_elements): Print the index of each element
of the array if necessary.
(ada_val_print_1): For non-packed arrays, compute the array low
bound, and pass it to val_print_array_elements().

Tested on x86-linux, no regression.

Opinions?
--
Joel

[-- Attachment #2: indexes.diff --]
[-- Type: text/plain, Size: 9749 bytes --]

Index: valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/valprint.c,v
retrieving revision 1.54
diff -u -p -r1.54 valprint.c
--- valprint.c 10 Jun 2005 06:07:32 -0000 1.54
+++ valprint.c 6 Sep 2005 20:18:00 -0000
@@ -100,6 +100,17 @@ Default output radix for printing of val
}
int output_format = 0;

+/* By default we print arrays without printing the index of each element in
+ the array. This behavior can be changed by setting PRINT_ARRAY_INDEXES. */
+
+static int print_array_indexes = 0;
+static void
+show_print_array_indexes (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("Printing of array indexes is %s.\n"), value);
+}
+
/* Print repeat counts if there are more than this many repetitions of an
element in an array. Referenced by the low level language dependent
print routines. */
@@ -859,9 +870,42 @@ print_char_chars (struct ui_file *stream
}
}

+/* Return non-zero if the debugger should print the index of each element
+ when printing array values. */
+
+int
+print_array_indexes_p (void)
+{
+ return print_array_indexes;
+}
+
+/* Print on STREAM using the given FORMAT the index for the element
+ at INDEX of an array whose index type is INDEX_TYPE. */
+
+void
+maybe_print_array_index (struct type *index_type, LONGEST index,
+ struct ui_file *stream, int format,
+ enum val_prettyprint pretty)
+{
+ struct value *index_value;
+
+ if (!print_array_indexes)
+ return;
+
+ index_value = value_from_longest (index_type, index);
+
+ LA_VALUE_PRINT (index_value, stream, format, pretty);
+ fprintf_filtered (stream, " => ");
+}
+
/* Called by various <lang>_val_print routines to print elements of an
array in the form "<elem1>, <elem2>, <elem3>, ...".

+ Some languages such as Ada allow the user to specify arrays where
+ the index of the first element is not zero. REAL_INDEX_OFFSET is
+ the user-level index of the first element of the array. For many
+ languages such as C or C++, it is always zero.
+
(FIXME?) Assumes array element separator is a comma, which is correct
for all languages currently handled.
(FIXME?) Some languages have a notation for repeated array elements,
@@ -873,11 +917,11 @@ val_print_array_elements (struct type *t
CORE_ADDR address, struct ui_file *stream,
int format, int deref_ref,
int recurse, enum val_prettyprint pretty,
- unsigned int i)
+ unsigned int i, LONGEST real_index_offset)
{
unsigned int things_printed = 0;
unsigned len;
- struct type *elttype;
+ struct type *elttype, *index_type;
unsigned eltlen;
/* Position of the array element we are examining to see
whether it is repeated. */
@@ -888,6 +932,7 @@ val_print_array_elements (struct type *t
elttype = TYPE_TARGET_TYPE (type);
eltlen = TYPE_LENGTH (check_typedef (elttype));
len = TYPE_LENGTH (type) / eltlen;
+ index_type = TYPE_INDEX_TYPE (type);

annotate_array_section_begin (i, elttype);

@@ -906,6 +951,8 @@ val_print_array_elements (struct type *t
}
}
wrap_here (n_spaces (2 + 2 * recurse));
+ maybe_print_array_index (index_type, i + real_index_offset,
+ stream, format, pretty);

rep1 = i + 1;
reps = 1;
@@ -1396,6 +1443,12 @@ Show the default input and output number
Use 'show input-radix' or 'show output-radix' to independently show each."),
&showlist);

+ add_setshow_boolean_cmd ("array-indexes", class_support,
+ &print_array_indexes, _("\
+Set printing of array indexes."), _("\
+Show printing of array indexes"), NULL, NULL, show_print_array_indexes,
+ &setprintlist, &showprintlist);
+
/* Give people the defaults which they are used to. */
prettyprint_structs = 0;
prettyprint_arrays = 0;
Index: valprint.h
===================================================================
RCS file: /cvs/src/src/gdb/valprint.h,v
retrieving revision 1.10
diff -u -p -r1.10 valprint.h
--- valprint.h 9 May 2005 21:20:35 -0000 1.10
+++ valprint.h 6 Sep 2005 20:18:00 -0000
@@ -50,10 +50,16 @@ extern int output_format;

extern int stop_print_at_null; /* Stop printing at null char? */

+extern int print_array_indexes_p (void);
+
+extern void maybe_print_array_index (struct type *index_type, LONGEST index,
+ struct ui_file *stream, int format,
+ enum val_prettyprint pretty);
+
extern void val_print_array_elements (struct type *, const gdb_byte *,
CORE_ADDR, struct ui_file *, int,
int, int, enum val_prettyprint,
- unsigned int);
+ unsigned int, LONGEST);

extern void val_print_type_code_int (struct type *, const gdb_byte *,
struct ui_file *);
Index: c-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/c-valprint.c,v
retrieving revision 1.37
diff -u -p -r1.37 c-valprint.c
--- c-valprint.c 9 May 2005 21:20:30 -0000 1.37
+++ c-valprint.c 6 Sep 2005 20:18:00 -0000
@@ -133,7 +133,7 @@ c_val_print (struct type *type, const gd
i = 0;
}
val_print_array_elements (type, valaddr + embedded_offset, address, stream,
- format, deref_ref, recurse, pretty, i);
+ format, deref_ref, recurse, pretty, i, 0);
fprintf_filtered (stream, "}");
}
break;
Index: ada-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/ada-valprint.c,v
retrieving revision 1.23
diff -u -p -r1.23 ada-valprint.c
--- ada-valprint.c 9 May 2005 21:20:30 -0000 1.23
+++ ada-valprint.c 6 Sep 2005 20:18:00 -0000
@@ -75,6 +75,44 @@ adjust_type_signedness (struct type *typ
TYPE_FLAGS (type) |= TYPE_FLAG_UNSIGNED;
}

+/* Assuming TYPE is a simple, non-empty array type, compute the lower
+ bound and the array index type. Save the low bound into LOW_BOUND
+ if not NULL. Save the index type in INDEX_TYPE if not NULL.
+
+ Return 1 if the operation was successful. Return zero otherwise,
+ in which case the value of LOW_BOUND and INDEX_TYPE is undefined. */
+
+static int
+ada_get_array_low_bound_and_type (struct type *type,
+ long *low_bound,
+ struct type **index_type)
+{
+ struct type *index = TYPE_INDEX_TYPE (type);
+ long low = 0;
+
+ if (index == NULL)
+ return 0;
+
+ if (TYPE_CODE (index) != TYPE_CODE_RANGE
+ && TYPE_CODE (index) != TYPE_CODE_ENUM)
+ return 0;
+
+ low = TYPE_LOW_BOUND (index);
+ if (low > TYPE_HIGH_BOUND (index))
+ return 0;
+
+ if (TYPE_CODE (index) == TYPE_CODE_RANGE)
+ index = TYPE_TARGET_TYPE (index);
+
+ if (low_bound)
+ *low_bound = low;
+
+ if (index_type)
+ *index_type = index;
+
+ return 1;
+}
+
/* Assuming TYPE is a simple, non-empty array type, prints its lower bound
on STREAM, if non-standard (i.e., other than 1 for numbers, other
than lower bound of index type for enumerated type). Returns 1
@@ -86,19 +124,10 @@ print_optional_low_bound (struct ui_file
struct type *index_type;
long low_bound;

- index_type = TYPE_INDEX_TYPE (type);
- low_bound = 0;
-
- if (index_type == NULL)
+ if (print_array_indexes_p ())
return 0;
- if (TYPE_CODE (index_type) == TYPE_CODE_RANGE)
- {
- low_bound = TYPE_LOW_BOUND (index_type);
- if (low_bound > TYPE_HIGH_BOUND (index_type))
- return 0;
- index_type = TYPE_TARGET_TYPE (index_type);
- }
- else
+
+ if (!ada_get_array_low_bound_and_type (type, &low_bound, &index_type))
return 0;

switch (TYPE_CODE (index_type))
@@ -137,16 +166,18 @@ val_print_packed_array_elements (struct
unsigned int i;
unsigned int things_printed = 0;
unsigned len;
- struct type *elttype;
+ struct type *elttype, *index_type;
unsigned eltlen;
unsigned long bitsize = TYPE_FIELD_BITSIZE (type, 0);
struct value *mark = value_mark ();
+ LONGEST low = 0;

elttype = TYPE_TARGET_TYPE (type);
eltlen = TYPE_LENGTH (check_typedef (elttype));
+ index_type = TYPE_INDEX_TYPE (type);

{
- LONGEST low, high;
+ LONGEST high;
if (get_discrete_bounds (TYPE_FIELD_TYPE (type, 0), &low, &high) < 0)
len = 1;
else
@@ -174,6 +205,7 @@ val_print_packed_array_elements (struct
}
}
wrap_here (n_spaces (2 + 2 * recurse));
+ maybe_print_array_index (index_type, i + low, stream, format, pretty);

i0 = i;
v0 = ada_value_primitive_packed_val (NULL, valaddr,
@@ -219,6 +251,8 @@ val_print_packed_array_elements (struct
fprintf_filtered (stream, ", ");
}
wrap_here (n_spaces (2 + 2 * recurse));
+ maybe_print_array_index (index_type, j + low,
+ stream, format, pretty);
}
val_print (elttype, value_contents (v0), 0, 0, stream, format,
0, recurse + 1, pretty);
@@ -824,7 +858,11 @@ ada_val_print_1 (struct type *type, cons
}
else
{
+ long low_bound = 0;
+
len = 0;
+ ada_get_array_low_bound_and_type (type, &low_bound, NULL);
+
fprintf_filtered (stream, "(");
print_optional_low_bound (stream, type);
if (TYPE_FIELD_BITSIZE (type, 0) > 0)
@@ -833,7 +871,7 @@ ada_val_print_1 (struct type *type, cons
else
val_print_array_elements (type, valaddr, address, stream,
format, deref_ref, recurse,
- pretty, 0);
+ pretty, 0, low_bound);
fprintf_filtered (stream, ")");
}
gdb_flush (stream);