Noice!
Overall looks good to me.
I think you're missing tests for C++ inheritance (all of regular, multiple and
virtual).
E.g,. with:
struct A { int a; int x; };
struct B : A { int b; int x; };
struct C : B { int c; int x; };
C c;
Today we print:
(gdb) p c
$1 = {<B> = {<A> = {a = 0, x = 0}, b = 0, x = 0}, c = 0, x = 0}
I suppose max-depth affects this as well. But given no tests,
can't be sure. :-)
Some nits pointed out below.
On 03/27/2019 09:53 PM, Andrew Burgess wrote:
> Introduce a new print setting max-depth which can be set with 'set
> print max-depth DEPTH'. The default value of DEPTH is 20, but this
> can also be set to unlimited.
>
> When GDB is printing a value containing nested structures GDB will
> stop descending at depth DEPTH. Here is a small example:
>
> 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 } } } };
>
> The following table shows how various depth settings effect printing
> of 'var':
s/effect/affect/
>
> | Depth Setting | Result of 'p var' |
> |---------------+--------------------------------|
> | Unlimited | $1 = {d = {c = {b = {a = 3}}}} |
> | 4 | $1 = {d = {c = {b = {a = 3}}}} |
> | 3 | $1 = {d = {c = {b = {...}}}} |
> | 2 | $1 = {d = {c = {...}}} |
> | 1 | $1 = {d = {...}} |
> | 0 | $1 = {...} |
>
> Only structures, unions, and arrays are replaced in this way, scalars
> and strings are not replaced.
>
> The replacement is counted from the level at which you print, not from
> the top level of the structure. So, consider the above example and
> this GDB session:
>
> (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}}
>
> Setting the max-depth to 2 doesn't prevent the user from exploring
> deeper into 'var' by asking for specific sub-fields to be printed.
>
> The motivation behind this feature is to try and give the user more
> control over how much is printed when examining large, complex data
> structures.
>
> The default max-depth of 20 means that there is a change in GDB's
> default behaviour. Someone printing a data structure with 20 levels
> of nesting will now see '{...}' instead of their data, they would need
> to adjust the max depth, or call print again naming a specific field
> in order to dig deeper into their data structure. If this is
> considered a problem then we could increase the default, or even make
> the default unlimited.
>
> This commit relies on the previous commit, which added a new field to
> the language structure, this new field was a string that contained the
> pattern that should be used when a structure/union/array is replaced
> in the output, this allows languages to use a syntax that is more
> appropriate, mostly this will be selecting the correct types of
> bracket '(...)' or '{...}', both of which are currently in use.
Could you say something about if/how this affects Python, Guile, and MI ?
> * GDB and GDBserver now support access to additional registers on
> diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c
> index 443c3b06dac..71da2b19755 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. */
> + struct value_print_options options_copy = *options;
> + struct value_print_options *opts = &options_copy;
You could drop the redundant "struct".
> +
> /* 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 parents depth when it comes to the
"parent's"
> + max print depth. */
> + if (opts->max_depth != -1 && opts->max_depth < INT_MAX)
> + ++opts->max_depth;
> + }
> @defun pretty_printer.display_hint (self)
> diff --git a/gdb/guile/scm-pretty-print.c b/gdb/guile/scm-pretty-print.c
> index e5096944b68..219e0ef63ad 100644
> --- a/gdb/guile/scm-pretty-print.c
> +++ b/gdb/guile/scm-pretty-print.c
> @@ -744,6 +744,16 @@ ppscm_print_children (SCM printer, enum display_hint hint,
> return;
> }
>
> + if (options->max_depth > -1
> + && recurse >= options->max_depth)
> + {
> + if (language->la_language == language_fortran)
> + fputs_filtered ("(...)", stream);
> + else
> + fputs_filtered ("{...}", stream);
Shouldn't this be using la_struct_too_deep_ellipsis here too?
> + return;
> + }
> diff --git a/gdb/python/py-prettyprint.c b/gdb/python/py-prettyprint.c
> index e64d1f88af8..504644143f3 100644
> --- a/gdb/python/py-prettyprint.c
> +++ b/gdb/python/py-prettyprint.c
> @@ -361,6 +361,16 @@ print_children (PyObject *printer, const char *hint,
> if (! PyObject_HasAttr (printer, gdbpy_children_cst))
> return;
>
> + if (options->max_depth > -1
> + && recurse >= options->max_depth)
> + {
> + if (language->la_language == language_fortran)
> + fputs_filtered ("(...)", stream);
> + else
> + fputs_filtered ("{...}", stream);
Ditto.
> + return;
> + }
> +
> diff --git a/gdb/testsuite/gdb.base/max-depth.exp b/gdb/testsuite/gdb.base/max-depth.exp
> new file mode 100644
> index 00000000000..777f66fab4e
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/max-depth.exp
> +proc compile_and_run_tests { lang } {
> + global testfile
> + global srcfile
> + global binfile
> + global subdir
> + global srcdir
> +
> + standard_testfile .c
> + set dir "$lang"
> +
> + # Create the additional flags
Add period.
> + set flags "debug"
> + lappend flags $lang
> +
> + set binfile [standard_output_file ${dir}/${testfile}]
> + if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "${flags}"] != "" } {
Spurious double space after "if".
Wonder if this could use build_executable or prepare_for_testing (eliminating
the clean_restart below).
> + unresolved "failed to compile"
> + return 0
> + }
> +
> + # Start with a fresh gdb.
> + clean_restart ${binfile}
> +
> + # Advance to main
Add period.
> + if { ![runto_main] } then {
> + fail "can't run to main"
> + return 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
Double space before "Expected".
> +++ b/gdb/testsuite/gdb.python/py-nested-maps.c
> @@ -0,0 +1,122 @@
> +
> +struct map_map_t *
> +create_map_map ()
create_map_map (void)
> +{
> 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 00000000000..146b9cab075
> --- /dev/null
> +++ b/gdb/testsuite/gdb.python/py-nested-maps.exp
> @@ -0,0 +1,211 @@
> +# 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.
> +
Should this say something about depth?
> +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'
Missing period.
> +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'
Missing period.
>
> # Issue a PASS and return true if evaluating CONDITION in the caller's
> diff --git a/gdb/valprint.c b/gdb/valprint.c
> index 10020901c2d..e47ac981ce8 100644
> --- a/gdb/valprint.c
> +++ b/gdb/valprint.c
> @@ -28,6 +28,7 @@
> #include "annotate.h"
> #include "valprint.h"
> #include "target-float.h"
> +#include "c-lang.h" /* For c_textual_element_type. */
> #include "extension.h"
> #include "ada-lang.h"
> #include "gdb_obstack.h"
> @@ -88,6 +89,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 +111,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 +284,39 @@ 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)
> +{
> + /* Resolve the real type. */
> + type = check_typedef (type);
> + while (TYPE_CODE (type) == TYPE_CODE_REF)
> + {
> + type = TYPE_TARGET_TYPE (type);
> + type = check_typedef (type);
> + }
> +
> + switch (TYPE_CODE (type))
> + {
> + case TYPE_CODE_ARRAY:
> + {
> + /* See if target type looks like a string. */
> + struct type * array_target_type = TYPE_TARGET_TYPE (type);
Spurious space after "*".
> + return (TYPE_LENGTH (type) > 0
> + && TYPE_LENGTH (array_target_type) > 0
> + && c_textual_element_type (array_target_type, 0));
Is using c_textual_element_type safe / the right thing to do
for all languages?
> + }
> + case TYPE_CODE_STRING:
> + return true;
> + default:
> + /* Check for scalar. */
> + return val_print_scalar_type_p(type);
> + }
> +}
> +
> /* See its definition in value.h. */
>
> int
> @@ -1054,6 +1090,15 @@ val_print (struct type *type, LONGEST embedded_offset,
> return;
> }
>
> + if (!val_print_scalar_or_string_type_p (type)
> + && options->max_depth > -1
> + && recurse >= options->max_depth)
> + {
> + gdb_assert (language->la_struct_too_deep_ellipsis != NULL);
Maybe put this assertion / validation where we register languages
instead, so you'd do this only once and in one place, instead of
potentially at all usage spots?
> + fputs_filtered (language->la_struct_too_deep_ellipsis, stream);
> + return;
> + }
> +
Thanks,
Pedro Alves
@@ -10,6 +10,15 @@
* Support for Pointer Authentication on AArch64 Linux.
+* 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 behaviour back.
+
*** Changes in GDB 8.3
* GDB and GDBserver now support access to additional registers on
@@ -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. */
+ struct value_print_options options_copy = *options;
+ struct 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 parents 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
@@ -334,8 +345,7 @@ cp_print_value_fields (struct type *type, struct type *real_type,
END_CATCH
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)
{
@@ -347,20 +357,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);
}
}
@@ -10560,6 +10560,63 @@
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
+
+@noindent
+and with @code{set print max-depth unlimited} in effect @samp{p var}
+would print
+
+@smallexample
+$1 = @{d = @{c = @{b = @{a = 3@}@}@}@}
+@end smallexample
+
+@noindent
+with @code{set print max-depth 0} in effect @samp{p var}
+would print
+
+@smallexample
+$1 = @{...@}
+@end smallexample
+
+@noindent
+with @code{set print max-depth 1} in effect @samp{p var}
+would print
+
+@smallexample
+$1 = @{d = @{...@}@}
+@end smallexample
+
+@noindent
+with @code{set print max-depth 2} in effect @samp{p var}
+would print
+
+@smallexample
+$1 = @{d = @{c = @{...@}@}@}
+@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
@@ -1469,6 +1469,9 @@
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
@@ -1285,6 +1285,9 @@
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)
@@ -744,6 +744,16 @@ ppscm_print_children (SCM printer, enum display_hint hint,
return;
}
+ if (options->max_depth > -1
+ && recurse >= options->max_depth)
+ {
+ if (language->la_language == language_fortran)
+ fputs_filtered ("(...)", stream);
+ else
+ fputs_filtered ("{...}", stream);
+ return;
+ }
+
/* If we are printing a map or an array, we want special formatting. */
is_map = hint == HINT_MAP;
is_array = hint == HINT_ARRAY;
@@ -898,7 +908,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)
@@ -361,6 +361,16 @@ print_children (PyObject *printer, const char *hint,
if (! PyObject_HasAttr (printer, gdbpy_children_cst))
return;
+ if (options->max_depth > -1
+ && recurse >= options->max_depth)
+ {
+ if (language->la_language == language_fortran)
+ fputs_filtered ("(...)", stream);
+ else
+ fputs_filtered ("{...}", stream);
+ return;
+ }
+
/* If we are printing a map or an array, we want some special
formatting. */
is_map = hint && ! strcmp (hint, "map");
@@ -518,7 +528,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)
new file mode 100644
@@ -0,0 +1,209 @@
+/* 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;
+
+int
+main ()
+{
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,122 @@
+# 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 subdir
+ global srcdir
+
+ standard_testfile .c
+ set dir "$lang"
+
+ # Create the additional flags
+ set flags "debug"
+ lappend flags $lang
+
+ set binfile [standard_output_file ${dir}/${testfile}]
+ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "${flags}"] != "" } {
+ unresolved "failed to compile"
+ return 0
+ }
+
+ # Start with a fresh gdb.
+ clean_restart ${binfile}
+
+ # 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}}"}
+}
+
+foreach_with_prefix l $lang {
+ compile_and_run_tests $l
+}
new file mode 100644
@@ -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 = \\( c = \\(\\.\\.\\.\\) \\) \\)" \
+ "\\( d = \\( c = \\( b = \\(\\.\\.\\.\\), array = \\(\\.\\.\\.\\) \\) \\) \\)" \
+ "\\( d = \\( c = \\( b = \\( a = 1 \\), array = \\(0, 0, 0, 0, 0\\) \\) \\) \\)" }
new file mode 100644
@@ -0,0 +1,40 @@
+! 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
+ 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
+ l = .FALSE. ! stop-here
+end program max_depth_test
new file mode 100644
@@ -0,0 +1,122 @@
+/* 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;
+};
+
+struct map_map_t
+{
+ int length;
+ struct map_t **values;
+};
+
+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;
+}
+
+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 ()
+{
+ struct map_map_t *mm = malloc (sizeof (struct map_map_t));
+ mm->length = 0;
+ mm->values = NULL;
+}
+
+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 ()
+{
+ 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. */
+}
new file mode 100644
@@ -0,0 +1,211 @@
+# 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.
+
+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" \
+ " \}" \
+ " \}" \
+ "\}" ] \
+ ]
+}
new file mode 100644
@@ -0,0 +1,129 @@
+# 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):
+ return None
+
+ 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):
+ return None
+
+ 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)
@@ -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
@@ -28,6 +28,7 @@
#include "annotate.h"
#include "valprint.h"
#include "target-float.h"
+#include "c-lang.h" /* For c_textual_element_type. */
#include "extension.h"
#include "ada-lang.h"
#include "gdb_obstack.h"
@@ -88,6 +89,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 +111,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 +284,39 @@ 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)
+{
+ /* Resolve the real type. */
+ type = check_typedef (type);
+ while (TYPE_CODE (type) == TYPE_CODE_REF)
+ {
+ type = TYPE_TARGET_TYPE (type);
+ type = check_typedef (type);
+ }
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+ {
+ /* See if target type looks like a string. */
+ struct type * array_target_type = TYPE_TARGET_TYPE (type);
+ return (TYPE_LENGTH (type) > 0
+ && TYPE_LENGTH (array_target_type) > 0
+ && c_textual_element_type (array_target_type, 0));
+ }
+ case TYPE_CODE_STRING:
+ return true;
+ default:
+ /* Check for scalar. */
+ return val_print_scalar_type_p(type);
+ }
+}
+
/* See its definition in value.h. */
int
@@ -1054,6 +1090,15 @@ val_print (struct type *type, LONGEST embedded_offset,
return;
}
+ if (!val_print_scalar_or_string_type_p (type)
+ && 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;
+ }
+
TRY
{
language->la_val_print (type, embedded_offset, address,
@@ -2860,6 +2905,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.
@@ -3153,4 +3207,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);
}
@@ -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