gdb: Introduce 'print max-depth' feature

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 affect printing
of 'var':

    | 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.

This commit should have no impact on MI output, expressions are
printed through the MI using -var-create and then -var-list-children.
As each use of -var-list-children only ever displays a single level of
an expression then the max-depth setting will have no impact.

This commit also adds the max-depth mechanism to the scripting
language pretty printers following basically the same rules as for the
built in value printing.

One quirk is that when printing a value using the display hint 'map',
if the keys of the map are structs then GDB will hide the keys one
depth level after it hides the values, this ensures that GDB produces
output like this:

  $1 = map_object = {[{key1}] = {...}, [{key2}] = {...}}

Instead of this less helpful output:

  $1 = map_object = {[{...}] = {...}, [{...}] = {...}}

This is covered by the new tests in gdb.python/py-nested-maps.exp.

gdb/ChangeLog:

	* 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.

gdb/doc/ChangeLog:

	* 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.

gdb/testsuite/ChangeLog:

	* 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.
This commit is contained in:
Andrew Burgess 2019-03-21 15:13:23 +00:00
parent 4be290b251
commit 2e62ab400f
26 changed files with 1484 additions and 35 deletions

View File

@ -1,3 +1,33 @@
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.

View File

@ -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

View File

@ -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 (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);
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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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 ()));

View File

@ -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)

View File

@ -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.

View File

@ -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;
}

View File

@ -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
}

View File

@ -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\\) \\) \\) \\)" }

View File

@ -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

View File

@ -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\"}"]

View File

@ -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)
}

View File

@ -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. */
}

View File

@ -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}}}"]

View File

@ -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.

View File

@ -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. */
}

View File

@ -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\}\}\}" \
]
}
}

View File

@ -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)

View File

@ -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

View File

@ -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);
}

View File

@ -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