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