aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog30
-rw-r--r--gdb/NEWS9
-rw-r--r--gdb/cp-valprint.c80
-rw-r--r--gdb/doc/ChangeLog8
-rw-r--r--gdb/doc/gdb.texinfo58
-rw-r--r--gdb/doc/guile.texi3
-rw-r--r--gdb/doc/python.texi8
-rw-r--r--gdb/guile/scm-pretty-print.c19
-rw-r--r--gdb/python/py-prettyprint.c15
-rw-r--r--gdb/python/py-value.c7
-rw-r--r--gdb/testsuite/ChangeLog18
-rw-r--r--gdb/testsuite/gdb.base/max-depth.c232
-rw-r--r--gdb/testsuite/gdb.base/max-depth.exp165
-rw-r--r--gdb/testsuite/gdb.fortran/max-depth.exp41
-rw-r--r--gdb/testsuite/gdb.fortran/max-depth.f9042
-rw-r--r--gdb/testsuite/gdb.go/max-depth.exp40
-rw-r--r--gdb/testsuite/gdb.go/max-depth.go41
-rw-r--r--gdb/testsuite/gdb.modula2/max-depth.c45
-rw-r--r--gdb/testsuite/gdb.modula2/max-depth.exp37
-rw-r--r--gdb/testsuite/gdb.python/py-format-string.exp21
-rw-r--r--gdb/testsuite/gdb.python/py-nested-maps.c130
-rw-r--r--gdb/testsuite/gdb.python/py-nested-maps.exp238
-rw-r--r--gdb/testsuite/gdb.python/py-nested-maps.py135
-rw-r--r--gdb/testsuite/lib/gdb.exp30
-rw-r--r--gdb/valprint.c57
-rw-r--r--gdb/valprint.h12
26 files changed, 1485 insertions, 36 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 432eb7b..b2e6f25 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,4 +1,34 @@
2019-04-29 Andrew Burgess <andrew.burgess@embecosm.com>
+ Chris January <chris.january@arm.com>
+ Daniel Everett <daniel.everett@arm.com>
+ Nick Forrington <nick.forrington@arm.com>
+ Richard Bunt <richard.bunt@arm.com>
+
+ * cp-valprint.c (cp_print_value_fields): Allow an additional level
+ of depth when printing anonymous structs or unions.
+ * guile/scm-pretty-print.c (gdbscm_apply_val_pretty_printer):
+ Don't print either the top-level value, or the children if the
+ max-depth is exceeded.
+ (ppscm_print_children): When printing the key of a map, allow one
+ extra level of depth.
+ * python/py-prettyprint.c (gdbpy_apply_val_pretty_printer): Don't
+ print either the top-level value, or the children if the max-depth
+ is exceeded.
+ (print_children): When printing the key of a map, allow one extra
+ level of depth.
+ * python/py-value.c (valpy_format_string): Add max_depth keyword.
+ * valprint.c: (PRINT_MAX_DEPTH_DEFAULT): Define.
+ (user_print_options): Initialise max_depth field.
+ (val_print_scalar_or_string_type_p): New function.
+ (val_print): Check to see if the max depth has been reached.
+ (val_print_check_max_depth): Define new function.
+ (show_print_max_depth): New function.
+ (_initialize_valprint): Add 'print max-depth' option.
+ * valprint.h (struct value_print_options) <max_depth>: New field.
+ (val_print_check_max_depth): Declare new function.
+ * NEWS: Document new feature.
+
+2019-04-29 Andrew Burgess <andrew.burgess@embecosm.com>
* ada-lang.c (ada_language_defn): Initialise new field.
* c-lang.c (c_is_string_type_p): New function.
diff --git a/gdb/NEWS b/gdb/NEWS
index 42b04e9..b21b2cb 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -19,6 +19,15 @@
* Two new convernience functions $_cimag and $_creal that extract the
imaginary and real parts respectively from complex numbers.
+* New commands
+
+set print max-depth
+show print max-depth
+ Allows deeply nested structures to be simplified when printing by
+ replacing deeply nested parts (beyond the max-depth) with ellipses.
+ The default max-depth is 20, but this can be set to unlimited to get
+ the old behavior back.
+
* Python API
** The gdb.Value type has a new method 'format_string' which returns a
diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c
index e883179..ff860df 100644
--- a/gdb/cp-valprint.c
+++ b/gdb/cp-valprint.c
@@ -272,10 +272,23 @@ cp_print_value_fields (struct type *type, struct type *real_type,
current_language->la_language,
DMGL_PARAMS | DMGL_ANSI);
annotate_field_name_end ();
+
+ /* We tweak various options in a few cases below. */
+ value_print_options options_copy = *options;
+ value_print_options *opts = &options_copy;
+
/* Do not print leading '=' in case of anonymous
unions. */
if (strcmp (TYPE_FIELD_NAME (type, i), ""))
fputs_filtered (" = ", stream);
+ else
+ {
+ /* If this is an anonymous field then we want to consider it
+ as though it is at its parent's depth when it comes to the
+ max print depth. */
+ if (opts->max_depth != -1 && opts->max_depth < INT_MAX)
+ ++opts->max_depth;
+ }
annotate_field_value ();
if (!field_is_static (&TYPE_FIELD (type, i))
@@ -299,14 +312,12 @@ cp_print_value_fields (struct type *type, struct type *real_type,
}
else
{
- struct value_print_options opts = *options;
-
- opts.deref_ref = 0;
+ opts->deref_ref = 0;
v = value_field_bitfield (type, i, valaddr, offset, val);
- common_val_print (v, stream, recurse + 1, &opts,
- current_language);
+ common_val_print (v, stream, recurse + 1,
+ opts, current_language);
}
}
else
@@ -333,8 +344,7 @@ cp_print_value_fields (struct type *type, struct type *real_type,
}
cp_print_static_field (TYPE_FIELD_TYPE (type, i),
- v, stream, recurse + 1,
- options);
+ v, stream, recurse + 1, opts);
}
else if (i == vptr_fieldno && type == vptr_basetype)
{
@@ -346,20 +356,18 @@ cp_print_value_fields (struct type *type, struct type *real_type,
CORE_ADDR addr;
addr = extract_typed_address (valaddr + i_offset, i_type);
- print_function_pointer_address (options,
+ print_function_pointer_address (opts,
get_type_arch (type),
addr, stream);
}
}
else
{
- struct value_print_options opts = *options;
-
- opts.deref_ref = 0;
+ opts->deref_ref = 0;
val_print (TYPE_FIELD_TYPE (type, i),
offset + TYPE_FIELD_BITPOS (type, i) / 8,
address,
- stream, recurse + 1, val, &opts,
+ stream, recurse + 1, val, opts,
current_language);
}
}
@@ -575,25 +583,35 @@ cp_print_value (struct type *type, struct type *real_type,
{
int result = 0;
- /* Attempt to run an extension language pretty-printer on the
- baseclass if possible. */
- if (!options->raw)
- result
- = apply_ext_lang_val_pretty_printer (baseclass,
- thisoffset + boffset,
- value_address (base_val),
- stream, recurse,
- base_val, options,
- current_language);
-
- if (!result)
- cp_print_value_fields (baseclass, thistype,
- thisoffset + boffset,
- value_address (base_val),
- stream, recurse, base_val, options,
- ((struct type **)
- obstack_base (&dont_print_vb_obstack)),
- 0);
+ if (options->max_depth > -1
+ && recurse >= options->max_depth)
+ {
+ const struct language_defn *language = current_language;
+ gdb_assert (language->la_struct_too_deep_ellipsis != NULL);
+ fputs_filtered (language->la_struct_too_deep_ellipsis, stream);
+ }
+ else
+ {
+ /* Attempt to run an extension language pretty-printer on the
+ baseclass if possible. */
+ if (!options->raw)
+ result
+ = apply_ext_lang_val_pretty_printer (baseclass,
+ thisoffset + boffset,
+ value_address (base_val),
+ stream, recurse,
+ base_val, options,
+ current_language);
+
+ if (!result)
+ cp_print_value_fields (baseclass, thistype,
+ thisoffset + boffset,
+ value_address (base_val),
+ stream, recurse, base_val, options,
+ ((struct type **)
+ obstack_base (&dont_print_vb_obstack)),
+ 0);
+ }
}
fputs_filtered (", ", stream);
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 3efed67..4166f19 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,11 @@
+2019-04-29 Andrew Burgess <andrew.burgess@embecosm.com>
+
+ * gdb.texinfo (Print Settings): Document 'print max-depth'.
+ * guile.texi (Guile Pretty Printing API): Document that 'print
+ max-depth' can effect the display of a values children.
+ * python.texi (Pretty Printing API): Likewise.
+ (Values From Inferior): Document max_depth keyword.
+
2019-04-27 Philippe Waroquiers <philippe.waroquiers@skynet.be>
* gdb.texinfo (Calling): Document the new
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index cf8333d..2282c80 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -10572,6 +10572,64 @@ is 10.
Display the current threshold for printing repeated identical
elements.
+@item set print max-depth @var{depth}
+@item set print max-depth unlimited
+@cindex printing nested structures
+Set the threshold after which nested structures are replaced with
+ellipsis, this can make visualising deeply nested structures easier.
+
+For example, given this C code
+
+@smallexample
+typedef struct s1 @{ int a; @} s1;
+typedef struct s2 @{ s1 b; @} s2;
+typedef struct s3 @{ s2 c; @} s3;
+typedef struct s4 @{ s3 d; @} s4;
+
+s4 var = @{ @{ @{ @{ 3 @} @} @} @};
+@end smallexample
+
+The following table shows how different values of @var{depth} will
+effect how @code{var} is printed by @value{GDBN}:
+
+@multitable @columnfractions .3 .7
+@headitem @var{depth} setting @tab Result of @samp{p var}
+@item unlimited
+@tab @code{$1 = @{d = @{c = @{b = @{a = 3@}@}@}@}}
+@item @code{0}
+@tab @code{$1 = @{...@}}
+@item @code{1}
+@tab @code{$1 = @{d = @{...@}@}}
+@item @code{2}
+@tab @code{$1 = @{d = @{c = @{...@}@}@}}
+@item @code{3}
+@tab @code{$1 = @{d = @{c = @{b = @{...@}@}@}@}}
+@item @code{4}
+@tab @code{$1 = @{d = @{c = @{b = @{a = 3@}@}@}@}}
+@end multitable
+
+To see the contents of structures that have been hidden the user can
+either increase the print max-depth, or they can print the elements of
+the structure that are visible, for example
+
+@smallexample
+(gdb) set print max-depth 2
+(gdb) p var
+$1 = @{d = @{c = @{...@}@}@}
+(gdb) p var.d
+$2 = @{c = @{b = @{...@}@}@}
+(gdb) p var.d.c
+$3 = @{b = @{a = 3@}@}
+@end smallexample
+
+The pattern used to replace nested structures varies based on
+language, for most languages @code{@{...@}} is used, but Fortran uses
+@code{(...)}.
+
+@item show print max-depth
+Display the current threshold after which nested structures are
+replaces with ellipsis.
+
@item set print null-stop
@cindex @sc{null} elements in arrays
Cause @value{GDBN} to stop printing the characters of an array when the first
diff --git a/gdb/doc/guile.texi b/gdb/doc/guile.texi
index 721338b..f4c29dc 100644
--- a/gdb/doc/guile.texi
+++ b/gdb/doc/guile.texi
@@ -1469,6 +1469,9 @@ object which is convertible to a @value{GDBN} value.
If @var{children} is @code{#f}, @value{GDBN} will act
as though the value has no children.
+
+Children may be hidden from display based on the value of @samp{set
+print max-depth} (@pxref{Print Settings}).
@end table
@end deffn
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 36947de..b47c38d 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -931,6 +931,11 @@ Number of array elements to print, or @code{0} to print an unlimited
number of elements (see @code{set print elements} in @ref{Print
Settings}).
+@item max_depth
+The maximum depth to print for nested structs and unions, or @code{-1}
+to print an unlimited number of elements (see @code{set print
+max-depth} in @ref{Print Settings}).
+
@item repeat_threshold
Set the threshold for suppressing display of repeated array elements, or
@code{0} to represent all elements, even if repeated. (See @code{set
@@ -1365,6 +1370,9 @@ object which is convertible to a @value{GDBN} value.
This method is optional. If it does not exist, @value{GDBN} will act
as though the value has no children.
+
+Children may be hidden from display based on the value of @samp{set
+print max-depth} (@pxref{Print Settings}).
@end defun
@defun pretty_printer.display_hint (self)
diff --git a/gdb/guile/scm-pretty-print.c b/gdb/guile/scm-pretty-print.c
index 656c4bb..630a062 100644
--- a/gdb/guile/scm-pretty-print.c
+++ b/gdb/guile/scm-pretty-print.c
@@ -897,7 +897,18 @@ ppscm_print_children (SCM printer, enum display_hint hint,
ppscm_print_exception_unless_memory_error (except_scm, stream);
break;
}
- common_val_print (value, stream, recurse + 1, options, language);
+ else
+ {
+ /* When printing the key of a map we allow one additional
+ level of depth. This means the key will print before the
+ value does. */
+ struct value_print_options opt = *options;
+ if (is_map && i % 2 == 0
+ && opt.max_depth != -1
+ && opt.max_depth < INT_MAX)
+ ++opt.max_depth;
+ common_val_print (value, stream, recurse + 1, &opt, language);
+ }
}
if (is_map && i % 2 == 0)
@@ -984,6 +995,12 @@ gdbscm_apply_val_pretty_printer (const struct extension_language_defn *extlang,
}
gdb_assert (ppscm_is_pretty_printer_worker (printer));
+ if (val_print_check_max_depth (stream, recurse, options, language))
+ {
+ result = EXT_LANG_RC_OK;
+ goto done;
+ }
+
/* If we are printing a map, we want some special formatting. */
hint = ppscm_get_display_hint_enum (printer);
if (hint == HINT_ERROR)
diff --git a/gdb/python/py-prettyprint.c b/gdb/python/py-prettyprint.c
index 7760cab..fdc520d 100644
--- a/gdb/python/py-prettyprint.c
+++ b/gdb/python/py-prettyprint.c
@@ -517,7 +517,17 @@ print_children (PyObject *printer, const char *hint,
error (_("Error while executing Python code."));
}
else
- common_val_print (value, stream, recurse + 1, options, language);
+ {
+ /* When printing the key of a map we allow one additional
+ level of depth. This means the key will print before the
+ value does. */
+ struct value_print_options opt = *options;
+ if (is_map && i % 2 == 0
+ && opt.max_depth != -1
+ && opt.max_depth < INT_MAX)
+ ++opt.max_depth;
+ common_val_print (value, stream, recurse + 1, &opt, language);
+ }
}
if (is_map && i % 2 == 0)
@@ -590,6 +600,9 @@ gdbpy_apply_val_pretty_printer (const struct extension_language_defn *extlang,
if (printer == Py_None)
return EXT_LANG_RC_NOP;
+ if (val_print_check_max_depth (stream, recurse, options, language))
+ return EXT_LANG_RC_OK;
+
/* If we are printing a map, we want some special formatting. */
gdb::unique_xmalloc_ptr<char> hint (gdbpy_get_display_hint (printer.get ()));
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
index 512e5d02..0ffd0b0 100644
--- a/gdb/python/py-value.c
+++ b/gdb/python/py-value.c
@@ -623,6 +623,7 @@ valpy_format_string (PyObject *self, PyObject *args, PyObject *kw)
"static_members", /* See set print static-members on|off. */
/* C non-bool options. */
"max_elements", /* See set print elements N. */
+ "max_depth", /* See set print max-depth N. */
"repeat_threshold", /* See set print repeats. */
"format", /* The format passed to the print command. */
NULL
@@ -665,7 +666,7 @@ valpy_format_string (PyObject *self, PyObject *args, PyObject *kw)
char *format = NULL;
if (!gdb_PyArg_ParseTupleAndKeywords (args,
kw,
- "|O!O!O!O!O!O!O!O!O!IIs",
+ "|O!O!O!O!O!O!O!O!O!IIIs",
keywords,
&PyBool_Type, &raw_obj,
&PyBool_Type, &pretty_arrays_obj,
@@ -677,6 +678,7 @@ valpy_format_string (PyObject *self, PyObject *args, PyObject *kw)
&PyBool_Type, &actual_objects_obj,
&PyBool_Type, &static_members_obj,
&opts.print_max,
+ &opts.max_depth,
&opts.repeat_count_threshold,
&format))
return NULL;
@@ -702,7 +704,8 @@ valpy_format_string (PyObject *self, PyObject *args, PyObject *kw)
return NULL;
/* Numeric arguments for which 0 means unlimited (which we represent as
- UINT_MAX). */
+ UINT_MAX). Note that the max-depth numeric argument uses -1 as
+ unlimited, and 0 is a valid choice. */
if (opts.print_max == 0)
opts.print_max = UINT_MAX;
if (opts.repeat_count_threshold == 0)
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index b6c3618..6d9ac5a 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,21 @@
+2019-04-29 Andrew Burgess <andrew.burgess@embecosm.com>
+ Richard Bunt <richard.bunt@arm.com>
+
+ * gdb.base/max-depth.c: New file.
+ * gdb.base/max-depth.exp: New file.
+ * gdb.python/py-nested-maps.c: New file.
+ * gdb.python/py-nested-maps.exp: New file.
+ * gdb.python/py-nested-maps.py: New file.
+ * gdb.python/py-format-string.exp (test_max_depth): New proc.
+ (test_all_common): Call test_max_depth.
+ * gdb.fortran/max-depth.exp: New file.
+ * gdb.fortran/max-depth.f90: New file.
+ * gdb.go/max-depth.exp: New file.
+ * gdb.go/max-depth.go: New file.
+ * gdb.modula2/max-depth.exp: New file.
+ * gdb.modula2/max-depth.c: New file.
+ * lib/gdb.exp (get_print_expr_at_depths): New proc.
+
2019-04-29 Tom de Vries <tdevries@suse.de>
* lib/opencl.exp (skip_opencl_tests): Add missing "with" in regexp.
diff --git a/gdb/testsuite/gdb.base/max-depth.c b/gdb/testsuite/gdb.base/max-depth.c
new file mode 100644
index 0000000..3c57249
--- /dev/null
+++ b/gdb/testsuite/gdb.base/max-depth.c
@@ -0,0 +1,232 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2019 Free Software Foundation, Inc.
+
+ 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/>. */
+
+struct s1
+{
+ int x;
+ int y;
+} s1;
+
+struct s2
+{
+ int x;
+ int y;
+ struct
+ {
+ int z;
+ int a;
+ };
+} s2;
+
+struct s3
+{
+ int x;
+ int y;
+ struct
+ {
+ int z;
+ int a;
+ struct
+ {
+ int b;
+ int c;
+ };
+ };
+} s3;
+
+struct s4
+{
+ int x;
+ int y;
+ struct
+ {
+ int x;
+ int y;
+ struct
+ {
+ int x;
+ int y;
+ } l2;
+ } l1;
+} s4;
+
+struct s5
+{
+ union
+ {
+ int raw[3];
+ struct
+ {
+ int x;
+ int y;
+ int z;
+ };
+ };
+} s5;
+
+typedef struct
+{
+ union
+ {
+ int raw[3];
+ struct
+ {
+ int x;
+ int y;
+ int z;
+ };
+ };
+} s6_t;
+
+s6_t s6;
+
+struct s7
+{
+ struct
+ {
+ int x;
+ int y;
+ };
+ struct
+ {
+ int z;
+ int a;
+ };
+ struct
+ {
+ int b;
+ int c;
+ };
+} s7;
+
+struct s8
+{
+ int x;
+ int y;
+ struct
+ {
+ int z;
+ int a;
+ struct
+ {
+ int b;
+ int c;
+ };
+ } d1;
+} s8;
+
+struct s9
+{
+ int x;
+ int y;
+ struct
+ {
+ int k;
+ int j;
+ struct
+ {
+ int z;
+ int a;
+ struct
+ {
+ int b;
+ int c;
+ };
+ } d1;
+ };
+ struct
+ {
+ int z;
+ int a;
+ struct
+ {
+ int b;
+ int c;
+ };
+ } d2;
+} s9;
+
+struct s10
+{
+ int x[10];
+ int y;
+ struct
+ {
+ int k[10];
+ int j;
+ struct
+ {
+ int z;
+ int a;
+ struct
+ {
+ int b[10];
+ int c;
+ };
+ } d1;
+ };
+ struct
+ {
+ int z;
+ int a;
+ struct
+ {
+ int b[10];
+ int c;
+ };
+ } d2;
+} s10;
+
+struct s11
+{
+ int x;
+ char s[10];
+ struct
+ {
+ int z;
+ int a;
+ };
+} s11;
+
+/* The following are C++ inheritance testing. */
+#ifdef __cplusplus
+
+/* This is non-virtual inheritance. */
+struct C1 { int c1 = 1; } c1;
+struct C2 { int c2 = 2; } c2;
+struct C3 : C2 { int c3 = 3; } c3;
+struct C4 { int c4 = 4; } c4;
+struct C5 : C4 { int c5 = 5; } c5;
+struct C6 : C5 { int c6 = 6; } c6;
+struct C7 : C1, C3, C6 { int c7 = 7; } c7;
+
+/* This is virtual inheritance. */
+struct V1 { int v1 = 1; } v1;
+struct V2 : virtual V1 { int v2 = 2; } v2;
+struct V3 : virtual V1 { int v3 = 3; } v3;
+struct V4 : virtual V2 { int v4 = 4; } v4;
+struct V5 : virtual V2 { int v5 = 1; } v5;
+struct V6 : virtual V2, virtual V3 { int v6 = 1; } v6;
+struct V7 : virtual V4, virtual V5, virtual V6 { int v7 = 1; } v7;
+
+#endif /* __cplusplus */
+
+int
+main ()
+{
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/max-depth.exp b/gdb/testsuite/gdb.base/max-depth.exp
new file mode 100644
index 0000000..b3b7876
--- /dev/null
+++ b/gdb/testsuite/gdb.base/max-depth.exp
@@ -0,0 +1,165 @@
+# Copyright 2019 Free Software Foundation, Inc.
+
+# 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/>.
+
+# Tests GDB's handling of 'set print max-depth'.
+
+# Only test C++ if we are able. Always use C.
+if { [skip_cplus_tests] || [get_compiler_info "c++"] } {
+ set lang {c}
+} else {
+ set lang {c c++}
+}
+
+foreach l $lang {
+ set dir "$l"
+ remote_exec host "rm -rf [standard_output_file ${dir}]"
+ remote_exec host "mkdir -p [standard_output_file ${dir}]"
+}
+
+proc compile_and_run_tests { lang } {
+ global testfile
+ global srcfile
+ global binfile
+ global hex
+
+ standard_testfile .c
+
+ # Create the additional flags.
+ set flags "debug"
+ lappend flags $lang
+
+ set dir "$lang"
+ set binfile [standard_output_file ${dir}/${testfile}]
+ if { [prepare_for_testing "failed to prepare" "${binfile}" "${srcfile}" "${flags}"] } {
+ return 0
+ }
+
+ # Advance to main.
+ if { ![runto_main] } then {
+ fail "can't run to main"
+ return 0
+ }
+
+ # The max-depth setting has no effect as the anonymous scopes are
+ # ignored and the members are aggregated into the parent scope.
+ gdb_print_expr_at_depths "s1" {"{...}" \
+ "{x = 0, y = 0}"\
+ "{x = 0, y = 0}"}
+
+ gdb_print_expr_at_depths "s2" {"{...}" \
+ "{x = 0, y = 0, {z = 0, a = 0}}" \
+ "{x = 0, y = 0, {z = 0, a = 0}}"}
+
+ gdb_print_expr_at_depths "s3" {"{...}" \
+ "{x = 0, y = 0, {z = 0, a = 0, {b = 0, c = 0}}}" \
+ "{x = 0, y = 0, {z = 0, a = 0, {b = 0, c = 0}}}" \
+ "{x = 0, y = 0, {z = 0, a = 0, {b = 0, c = 0}}}"}
+
+ # Increasing max-depth unfurls more of the object.
+ gdb_print_expr_at_depths "s4" {"{...}" \
+ "{x = 0, y = 0, l1 = {...}}" \
+ "{x = 0, y = 0, l1 = {x = 0, y = 0, l2 = {...}}}" \
+ "{x = 0, y = 0, l1 = {x = 0, y = 0, l2 = {x = 0, y = 0}}}"}
+
+ # Check handling of unions, in this case 'raw' is printed instead of
+ # just {...} as this is not useful.
+ gdb_print_expr_at_depths "s5" {"{...}" \
+ "{{raw = {...}, {x = 0, y = 0, z = 0}}}" \
+ "{{raw = \\{0, 0, 0\\}, {x = 0, y = 0, z = 0}}}"}
+
+ # Check handling of typedefs.
+ gdb_print_expr_at_depths "s6" {"{...}" \
+ "{{raw = {...}, {x = 0, y = 0, z = 0}}}" \
+ "{{raw = \\{0, 0, 0\\}, {x = 0, y = 0, z = 0}}}"}
+
+ # Multiple anonymous structures in parallel.
+ gdb_print_expr_at_depths "s7" {"{...}" \
+ "{{x = 0, y = 0}, {z = 0, a = 0}, {b = 0, c = 0}}" \
+ "{{x = 0, y = 0}, {z = 0, a = 0}, {b = 0, c = 0}}"}
+
+ # Flip flop between named and anonymous. Expected to unfurl to the
+ # first non-anonymous type.
+ gdb_print_expr_at_depths "s8" {"{...}" \
+ "{x = 0, y = 0, d1 = {...}}" \
+ "{x = 0, y = 0, d1 = {z = 0, a = 0, {b = 0, c = 0}}}"}
+
+ # Imbalanced tree, this will unfurl one size more than the other as
+ # one side has more anonymous levels.
+ gdb_print_expr_at_depths "s9" {"{...}" \
+ "{x = 0, y = 0, {k = 0, j = 0, d1 = {...}}, d2 = {...}}" \
+ "{x = 0, y = 0, {k = 0, j = 0, d1 = {z = 0, a = 0, {b = 0, c = 0}}}, d2 = {z = 0, a = 0, {b = 0, c = 0}}}"}
+
+ # Arrays are treated as an extra level, while scalars are not.
+ gdb_print_expr_at_depths "s10" {"{...}" \
+ "{x = {...}, y = 0, {k = {...}, j = 0, d1 = {...}}, d2 = {...}}" \
+ "{x = \\{0, 0, 0, 0, 0, 0, 0, 0, 0, 0\\}, y = 0, {k = \\{0, 0, 0, 0, 0, 0, 0, 0, 0, 0\\}, j = 0, d1 = {z = 0, a = 0, {b = {...}, c = 0}}}, d2 = {z = 0, a = 0, {b = {...}, c = 0}}}" \
+ "{x = \\{0, 0, 0, 0, 0, 0, 0, 0, 0, 0\\}, y = 0, {k = \\{0, 0, 0, 0, 0, 0, 0, 0, 0, 0\\}, j = 0, d1 = {z = 0, a = 0, {b = \\{0, 0, 0, 0, 0, 0, 0, 0, 0, 0\\}, c = 0}}}, d2 = {z = 0, a = 0, {b = \\{0, 0, 0, 0, 0, 0, 0, 0, 0, 0\\}, c = 0}}}"}
+
+ # Strings are treated as scalars.
+ gdb_print_expr_at_depths "s11" {"{...}" \
+ "{x = 0, s = \"\\\\000\\\\000\\\\000\\\\000\\\\000\\\\000\\\\000\\\\000\\\\000\", {z = 0, a = 0}}"}
+
+
+ if { $lang == "c++" } {
+ gdb_print_expr_at_depths "c1" {"{...}" \
+ "{c1 = 1}" }
+ gdb_print_expr_at_depths "c2" { "{...}" "{c2 = 2}" }
+ gdb_print_expr_at_depths "c3" { "{...}" \
+ "{<C2> = {...}, c3 = 3}" \
+ "{<C2> = {c2 = 2}, c3 = 3}" }
+ gdb_print_expr_at_depths "c4" { "{...}" "{c4 = 4}" }
+ gdb_print_expr_at_depths "c5" { "{...}" \
+ "{<C4> = {...}, c5 = 5}" \
+ "{<C4> = {c4 = 4}, c5 = 5}" }
+ gdb_print_expr_at_depths "c6" { "{...}" \
+ "{<C5> = {...}, c6 = 6}" \
+ "{<C5> = {<C4> = {...}, c5 = 5}, c6 = 6}" \
+ "{<C5> = {<C4> = {c4 = 4}, c5 = 5}, c6 = 6}" }
+ gdb_print_expr_at_depths "c7" { "{...}" \
+ "{<C1> = {...}, <C3> = {...}, <C6> = {...}, c7 = 7}" \
+ "{<C1> = {c1 = 1}, <C3> = {<C2> = {...}, c3 = 3}, <C6> = {<C5> = {...}, c6 = 6}, c7 = 7}" \
+ "{<C1> = {c1 = 1}, <C3> = {<C2> = {c2 = 2}, c3 = 3}, <C6> = {<C5> = {<C4> = {...}, c5 = 5}, c6 = 6}, c7 = 7}" \
+ "{<C1> = {c1 = 1}, <C3> = {<C2> = {c2 = 2}, c3 = 3}, <C6> = {<C5> = {<C4> = {c4 = 4}, c5 = 5}, c6 = 6}, c7 = 7}" }
+
+ gdb_print_expr_at_depths "v1" [list "{...}" "{v1 = 1}" ]
+ gdb_print_expr_at_depths "v2" [list "{...}" \
+ "{<V1> = {...}, _vptr.V2 = $hex <VTT for V2>, v2 = 2}" \
+ "{<V1> = {v1 = 1}, _vptr.V2 = $hex <VTT for V2>, v2 = 2}" ]
+ gdb_print_expr_at_depths "v3" [list "{...}" \
+ "{<V1> = {...}, _vptr.V3 = $hex <VTT for V3>, v3 = 3}" \
+ "{<V1> = {v1 = 1}, _vptr.V3 = $hex <VTT for V3>, v3 = 3}" ]
+ gdb_print_expr_at_depths "v4" [list "{...}" \
+ "{<V2> = {...}, _vptr.V4 = $hex <vtable for V4\[^>\]+>, v4 = 4}" \
+ "{<V2> = {<V1> = {...}, _vptr.V2 = $hex <VTT for V4>, v2 = 2}, _vptr.V4 = $hex <vtable for V4\[^>\]+>, v4 = 4}" \
+ "{<V2> = {<V1> = {v1 = 1}, _vptr.V2 = $hex <VTT for V4>, v2 = 2}, _vptr.V4 = $hex <vtable for V4\[^>\]+>, v4 = 4}" ]
+ gdb_print_expr_at_depths "v5" [list "{...}" \
+ "{<V2> = {...}, _vptr.V5 = $hex <vtable for V5\[^>\]+>, v5 = 1}" \
+ "{<V2> = {<V1> = {...}, _vptr.V2 = $hex <VTT for V5>, v2 = 2}, _vptr.V5 = $hex <vtable for V5\[^>\]+>, v5 = 1}" \
+ "{<V2> = {<V1> = {v1 = 1}, _vptr.V2 = $hex <VTT for V5>, v2 = 2}, _vptr.V5 = $hex <vtable for V5\[^>\]+>, v5 = 1}" ]
+ gdb_print_expr_at_depths "v6" [list "{...}" \
+ "{<V2> = {...}, <V3> = {...}, _vptr.V6 = $hex <vtable for V6\[^>\]+>, v6 = 1}" \
+ "{<V2> = {<V1> = {...}, _vptr.V2 = $hex <vtable for V6\[^>\]+>, v2 = 2}, <V3> = {_vptr.V3 = $hex <VTT for V6>, v3 = 3}, _vptr.V6 = $hex <vtable for V6\[^>\]+>, v6 = 1}" \
+ "{<V2> = {<V1> = {v1 = 1}, _vptr.V2 = $hex <vtable for V6\[^>\]+>, v2 = 2}, <V3> = {_vptr.V3 = $hex <VTT for V6>, v3 = 3}, _vptr.V6 = $hex <vtable for V6\[^>\]+>, v6 = 1}" ]
+ gdb_print_expr_at_depths "v7" [list "{...}" \
+ "{<V4> = {...}, <V5> = {...}, <V6> = {...}, _vptr.V7 = $hex <vtable for V7\[^>\]+>, v7 = 1}" \
+ "{<V4> = {<V2> = {...}, _vptr.V4 = $hex <vtable for V7\[^>\]+>, v4 = 4}, <V5> = {_vptr.V5 = $hex <vtable for V7\[^>\]+>, v5 = 1}, <V6> = {<V3> = {...}, _vptr.V6 = $hex <vtable for V7\[^>\]+>, v6 = 1}, _vptr.V7 = $hex <vtable for V7\[^>\]+>, v7 = 1}" \
+ "{<V4> = {<V2> = {<V1> = {...}, _vptr.V2 = $hex <vtable for V7\[^>\]+>, v2 = 2}, _vptr.V4 = $hex <vtable for V7\[^>\]+>, v4 = 4}, <V5> = {_vptr.V5 = $hex <vtable for V7\[^>\]+>, v5 = 1}, <V6> = {<V3> = {_vptr.V3 = $hex <VTT for V7>, v3 = 3}, _vptr.V6 = $hex <vtable for V7\[^>\]+>, v6 = 1}, _vptr.V7 = $hex <vtable for V7\[^>\]+>, v7 = 1}" \
+ "{<V4> = {<V2> = {<V1> = {v1 = 1}, _vptr.V2 = $hex <vtable for V7\[^>\]+>, v2 = 2}, _vptr.V4 = $hex <vtable for V7\[^>\]+>, v4 = 4}, <V5> = {_vptr.V5 = $hex <vtable for V7\[^>\]+>, v5 = 1}, <V6> = {<V3> = {_vptr.V3 = $hex <VTT for V7>, v3 = 3}, _vptr.V6 = $hex <vtable for V7\[^>\]+>, v6 = 1}, _vptr.V7 = $hex <vtable for V7\[^>\]+>, v7 = 1}" ]
+ }
+}
+
+foreach_with_prefix l $lang {
+ compile_and_run_tests $l
+}
diff --git a/gdb/testsuite/gdb.fortran/max-depth.exp b/gdb/testsuite/gdb.fortran/max-depth.exp
new file mode 100644
index 0000000..8b0bb80
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/max-depth.exp
@@ -0,0 +1,41 @@
+# Copyright 2019 Free Software Foundation, Inc.
+#
+# 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/>.
+
+# This file tests GDB's handling of 'set print max-depth' for nested
+# fortran types.
+
+load_lib "fortran.exp"
+
+if { [skip_fortran_tests] } { continue }
+
+standard_testfile .f90
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile {debug f90}] } {
+ return -1
+}
+
+if { ![runto MAIN__] } {
+ perror "Could not run to breakpoint `MAIN__'."
+ continue
+}
+
+gdb_breakpoint [gdb_get_line_number "stop-here"]
+gdb_continue_to_breakpoint "stop-here" ".*stop-here.*"
+
+gdb_print_expr_at_depths "var" {"\\(\\.\\.\\.\\)" \
+ "\\( d = \\(\\.\\.\\.\\) \\)" \
+ "\\( d = \\( string = 'abcde', c = \\(\\.\\.\\.\\) \\) \\)" \
+ "\\( d = \\( string = 'abcde', c = \\( b = \\(\\.\\.\\.\\), array = \\(\\.\\.\\.\\) \\) \\) \\)" \
+ "\\( d = \\( string = 'abcde', c = \\( b = \\( a = 1 \\), array = \\(0, 0, 0, 0, 0\\) \\) \\) \\)" }
diff --git a/gdb/testsuite/gdb.fortran/max-depth.f90 b/gdb/testsuite/gdb.fortran/max-depth.f90
new file mode 100644
index 0000000..9b6f90c
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/max-depth.f90
@@ -0,0 +1,42 @@
+! Copyright 2019 Free Software Foundation, Inc.
+!
+! 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 2 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/>.
+
+program max_depth_test
+ type :: s1
+ integer :: a
+ end type s1
+
+ type :: s2
+ type (s1) :: b
+ integer :: array (5)
+ end type s2
+
+ type :: s3
+ character(5) :: string
+ type (s2) :: c
+ end type s3
+
+ type :: s4
+ type (s3) :: d
+ end type s4
+
+ logical :: l
+ type (s4) :: var
+
+ var%d%c%b%a = 1
+ var%d%c%array = 0
+ var%d%string = "abcde"
+ l = .FALSE. ! stop-here
+end program max_depth_test
diff --git a/gdb/testsuite/gdb.go/max-depth.exp b/gdb/testsuite/gdb.go/max-depth.exp
new file mode 100644
index 0000000..0f8ba9a
--- /dev/null
+++ b/gdb/testsuite/gdb.go/max-depth.exp
@@ -0,0 +1,40 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2019 Free Software Foundation, Inc.
+#
+# 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/>.
+
+# Test the use of 'set prinnt max-depth' when printing go structures.
+
+load_lib "go.exp"
+
+if { [skip_go_tests] } { continue }
+
+standard_testfile .go
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} {debug go}] } {
+ return -1
+}
+
+if { [go_runto_main] < 0 } {
+ untested "could not run to main"
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "Break here"]
+gdb_continue_to_breakpoint "run to breakpoint" ".*Break here.*"
+
+gdb_print_expr_at_depths "s1" [list "{...}" \
+ "{m_struct = {...}, m_string = $hex \"hello world\"}" \
+ "{m_struct = {m_a = 3, m_b = 7}, m_string = $hex \"hello world\"}"]
diff --git a/gdb/testsuite/gdb.go/max-depth.go b/gdb/testsuite/gdb.go/max-depth.go
new file mode 100644
index 0000000..6dbfc22
--- /dev/null
+++ b/gdb/testsuite/gdb.go/max-depth.go
@@ -0,0 +1,41 @@
+// Copyright 2019 Free Software Foundation, Inc.
+//
+// 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/>.
+
+package main
+
+import "fmt"
+
+type S1 struct {
+ m_a int
+ m_b int
+}
+
+type S2 struct {
+ m_struct S1
+ m_string string
+}
+
+func main () {
+ var s1 S2
+ var i int
+
+ s1.m_string = "hello world"
+ s1.m_struct.m_a = 3
+ s1.m_struct.m_b = 7
+
+ i = 0 // Break here.
+ fmt.Println ("Got: %d, %d, %d, %s", i, s1.m_struct.m_a,
+ s1.m_struct.m_b, s1.m_string)
+}
diff --git a/gdb/testsuite/gdb.modula2/max-depth.c b/gdb/testsuite/gdb.modula2/max-depth.c
new file mode 100644
index 0000000..c2fd70c
--- /dev/null
+++ b/gdb/testsuite/gdb.modula2/max-depth.c
@@ -0,0 +1,45 @@
+/* Copyright 2019 Free Software Foundation, Inc.
+
+ 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 <string.h>
+
+struct S1
+{
+ int a;
+ int b;
+};
+
+struct S2
+{
+ char str[10];
+ struct S1 s1;
+};
+
+struct S3
+{
+ struct S2 s2;
+};
+
+int
+main ()
+{
+ struct S3 s3;
+
+ memcpy (s3.s2.str, "abcde\0fghi", 10);
+ s3.s2.s1.a = 3;
+ s3.s2.s1.b = 4;
+
+ return 0; /* Break here. */
+}
diff --git a/gdb/testsuite/gdb.modula2/max-depth.exp b/gdb/testsuite/gdb.modula2/max-depth.exp
new file mode 100644
index 0000000..ac7edfe
--- /dev/null
+++ b/gdb/testsuite/gdb.modula2/max-depth.exp
@@ -0,0 +1,37 @@
+# Copyright 2019 Free Software Foundation, Inc.
+
+# 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/>.
+
+# Test the use of 'set prinnt max-depth' when printing modula2 structures.
+
+standard_testfile
+
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug quiet}]} {
+ return -1
+}
+
+if { ![runto_main] } then {
+ fail "can't run to main"
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "Break here"]
+gdb_continue_to_breakpoint "breakpoint"
+
+gdb_test "set lang modula-2" ".*does not match.*" "switch to modula-2"
+
+gdb_print_expr_at_depths "s3" [list "{...}" \
+ "{s2 = {...}}" \
+ "{s2 = {str = \"abcde\\\\000fghi\", s1 = {...}}}" \
+ "{s2 = {str = \"abcde\\\\000fghi\", s1 = {a = 3, b = 4}}}"]
diff --git a/gdb/testsuite/gdb.python/py-format-string.exp b/gdb/testsuite/gdb.python/py-format-string.exp
index 2f574fb..ebb2074 100644
--- a/gdb/testsuite/gdb.python/py-format-string.exp
+++ b/gdb/testsuite/gdb.python/py-format-string.exp
@@ -672,6 +672,26 @@ proc test_max_elements {} {
}
}
+# Test the max_depth option for gdb.Value.format_string.
+proc test_max_depth {} {
+ set opts "max_depth=-1"
+ with_test_prefix $opts {
+ check_format_string "a_struct_with_union" $opts
+ }
+ set opts "max_depth=0"
+ with_test_prefix $opts {
+ check_format_string "a_struct_with_union" $opts "\\{\.\.\.\\}"
+ }
+ set opts "max_depth=1"
+ with_test_prefix $opts {
+ check_format_string "a_struct_with_union" $opts "\\{the_union = \\{\.\.\.\\}\\}"
+ }
+ set opts "max_depth=2"
+ with_test_prefix $opts {
+ check_format_string "a_struct_with_union" $opts
+ }
+}
+
# Test the repeat_threshold option for gdb.Value.format_string.
proc test_repeat_threshold {} {
global current_lang
@@ -925,6 +945,7 @@ proc test_all_common {} {
test_actual_objects
test_static_members
test_max_elements
+ test_max_depth
test_repeat_threshold
test_format
# Multiple options mixed together.
diff --git a/gdb/testsuite/gdb.python/py-nested-maps.c b/gdb/testsuite/gdb.python/py-nested-maps.c
new file mode 100644
index 0000000..94107c0
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-nested-maps.c
@@ -0,0 +1,130 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2019 Free Software Foundation, Inc.
+
+ 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 <stdlib.h>
+#include <string.h>
+
+#define FIXED_MAP_SIZE 10
+
+struct key_t
+{
+ int a;
+ int b;
+};
+
+struct value_t
+{
+ int x;
+ int y;
+ int z;
+};
+
+struct map_t
+{
+ const char *name;
+ int length;
+ struct key_t *keys;
+ struct value_t *values;
+
+ /* This field is used only by the pretty printer. */
+ int show_header;
+};
+
+struct map_map_t
+{
+ int length;
+ struct map_t **values;
+
+ /* This field is used only by the pretty printer. */
+ int show_header;
+};
+
+struct map_t *
+create_map (const char *name)
+{
+ struct map_t *m = malloc (sizeof (struct map_t));
+ m->name = strdup (name);
+ m->length = 0;
+ m->keys = NULL;
+ m->values = NULL;
+ m->show_header = 0;
+}
+
+void
+add_map_element (struct map_t *m, struct key_t k, struct value_t v)
+{
+ if (m->length == 0)
+ {
+ m->keys = malloc (sizeof (struct key_t) * FIXED_MAP_SIZE);
+ m->values = malloc (sizeof (struct value_t) * FIXED_MAP_SIZE);
+ }
+
+ m->keys[m->length] = k;
+ m->values[m->length] = v;
+ m->length++;
+}
+
+struct map_map_t *
+create_map_map (void)
+{
+ struct map_map_t *mm = malloc (sizeof (struct map_map_t));
+ mm->length = 0;
+ mm->values = NULL;
+ mm->show_header = 0;
+}
+
+void
+add_map_map_element (struct map_map_t *mm, struct map_t *map)
+{
+ if (mm->length == 0)
+ mm->values = malloc (sizeof (struct map_t *) * FIXED_MAP_SIZE);
+
+ mm->values[mm->length] = map;
+ mm->length++;
+}
+
+int
+main (void)
+{
+ struct map_t *m1 = create_map ("m1");
+ struct key_t k1 = {3, 4};
+ struct key_t k2 = {4, 5};
+ struct key_t k3 = {5, 6};
+ struct key_t k4 = {6, 7};
+ struct key_t k5 = {7, 8};
+ struct key_t k6 = {8, 9};
+ struct value_t v1 = {0, 1, 2};
+ struct value_t v2 = {3, 4, 5};
+ struct value_t v3 = {6, 7, 8};
+ struct value_t v4 = {9, 0, 1};
+ struct value_t v5 = {2, 3, 4};
+ struct value_t v6 = {5, 6, 7};
+ add_map_element (m1, k1, v1);
+ add_map_element (m1, k2, v2);
+ add_map_element (m1, k3, v3);
+
+ struct map_t *m2 = create_map ("m2");
+ add_map_element (m2, k4, v4);
+ add_map_element (m2, k5, v5);
+ add_map_element (m2, k6, v6);
+
+ struct map_map_t *mm = create_map_map ();
+ add_map_map_element (mm, m1);
+ add_map_map_element (mm, m2);
+
+ return 0; /* Break here. */
+}
diff --git a/gdb/testsuite/gdb.python/py-nested-maps.exp b/gdb/testsuite/gdb.python/py-nested-maps.exp
new file mode 100644
index 0000000..81dd99c
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-nested-maps.exp
@@ -0,0 +1,238 @@
+# Copyright (C) 2019 Free Software Foundation, Inc.
+
+# 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/>.
+
+# This tests GDB's python pretty printing of nested map like
+# structures using structures as keys and values, it then tests how
+# 'set print max-depth' affects this printing.
+
+load_lib gdb-python.exp
+
+standard_testfile
+
+# Start with a fresh gdb.
+gdb_exit
+gdb_start
+
+# Skip all tests if Python scripting is not enabled.
+if { [skip_python_tests] } { continue }
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile {debug}] } {
+ return -1
+}
+
+if ![runto_main ] then {
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "Break here"]
+gdb_continue_to_breakpoint "run to testing point" ".*Break here.*"
+
+set remote_python_file [gdb_remote_download host \
+ ${srcdir}/${subdir}/${testfile}.py]
+gdb_test_no_output "source ${remote_python_file}" "load python file"
+
+# Test printing with 'set print pretty off'.
+gdb_test_no_output "set print pretty off"
+with_test_prefix "pretty=off" {
+ gdb_print_expr_at_depths "*m1" \
+ [list \
+ "\{\\.\\.\\.\}" \
+ "\{\\\[\{a = 3, b = 4\}\\\] = \{\\.\\.\\.\}, \\\[\{a = 4, b = 5\}\\\] = \{\\.\\.\\.\}, \\\[\{a = 5, b = 6\}\\\] = \{\\.\\.\\.\}\}" \
+ "\{\\\[\{a = 3, b = 4\}\\\] = \{x = 0, y = 1, z = 2\}, \\\[\{a = 4, b = 5\}\\\] = \{x = 3, y = 4, z = 5\}, \\\[\{a = 5, b = 6\}\\\] = \{x = 6, y = 7, z = 8\}\}" \
+ ]
+
+ gdb_print_expr_at_depths "*mm" \
+ [list \
+ "\{\\.\\.\\.\}" \
+ "\{\\\[$hex \"m1\"\\\] = \{\\.\\.\\.\}, \\\[$hex \"m2\"\\\] = \{\\.\\.\\.\}\}" \
+ "\{\\\[$hex \"m1\"\\\] = \{\\\[\{a = 3, b = 4\}\\\] = \{\\.\\.\\.\}, \\\[\{a = 4, b = 5\}\\\] = \{\\.\\.\\.\}, \\\[\{a = 5, b = 6\}\\\] = \{\\.\\.\\.\}\}, \\\[$hex \"m2\"\\\] = \{\\\[\{a = 6, b = 7\}\\\] = \{\\.\\.\\.\}, \\\[\{a = 7, b = 8\}\\\] = \{\\.\\.\\.\}, \\\[\{a = 8, b = 9\}\\\] = \{\\.\\.\\.\}\}\}" \
+ "\{\\\[$hex \"m1\"\\\] = \{\\\[\{a = 3, b = 4\}\\\] = \{x = 0, y = 1, z = 2\}, \\\[\{a = 4, b = 5\}\\\] = \{x = 3, y = 4, z = 5\}, \\\[\{a = 5, b = 6\}\\\] = \{x = 6, y = 7, z = 8\}\}, \\\[$hex \"m2\"\\\] = \{\\\[\{a = 6, b = 7\}\\\] = \{x = 9, y = 0, z = 1\}, \\\[\{a = 7, b = 8\}\\\] = \{x = 2, y = 3, z = 4\}, \\\[\{a = 8, b = 9\}\\\] = \{x = 5, y = 6, z = 7\}\}\}" \
+ ]
+}
+
+# Now again, but with 'set print pretty on'.
+gdb_test_no_output "set print pretty on"
+with_test_prefix "pretty=on" {
+ gdb_print_expr_at_depths "*m1" \
+ [list \
+ "\{\\.\\.\\.\}" \
+ [multi_line \
+ " = \{" \
+ " \\\[\{" \
+ " a = 3," \
+ " b = 4" \
+ " \}\\\] = \{\\.\\.\\.\}," \
+ " \\\[\{" \
+ " a = 4," \
+ " b = 5" \
+ " \}\\\] = \{\\.\\.\\.\}," \
+ " \\\[\{" \
+ " a = 5," \
+ " b = 6" \
+ " \}\\\] = \{\\.\\.\\.\}" \
+ "\}" ] \
+ [multi_line \
+ " = \{" \
+ " \\\[\{" \
+ " a = 3," \
+ " b = 4" \
+ " \}\\\] = \{" \
+ " x = 0," \
+ " y = 1," \
+ " z = 2" \
+ " \}," \
+ " \\\[\{" \
+ " a = 4," \
+ " b = 5" \
+ " \}\\\] = \{" \
+ " x = 3," \
+ " y = 4," \
+ " z = 5" \
+ " \}," \
+ " \\\[\{" \
+ " a = 5," \
+ " b = 6" \
+ " \}\\\] = \{" \
+ " x = 6," \
+ " y = 7," \
+ " z = 8" \
+ " \}" \
+ "\}" ] \
+ ]
+
+ gdb_print_expr_at_depths "*mm" \
+ [list \
+ "\{\\.\\.\\.\}" \
+ [multi_line \
+ " = \{" \
+ " \\\[$hex \"m1\"\\\] = \{\\.\\.\\.\}," \
+ " \\\[$hex \"m2\"\\\] = \{\\.\\.\\.\}" \
+ "\}" ] \
+ [multi_line \
+ " = \{" \
+ " \\\[$hex \"m1\"\\\] = \{" \
+ " \\\[\{" \
+ " a = 3," \
+ " b = 4" \
+ " \}\\\] = \{\\.\\.\\.\}," \
+ " \\\[\{" \
+ " a = 4," \
+ " b = 5" \
+ " \}\\\] = \{\\.\\.\\.\}," \
+ " \\\[\{" \
+ " a = 5," \
+ " b = 6" \
+ " \}\\\] = \{\\.\\.\\.\}" \
+ " \}," \
+ " \\\[$hex \"m2\"\\\] = \{" \
+ " \\\[\{" \
+ " a = 6," \
+ " b = 7" \
+ " \}\\\] = \{\\.\\.\\.\}," \
+ " \\\[\{" \
+ " a = 7," \
+ " b = 8" \
+ " \}\\\] = \{\\.\\.\\.\}," \
+ " \\\[\{" \
+ " a = 8," \
+ " b = 9" \
+ " \}\\\] = \{\\.\\.\\.\}" \
+ " \}" \
+ "\}" ] \
+ [multi_line \
+ " = \{" \
+ " \\\[$hex \"m1\"\\\] = \{" \
+ " \\\[\{" \
+ " a = 3," \
+ " b = 4" \
+ " \}\\\] = \{" \
+ " x = 0," \
+ " y = 1," \
+ " z = 2" \
+ " \}," \
+ " \\\[\{" \
+ " a = 4," \
+ " b = 5" \
+ " \}\\\] = \{" \
+ " x = 3," \
+ " y = 4," \
+ " z = 5" \
+ " \}," \
+ " \\\[\{" \
+ " a = 5," \
+ " b = 6" \
+ " \}\\\] = \{" \
+ " x = 6," \
+ " y = 7," \
+ " z = 8" \
+ " \}" \
+ " \}," \
+ " \\\[$hex \"m2\"\\\] = \{" \
+ " \\\[\{" \
+ " a = 6," \
+ " b = 7" \
+ " \}\\\] = \{" \
+ " x = 9," \
+ " y = 0," \
+ " z = 1" \
+ " \}," \
+ " \\\[\{" \
+ " a = 7," \
+ " b = 8" \
+ " \}\\\] = \{" \
+ " x = 2," \
+ " y = 3," \
+ " z = 4" \
+ " \}," \
+ " \\\[\{" \
+ " a = 8," \
+ " b = 9" \
+ " \}\\\] = \{" \
+ " x = 5," \
+ " y = 6," \
+ " z = 7" \
+ " \}" \
+ " \}" \
+ "\}" ] \
+ ]
+}
+
+# Test printing with 'set print pretty off', but this time display a
+# top level string (returned from the to_string method) as part of the
+# printed value.
+gdb_test_no_output "set mm->show_header=1"
+gdb_test_no_output "set m1->show_header=1"
+gdb_test_no_output "set m2->show_header=1"
+with_test_prefix "headers=on" {
+ gdb_test_no_output "set print pretty off"
+ with_test_prefix "pretty=off" {
+ gdb_print_expr_at_depths "*m1" \
+ [list \
+ "\{\\.\\.\\.\}" \
+ "pp_map = \{\\\[\{a = 3, b = 4\}\\\] = \{\\.\\.\\.\}, \\\[\{a = 4, b = 5\}\\\] = \{\\.\\.\\.\}, \\\[\{a = 5, b = 6\}\\\] = \{\\.\\.\\.\}\}" \
+ "pp_map = \{\\\[\{a = 3, b = 4\}\\\] = \{x = 0, y = 1, z = 2\}, \\\[\{a = 4, b = 5\}\\\] = \{x = 3, y = 4, z = 5\}, \\\[\{a = 5, b = 6\}\\\] = \{x = 6, y = 7, z = 8\}\}" \
+ ]
+
+ gdb_print_expr_at_depths "*mm" \
+ [list \
+ "\{\\.\\.\\.\}" \
+ "pp_map_map = \{\\\[$hex \"m1\"\\\] = \{\\.\\.\\.\}, \\\[$hex \"m2\"\\\] = \{\\.\\.\\.\}\}" \
+ "pp_map_map = \{\\\[$hex \"m1\"\\\] = pp_map = \{\\\[\{a = 3, b = 4\}\\\] = \{\\.\\.\\.\}, \\\[\{a = 4, b = 5\}\\\] = \{\\.\\.\\.\}, \\\[\{a = 5, b = 6\}\\\] = \{\\.\\.\\.\}\}, \\\[$hex \"m2\"\\\] = pp_map = \{\\\[\{a = 6, b = 7\}\\\] = \{\\.\\.\\.\}, \\\[\{a = 7, b = 8\}\\\] = \{\\.\\.\\.\}, \\\[\{a = 8, b = 9\}\\\] = \{\\.\\.\\.\}\}\}" \
+ "pp_map_map = \{\\\[$hex \"m1\"\\\] = pp_map = \{\\\[\{a = 3, b = 4\}\\\] = \{x = 0, y = 1, z = 2\}, \\\[\{a = 4, b = 5\}\\\] = \{x = 3, y = 4, z = 5\}, \\\[\{a = 5, b = 6\}\\\] = \{x = 6, y = 7, z = 8\}\}, \\\[$hex \"m2\"\\\] = pp_map = \{\\\[\{a = 6, b = 7\}\\\] = \{x = 9, y = 0, z = 1\}, \\\[\{a = 7, b = 8\}\\\] = \{x = 2, y = 3, z = 4\}, \\\[\{a = 8, b = 9\}\\\] = \{x = 5, y = 6, z = 7\}\}\}" \
+ ]
+ }
+}
diff --git a/gdb/testsuite/gdb.python/py-nested-maps.py b/gdb/testsuite/gdb.python/py-nested-maps.py
new file mode 100644
index 0000000..d3fdf59
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-nested-maps.py
@@ -0,0 +1,135 @@
+# Copyright (C) 2019 Free Software Foundation, Inc.
+
+# 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/>.
+
+# This file is part of the GDB testsuite. It tests GDB's printing of
+# nested map like structures.
+
+import re
+import gdb
+
+def _iterator1 (pointer, len):
+ while len > 0:
+ map = pointer.dereference()
+ yield ('', map['name'])
+ yield ('', map.dereference())
+ pointer += 1
+ len -= 1
+
+def _iterator2 (pointer1, pointer2, len):
+ while len > 0:
+ yield ("", pointer1.dereference())
+ yield ("", pointer2.dereference())
+ pointer1 += 1
+ pointer2 += 1
+ len -= 1
+
+class pp_map (object):
+ def __init__(self, val):
+ self.val = val
+
+ def to_string(self):
+ if (self.val['show_header'] == 0):
+ return None
+ else:
+ return "pp_map"
+
+ def children(self):
+ return _iterator2(self.val['keys'],
+ self.val['values'],
+ self.val['length'])
+
+ def display_hint (self):
+ return 'map'
+
+class pp_map_map (object):
+ def __init__(self, val):
+ self.val = val
+
+ def to_string(self):
+ if (self.val['show_header'] == 0):
+ return None
+ else:
+ return "pp_map_map"
+
+ def children(self):
+ return _iterator1(self.val['values'],
+ self.val['length'])
+
+ def display_hint (self):
+ return 'map'
+
+def lookup_function (val):
+ "Look-up and return a pretty-printer that can print val."
+
+ # Get the type.
+ type = val.type
+
+ # If it points to a reference, get the reference.
+ if type.code == gdb.TYPE_CODE_REF:
+ type = type.target ()
+
+ # Get the unqualified type, stripped of typedefs.
+ type = type.unqualified ().strip_typedefs ()
+
+ # Get the type name.
+ typename = type.tag
+
+ if typename == None:
+ return None
+
+ # Iterate over local dictionary of types to determine
+ # if a printer is registered for that type. Return an
+ # instantiation of the printer if found.
+ for function in pretty_printers_dict:
+ if function.match (typename):
+ return pretty_printers_dict[function] (val)
+
+ # Cannot find a pretty printer. Return None.
+ return None
+
+# Lookup a printer for VAL in the typedefs dict.
+def lookup_typedefs_function (val):
+ "Look-up and return a pretty-printer that can print val (typedefs)."
+
+ # Get the type.
+ type = val.type
+
+ if type == None or type.name == None or type.code != gdb.TYPE_CODE_TYPEDEF:
+ return None
+
+ # Iterate over local dictionary of typedef types to determine if a
+ # printer is registered for that type. Return an instantiation of
+ # the printer if found.
+ for function in typedefs_pretty_printers_dict:
+ if function.match (type.name):
+ return typedefs_pretty_printers_dict[function] (val)
+
+ # Cannot find a pretty printer.
+ return None
+
+def register_pretty_printers ():
+ pretty_printers_dict[re.compile ('^struct map_t$')] = pp_map
+ pretty_printers_dict[re.compile ('^map_t$')] = pp_map
+ pretty_printers_dict[re.compile ('^struct map_map_t$')] = pp_map_map
+ pretty_printers_dict[re.compile ('^map_map_t$')] = pp_map_map
+
+# Dict for struct types with typedefs fully stripped.
+pretty_printers_dict = {}
+# Dict for typedef types.
+typedefs_pretty_printers_dict = {}
+
+register_pretty_printers ()
+gdb.pretty_printers.append (lookup_function)
+gdb.pretty_printers.append (lookup_typedefs_function)
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index f0f4334..25d370e 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -1390,6 +1390,36 @@ proc gdb_test_stdio {command inferior_pattern {gdb_pattern ""} {message ""}} {
return $res
}
+# get_print_expr_at_depths EXP OUTPUTS
+#
+# Used for testing 'set print max-depth'. Prints the expression EXP
+# with 'set print max-depth' set to various depths. OUTPUTS is a list
+# of `n` different patterns to match at each of the depths from 0 to
+# (`n` - 1).
+#
+# This proc does one final check with the max-depth set to 'unlimited'
+# which is tested against the last pattern in the OUTPUTS list. The
+# OUTPUTS list is therefore required to match every depth from 0 to a
+# depth where the whole of EXP is printed with no ellipsis.
+#
+# This proc leaves the 'set print max-depth' set to 'unlimited'.
+proc gdb_print_expr_at_depths {exp outputs} {
+ for { set depth 0 } { $depth <= [llength $outputs] } { incr depth } {
+ if { $depth == [llength $outputs] } {
+ set expected_result [lindex $outputs [expr [llength $outputs] - 1]]
+ set depth_string "unlimited"
+ } else {
+ set expected_result [lindex $outputs $depth]
+ set depth_string $depth
+ }
+
+ with_test_prefix "exp='$exp': depth=${depth_string}" {
+ gdb_test_no_output "set print max-depth ${depth_string}"
+ gdb_test "p $exp" "$expected_result"
+ }
+ }
+}
+
# Issue a PASS and return true if evaluating CONDITION in the caller's
diff --git a/gdb/valprint.c b/gdb/valprint.c
index b02ebf6..b9d8878 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -88,6 +88,7 @@ static void val_print_type_code_flags (struct type *type,
struct ui_file *stream);
#define PRINT_MAX_DEFAULT 200 /* Start print_max off at this value. */
+#define PRINT_MAX_DEPTH_DEFAULT 20 /* Start print_max_depth off at this value. */
struct value_print_options user_print_options =
{
@@ -109,7 +110,8 @@ struct value_print_options user_print_options =
1, /* pascal_static_field_print */
0, /* raw */
0, /* summary */
- 1 /* symbol_print */
+ 1, /* symbol_print */
+ PRINT_MAX_DEPTH_DEFAULT /* max_depth */
};
/* Initialize *OPTS to be a copy of the user print options. */
@@ -281,6 +283,18 @@ val_print_scalar_type_p (struct type *type)
}
}
+/* A helper function for val_print. When printing with limited depth we
+ want to print string and scalar arguments, but not aggregate arguments.
+ This function distinguishes between the two. */
+
+static bool
+val_print_scalar_or_string_type_p (struct type *type,
+ const struct language_defn *language)
+{
+ return (val_print_scalar_type_p (type)
+ || language->la_is_string_type_p (type));
+}
+
/* See its definition in value.h. */
int
@@ -1054,6 +1068,11 @@ val_print (struct type *type, LONGEST embedded_offset,
return;
}
+ /* If this value is too deep then don't print it. */
+ if (!val_print_scalar_or_string_type_p (type, language)
+ && val_print_check_max_depth (stream, recurse, options, language))
+ return;
+
try
{
language->la_val_print (type, embedded_offset, address,
@@ -1066,6 +1085,23 @@ val_print (struct type *type, LONGEST embedded_offset,
}
}
+/* See valprint.h. */
+
+bool
+val_print_check_max_depth (struct ui_file *stream, int recurse,
+ const struct value_print_options *options,
+ const struct language_defn *language)
+{
+ if (options->max_depth > -1 && recurse >= options->max_depth)
+ {
+ gdb_assert (language->la_struct_too_deep_ellipsis != NULL);
+ fputs_filtered (language->la_struct_too_deep_ellipsis, stream);
+ return true;
+ }
+
+ return false;
+}
+
/* Check whether the value VAL is printable. Return 1 if it is;
return 0 and print an appropriate error message to STREAM according to
OPTIONS if it is not. */
@@ -2859,6 +2895,15 @@ val_print_string (struct type *elttype, const char *encoding,
return (bytes_read / width);
}
+
+/* Handle 'show print max-depth'. */
+
+static void
+show_print_max_depth (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("Maximum print depth is %s.\n"), value);
+}
/* The 'set input-radix' command writes to this auxiliary variable.
@@ -3152,4 +3197,14 @@ Use 'show input-radix' or 'show output-radix' to independently show each."),
Set printing of array indexes."), _("\
Show printing of array indexes"), NULL, NULL, show_print_array_indexes,
&setprintlist, &showprintlist);
+
+ add_setshow_zuinteger_unlimited_cmd ("max-depth", class_support,
+ &user_print_options.max_depth, _("\
+Set maximum print depth for nested structures, unions and arrays."), _("\
+Show maximum print depth for nested structures, unions, and arrays."), _("\
+When structures, unions, or arrays are nested beyond this depth then they\n\
+will be replaced with either '{...}' or '(...)' depending on the language.\n\
+Use 'set print max-depth unlimited' to print the complete structure."),
+ NULL, show_print_max_depth,
+ &setprintlist, &showprintlist);
}
diff --git a/gdb/valprint.h b/gdb/valprint.h
index db99b52..e5cc947 100644
--- a/gdb/valprint.h
+++ b/gdb/valprint.h
@@ -92,6 +92,9 @@ struct value_print_options
/* If nonzero, when printing a pointer, print the symbol to which it
points, if any. */
int symbol_print;
+
+ /* Maximum print depth when printing nested aggregates. */
+ int max_depth;
};
/* The global print options set by the user. In general this should
@@ -246,4 +249,13 @@ extern int build_address_symbolic (struct gdbarch *,
int *line,
int *unmapped);
+/* Check to see if RECURSE is greater than or equal to the allowed
+ printing max-depth (see 'set print max-depth'). If it is then print an
+ ellipsis expression to STREAM and return true, otherwise return false.
+ LANGUAGE determines what type of ellipsis expression is printed. */
+
+extern bool val_print_check_max_depth (struct ui_file *stream, int recurse,
+ const struct value_print_options *opts,
+ const struct language_defn *language);
+
#endif