From a0c07915778486a950952139d27c01d4285b02b4 Mon Sep 17 00:00:00 2001 From: Andrew Burgess Date: Fri, 10 Feb 2023 23:49:19 +0000 Subject: [PATCH] GDB: Introduce limited array lengths while printing values This commit introduces the idea of loading only part of an array in order to print it, what I call "limited length" arrays. The motivation behind this work is to make it possible to print slices of very large arrays, where very large means bigger than `max-value-size'. Consider this GDB session with the current GDB: (gdb) set max-value-size 100 (gdb) p large_1d_array value requires 400 bytes, which is more than max-value-size (gdb) p -elements 10 -- large_1d_array value requires 400 bytes, which is more than max-value-size notice that the request to print 10 elements still fails, even though 10 elements should be less than the max-value-size. With a patched version of GDB: (gdb) p -elements 10 -- large_1d_array $1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9...} So now the print has succeeded. It also has loaded `max-value-size' worth of data into value history, so the recorded value can be accessed consistently: (gdb) p -elements 10 -- $1 $2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9...} (gdb) p $1 $3 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, } (gdb) Accesses with other languages work similarly, although for Ada only C-style [] array element/dimension accesses use history. For both Ada and Fortran () array element/dimension accesses go straight to the inferior, bypassing the value history just as with C pointers. Co-Authored-By: Maciej W. Rozycki --- gdb/NEWS | 6 + gdb/doc/gdb.texinfo | 9 + gdb/f-valprint.c | 32 ++- gdb/printcmd.c | 16 ++ gdb/testsuite/gdb.ada/limited-length.exp | 264 +++++++++++++++++++ gdb/testsuite/gdb.ada/limited-length/foo.adb | 37 +++ gdb/testsuite/gdb.ada/limited-length/pck.adb | 25 ++ gdb/testsuite/gdb.ada/limited-length/pck.ads | 21 ++ gdb/testsuite/gdb.base/limited-length.c | 48 ++++ gdb/testsuite/gdb.base/limited-length.exp | 242 +++++++++++++++++ gdb/testsuite/gdb.fortran/limited-length.exp | 220 ++++++++++++++++ gdb/testsuite/gdb.fortran/limited-length.f90 | 39 +++ gdb/valprint.c | 10 +- gdb/value.c | 187 +++++++++++-- gdb/value.h | 17 ++ 15 files changed, 1149 insertions(+), 24 deletions(-) create mode 100644 gdb/testsuite/gdb.ada/limited-length.exp create mode 100644 gdb/testsuite/gdb.ada/limited-length/foo.adb create mode 100644 gdb/testsuite/gdb.ada/limited-length/pck.adb create mode 100644 gdb/testsuite/gdb.ada/limited-length/pck.ads create mode 100644 gdb/testsuite/gdb.base/limited-length.c create mode 100644 gdb/testsuite/gdb.base/limited-length.exp create mode 100644 gdb/testsuite/gdb.fortran/limited-length.exp create mode 100644 gdb/testsuite/gdb.fortran/limited-length.f90 diff --git a/gdb/NEWS b/gdb/NEWS index b85923cf80d..1328f4faa80 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -44,6 +44,12 @@ keyword already gave an error when used multiple times with the watch command, this remains unchanged. +* The 'set print elements' setting now helps when printing large arrays. + If an array would otherwise exceed max-value-size, but 'print elements' + is set such that the size of elements to print is less than or equal + to 'max-value-size', GDB will now still print the array, however only + 'max-value-size' worth of data will be added into the value history. + * New commands maintenance print record-instruction [ N ] diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 7b128053b5a..0beb45857c3 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -11759,6 +11759,14 @@ When @value{GDBN} starts, this limit is set to 200. Setting @var{number-of-elements} to @code{unlimited} or zero means that the number of elements to print is unlimited. +When printing very large arrays, whose size is greater than +@code{max-value-size} (@pxref{set max-value-size,,max-value-size}), +if the @code{print elements} is set such that the size of the elements +being printed is less than or equal to @code{max-value-size}, then +@value{GDBN} will print the array (up to the @code{print elements} limit), +and only @code{max-value-size} worth of data will be added into the value +history (@pxref{Value History, ,Value History}). + @item show print elements Display the number of elements of a large array that @value{GDBN} will print. @@ -14174,6 +14182,7 @@ may indicate a value that is incorrectly large, this in turn may cause @value{GDBN} to try and allocate an overly large amount of memory. @table @code +@anchor{set max-value-size} @kindex set max-value-size @item set max-value-size @var{bytes} @itemx set max-value-size unlimited diff --git a/gdb/f-valprint.c b/gdb/f-valprint.c index 55dbcc8309f..b08613f9153 100644 --- a/gdb/f-valprint.c +++ b/gdb/f-valprint.c @@ -261,10 +261,20 @@ public: size_t dim_indx = m_dimension - 1; struct type *elt_type_prev = m_elt_type_prev; LONGEST elt_off_prev = m_elt_off_prev; - bool repeated = (m_options->repeat_count_threshold < UINT_MAX - && elt_type_prev != nullptr - && value_contents_eq (m_val, elt_off_prev, m_val, elt_off, - elt_type->length ())); + bool repeated = false; + + if (m_options->repeat_count_threshold < UINT_MAX + && elt_type_prev != nullptr) + { + struct value *e_val = value_from_component (m_val, elt_type, elt_off); + struct value *e_prev = value_from_component (m_val, elt_type, + elt_off_prev); + repeated = ((value_entirely_available (e_prev) + && value_entirely_available (e_val) + && value_contents_eq (e_prev, e_val)) + || (value_entirely_unavailable (e_prev) + && value_entirely_unavailable (e_val))); + } if (repeated) m_nrepeats++; @@ -333,7 +343,7 @@ private: have been sliced and we do not want to compare any memory contents present between the slices requested. */ bool - dimension_contents_eq (const struct value *val, struct type *type, + dimension_contents_eq (struct value *val, struct type *type, LONGEST offset1, LONGEST offset2) { if (type->code () == TYPE_CODE_ARRAY @@ -362,8 +372,16 @@ private: return true; } else - return value_contents_eq (val, offset1, val, offset2, - type->length ()); + { + struct value *e_val1 = value_from_component (val, type, offset1); + struct value *e_val2 = value_from_component (val, type, offset2); + + return ((value_entirely_available (e_val1) + && value_entirely_available (e_val2) + && value_contents_eq (e_val1, e_val2)) + || (value_entirely_unavailable (e_val1) + && value_entirely_unavailable (e_val2))); + } } /* The number of elements printed so far. */ diff --git a/gdb/printcmd.c b/gdb/printcmd.c index 7f3551327a8..9bda60d6f80 100644 --- a/gdb/printcmd.c +++ b/gdb/printcmd.c @@ -1242,6 +1242,11 @@ print_command_parse_format (const char **expp, const char *cmdname, void print_value (value *val, const value_print_options &opts) { + /* This setting allows large arrays to be printed by limiting the + number of elements that are loaded into GDB's memory; we only + need to load as many array elements as we plan to print. */ + scoped_array_length_limiting limit_large_arrays (opts.print_max); + int histindex = record_latest_value (val); annotate_value_history_begin (histindex, value_type (val)); @@ -1301,6 +1306,11 @@ process_print_command_args (const char *args, value_print_options *print_opts, if (exp != nullptr && *exp) { + /* This setting allows large arrays to be printed by limiting the + number of elements that are loaded into GDB's memory; we only + need to load as many array elements as we plan to print. */ + scoped_array_length_limiting limit_large_arrays (print_opts->print_max); + /* VOIDPRINT is true to indicate that we do want to print a void value, so invert it for parse_expression. */ expression_up expr = parse_expression (exp, nullptr, !voidprint); @@ -1489,6 +1499,12 @@ output_command (const char *exp, int from_tty) get_formatted_print_options (&opts, format); opts.raw = fmt.raw; + + /* This setting allows large arrays to be printed by limiting the + number of elements that are loaded into GDB's memory; we only + need to load as many array elements as we plan to print. */ + scoped_array_length_limiting limit_large_arrays (opts.print_max); + print_formatted (val, fmt.size, &opts, gdb_stdout); annotate_value_end (); diff --git a/gdb/testsuite/gdb.ada/limited-length.exp b/gdb/testsuite/gdb.ada/limited-length.exp new file mode 100644 index 00000000000..1e3afe72c7e --- /dev/null +++ b/gdb/testsuite/gdb.ada/limited-length.exp @@ -0,0 +1,264 @@ +# Copyright 2023 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 . + +load_lib "ada.exp" + +require allow_ada_tests + +standard_ada_testfile foo + +if {[gdb_compile_ada "${srcfile}" "${binfile}" executable \ + [list debug ]] != "" } { + return -1 +} + +clean_restart ${testfile} + +set bp_location [gdb_get_line_number "STOP" ${testdir}/foo.adb] +if {![runto "foo.adb:$bp_location"]} { + perror "Couldn't run ${testfile}" + return +} + +with_test_prefix "with standard max-value size" { + gdb_test "print Large_1d_Array" \ + " = \\(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,\ + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\ + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,\ + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,\ + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,\ + 61, 62, 63, 64\\)" + gdb_test -nonl "output Large_1d_Array" \ + "\\(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,\ + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\ + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,\ + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,\ + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,\ + 61, 62, 63, 64\\)" + gdb_test "print Large_3d_Array" \ + " = \\(\\(\\(1, 2, 3, 4\\), \\(5, 6, 7, 8\\),\ + \\(9, 10, 11, 12\\), \\(13, 14, 15, 16\\)\\),\ + \\(\\(17, 18, 19, 20\\), \\(21, 22, 23, 24\\),\ + \\(25, 26, 27, 28\\), \\(29, 30, 31, 32\\)\\),\ + \\(\\(33, 34, 35, 36\\), \\(37, 38, 39, 40\\),\ + \\(41, 42, 43, 44\\), \\(45, 46, 47, 48\\)\\),\ + \\(\\(49, 50, 51, 52\\), \\(53, 54, 55, 56\\),\ + \\(57, 58, 59, 60\\), \\(61, 62, 63, 64\\)\\)\\)" + gdb_test -nonl "output Large_3d_Array" \ + "\\(\\(\\(1, 2, 3, 4\\), \\(5, 6, 7, 8\\),\ + \\(9, 10, 11, 12\\), \\(13, 14, 15, 16\\)\\),\ + \\(\\(17, 18, 19, 20\\), \\(21, 22, 23, 24\\),\ + \\(25, 26, 27, 28\\), \\(29, 30, 31, 32\\)\\),\ + \\(\\(33, 34, 35, 36\\), \\(37, 38, 39, 40\\),\ + \\(41, 42, 43, 44\\), \\(45, 46, 47, 48\\)\\),\ + \\(\\(49, 50, 51, 52\\), \\(53, 54, 55, 56\\),\ + \\(57, 58, 59, 60\\), \\(61, 62, 63, 64\\)\\)\\)" +} + +# Set the max-value-size so we can only print 33 elements. +set elements 33 +set elem_size [get_valueof "/d" "(Large_1d_Array(1)'Size + 7) / 8" "*unknown*"] +gdb_test_no_output "set max-value-size [expr $elem_size * $elements]" + +with_test_prefix "with reduced max-value size" { + gdb_test "print Large_1d_Array" \ + "value of type `.*' requires $decimal bytes,\ + which is more than max-value-size" + gdb_test "output Large_1d_Array" \ + "value of type `.*' requires $decimal bytes,\ + which is more than max-value-size" + gdb_test "print Large_3d_Array" \ + "value of type `.*' requires $decimal bytes,\ + which is more than max-value-size" + gdb_test "output Large_3d_Array" \ + "value of type `.*' requires $decimal bytes,\ + which is more than max-value-size" +} + +with_test_prefix "with reduced print -elements flag" { + gdb_test "print -elements 2 -- Large_1d_Array" \ + " = \\(1, 2\\.\\.\\.\\)" + gdb_test "print -elements 2 -- Large_3d_Array" \ + " = \\(\\(\\(1, 2\\.\\.\\.\\), \\(5, 6\\.\\.\\.\\)\\.\\.\\.\\),\ + \\(\\(17, 18\\.\\.\\.\\),\ + \\(21, 22\\.\\.\\.\\)\\.\\.\\.\\)\\.\\.\\.\\)" +} + +gdb_test_no_output "set print elements 2" + +with_test_prefix "with reduced print elements" { + gdb_test "print Large_1d_Array" \ + " = \\(1, 2\\.\\.\\.\\)" + gdb_test -nonl "output Large_1d_Array" \ + "\\(1, 2\\.\\.\\.\\)" + + gdb_test "print \$" \ + " = \\(1, 2\\.\\.\\.\\)" \ + "print Large_1d_Array from history" + gdb_test -nonl "output \$\$" \ + "\\(1, 2\\.\\.\\.\\)" \ + "output Large_1d_Array from history" + + gdb_test "print Large_3d_Array" \ + " = \\(\\(\\(1, 2\\.\\.\\.\\), \\(5, 6\\.\\.\\.\\)\\.\\.\\.\\),\ + \\(\\(17, 18\\.\\.\\.\\),\ + \\(21, 22\\.\\.\\.\\)\\.\\.\\.\\)\\.\\.\\.\\)" + gdb_test -nonl "output Large_3d_Array" \ + "\\(\\(\\(1, 2\\.\\.\\.\\), \\(5, 6\\.\\.\\.\\)\\.\\.\\.\\),\ + \\(\\(17, 18\\.\\.\\.\\),\ + \\(21, 22\\.\\.\\.\\)\\.\\.\\.\\)\\.\\.\\.\\)" + + gdb_test "print \$" \ + " = \\(\\(\\(1, 2\\.\\.\\.\\), \\(5, 6\\.\\.\\.\\)\\.\\.\\.\\),\ + \\(\\(17, 18\\.\\.\\.\\),\ + \\(21, 22\\.\\.\\.\\)\\.\\.\\.\\)\\.\\.\\.\\)" \ + "print Large_3d_Array from history" + gdb_test -nonl "output \$\$" \ + "\\(\\(\\(1, 2\\.\\.\\.\\), \\(5, 6\\.\\.\\.\\)\\.\\.\\.\\),\ + \\(\\(17, 18\\.\\.\\.\\),\ + \\(21, 22\\.\\.\\.\\)\\.\\.\\.\\)\\.\\.\\.\\)" \ + "output Large_3d_Array from history" +} + +gdb_test_no_output "set print elements $elements" + +with_test_prefix "with print elements matching max-value size" { + gdb_test "print \$\$2" \ + " = \\(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,\ + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\ + 25, 26, 27, 28, 29, 30, 31, 32, 33\\.\\.\\.\\)" \ + "print Large_1d_Array from history" + gdb_test -nonl "output \$\$3" \ + "\\(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,\ + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\ + 25, 26, 27, 28, 29, 30, 31, 32, 33\\.\\.\\.\\)" \ + "output Large_1d_Array from history" + + gdb_test "print \$\$2" \ + " = \\(\\(\\(1, 2, 3, 4\\), \\(5, 6, 7, 8\\),\ + \\(9, 10, 11, 12\\), \\(13, 14, 15, 16\\)\\),\ + \\(\\(17, 18, 19, 20\\), \\(21, 22, 23, 24\\),\ + \\(25, 26, 27, 28\\), \\(29, 30, 31, 32\\)\\),\ + \\(\\(33(?:, )\{3\}\\)(?:,\ + \\((?:, )\{3\}\\))\{3\}\\),\ + \\(\\((?:, )\{3\}\\)(?:,\ + \\((?:, )\{3\}\\))\{3\}\\)\\)" \ + "print Large_3d_Array from history" + gdb_test -nonl "output \$\$3" \ + "\\(\\(\\(1, 2, 3, 4\\), \\(5, 6, 7, 8\\),\ + \\(9, 10, 11, 12\\), \\(13, 14, 15, 16\\)\\),\ + \\(\\(17, 18, 19, 20\\), \\(21, 22, 23, 24\\),\ + \\(25, 26, 27, 28\\), \\(29, 30, 31, 32\\)\\),\ + \\(\\(33(?:, )\{3\}\\)(?:,\ + \\((?:, )\{3\}\\))\{3\}\\),\ + \\(\\((?:, )\{3\}\\)(?:,\ + \\((?:, )\{3\}\\))\{3\}\\)\\)" \ + "output Large_3d_Array from history" +} + +gdb_test_no_output "set max-value-size unlimited" +gdb_test_no_output "set print elements unlimited" +gdb_test_no_output "set print repeats 2" + +with_test_prefix "with unlimited print elements" { + gdb_test "print \$\$" \ + " = \\(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,\ + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\ + 25, 26, 27, 28, 29, 30, 31, 32, 33,\ + \\)" \ + "print Large_1d_Array from history" + gdb_test -nonl "output \$\$2" \ + "\\(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,\ + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\ + 25, 26, 27, 28, 29, 30, 31, 32, 33,\ + \\)" \ + "output Large_1d_Array from history" + + gdb_test "print \$\$" \ + " = \\(\\(\\(1, 2, 3, 4\\), \\(5, 6, 7, 8\\),\ + \\(9, 10, 11, 12\\), \\(13, 14, 15, 16\\)\\),\ + \\(\\(17, 18, 19, 20\\), \\(21, 22, 23, 24\\),\ + \\(25, 26, 27, 28\\), \\(29, 30, 31, 32\\)\\),\ + \\(\\(33, \\),\ + \\( \\) \\),\ + \\(\\( \\)\ + \\)\\)" \ + "print Large_3d_Array from history" + gdb_test -nonl "output \$\$2" \ + "\\(\\(\\(1, 2, 3, 4\\), \\(5, 6, 7, 8\\),\ + \\(9, 10, 11, 12\\), \\(13, 14, 15, 16\\)\\),\ + \\(\\(17, 18, 19, 20\\), \\(21, 22, 23, 24\\),\ + \\(25, 26, 27, 28\\), \\(29, 30, 31, 32\\)\\),\ + \\(\\(33, \\),\ + \\( \\) \\),\ + \\(\\( \\) \\)\\)" \ + "output Large_3d_Array from history" + + gdb_test "print \$\[2\]" \ + " = \\(\\(17, 18, 19, 20\\), \\(21, 22, 23, 24\\),\ + \\(25, 26, 27, 28\\), \\(29, 30, 31, 32\\)\\)" \ + "print available Large_3d_Array row from history" + gdb_test -nonl "output \$\$\[2\]" \ + "\\(\\(17, 18, 19, 20\\), \\(21, 22, 23, 24\\),\ + \\(25, 26, 27, 28\\), \\(29, 30, 31, 32\\)\\)" \ + "output available Large_3d_Array row from history" + + gdb_test "print \$\$\[3\]" \ + " = \\(\\(33, \\),\ + \\( \\) \\)" \ + "print partially available Large_3d_Array row from history" + gdb_test -nonl "output \$\$2\[3\]" \ + "\\(\\(33, \\),\ + \\( \\) \\)" \ + "output partially available Large_3d_Array row from history" + + # These go straigth to the inferior. + gdb_test "print \$\$2(3)" \ + " = \\(\\(33, 34, 35, 36\\), \\(37, 38, 39, 40\\),\ + \\(41, 42, 43, 44\\), \\(45, 46, 47, 48\\)\\)" \ + "print partially available Large_3d_Array row bypassing history" + gdb_test -nonl "output \$\$3(3)" \ + "\\(\\(33, 34, 35, 36\\), \\(37, 38, 39, 40\\),\ + \\(41, 42, 43, 44\\), \\(45, 46, 47, 48\\)\\)" \ + "output partially available Large_3d_Array row bypassing history" + + gdb_test "print \$\$3\[4\]" \ + " = " \ + "print unavailable Large_3d_Array row from history" + gdb_test -nonl "output \$\$4\[4\]" \ + "" \ + "output unavailable Large_3d_Array row from history" + + gdb_test "print \$\$4\[3\]\[1\]\[1\]" \ + " = 33" \ + "print available Large_3d_Array element from history" + gdb_test -nonl "output \$\$5\[3\]\[1\]\[1\]" \ + "33" \ + "output available Large_3d_Array element from history" + + gdb_test "print \$\$5\[3\]\[1\]\[2\]" \ + " = " \ + "print unavailable Large_3d_Array element from history" + gdb_test -nonl "output \$\$6\[3\]\[1\]\[2\]" \ + "" \ + "output unavailable Large_3d_Array element from history" + + gdb_test "print \$\$6\[3\]\[1\]\[1\] + \$\$6\[3\]\[1\]\[2\]" \ + "value is not available" \ + "print expression referring unavailable element from history" + gdb_test "output \$\$6\[3\]\[1\]\[1\] + \$\$6\[3\]\[1\]\[2\]" \ + "value is not available" \ + "output expression referring unavailable element from history" +} diff --git a/gdb/testsuite/gdb.ada/limited-length/foo.adb b/gdb/testsuite/gdb.ada/limited-length/foo.adb new file mode 100644 index 00000000000..b9505446655 --- /dev/null +++ b/gdb/testsuite/gdb.ada/limited-length/foo.adb @@ -0,0 +1,37 @@ +-- This testcase is part of GDB, the GNU debugger. +-- +-- Copyright 2023 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 . + +with Pck; use Pck; + +procedure Foo is + Large_1d_Array : array (1..64) of Integer; + Large_3d_Array : array (1..4,1..4,1..4) of Integer; + Count : Integer := 1; +begin + for i in 1 .. 4 loop + for j in 1 .. 4 loop + for k in 1 .. 4 loop + Large_1d_Array (Count) := Count; + Large_3d_Array (i,j,k) := Count; + Count := Count + 1; + end loop; + end loop; + end loop; + Do_Nothing (Large_1d_Array'Address); + Do_Nothing (Large_3d_Array'Address); -- STOP +end Foo; + diff --git a/gdb/testsuite/gdb.ada/limited-length/pck.adb b/gdb/testsuite/gdb.ada/limited-length/pck.adb new file mode 100644 index 00000000000..53443027df9 --- /dev/null +++ b/gdb/testsuite/gdb.ada/limited-length/pck.adb @@ -0,0 +1,25 @@ +-- This testcase is part of GDB, the GNU debugger. +-- +-- Copyright 2023 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 . + +package body Pck is + + procedure Do_Nothing (A : System.Address) is + begin + null; + end Do_Nothing; + +end Pck; diff --git a/gdb/testsuite/gdb.ada/limited-length/pck.ads b/gdb/testsuite/gdb.ada/limited-length/pck.ads new file mode 100644 index 00000000000..2ef2f6c9bdb --- /dev/null +++ b/gdb/testsuite/gdb.ada/limited-length/pck.ads @@ -0,0 +1,21 @@ +-- This testcase is part of GDB, the GNU debugger. +-- +-- Copyright 2023 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 . + +with System; +package Pck is + procedure Do_Nothing (A : System.Address); +end Pck; diff --git a/gdb/testsuite/gdb.base/limited-length.c b/gdb/testsuite/gdb.base/limited-length.c new file mode 100644 index 00000000000..177400d3894 --- /dev/null +++ b/gdb/testsuite/gdb.base/limited-length.c @@ -0,0 +1,48 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright (C) 2023 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 . */ + +int large_1d_array[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99 +}; + +int large_2d_array[][10] = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}, + {20, 21, 22, 23, 24, 25, 26, 27, 28, 29}, + {30, 31, 32, 33, 34, 35, 36, 37, 38, 39}, + {40, 41, 42, 43, 44, 45, 46, 47, 48, 49}, + {50, 51, 52, 53, 54, 55, 56, 57, 58, 59}, + {60, 61, 62, 63, 64, 65, 66, 67, 68, 69}, + {70, 71, 72, 73, 74, 75, 76, 77, 78, 79}, + {80, 81, 82, 83, 84, 85, 86, 87, 88, 89}, + {90, 91, 92, 93, 94, 95, 96, 97, 98, 99} +}; + +int +main () +{ + return 0; +} diff --git a/gdb/testsuite/gdb.base/limited-length.exp b/gdb/testsuite/gdb.base/limited-length.exp new file mode 100644 index 00000000000..2918b1a1fe9 --- /dev/null +++ b/gdb/testsuite/gdb.base/limited-length.exp @@ -0,0 +1,242 @@ +# Copyright 2023 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 . + +# Test GDB's limited array printing. + +standard_testfile + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile]} { + return -1 +} + +if {![runto_main]} { + perror "couldn't run to breakpoint" + continue +} + +with_test_prefix "with standard max-value size" { + gdb_test "print large_1d_array" \ + " = \\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,\ + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,\ + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,\ + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\ + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,\ + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,\ + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,\ + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,\ + 96, 97, 98, 99\\\}" + gdb_test -nonl "output large_1d_array" \ + "\\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,\ + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,\ + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,\ + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\ + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,\ + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,\ + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,\ + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,\ + 96, 97, 98, 99\\\}" + gdb_test "print large_2d_array" \ + " = \\\{\\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9\\\},\ + \\\{10, 11, 12, 13, 14, 15, 16, 17, 18, 19\\\},\ + \\\{20, 21, 22, 23, 24, 25, 26, 27, 28, 29\\\},\ + \\\{30, 31, 32, 33, 34, 35, 36, 37, 38, 39\\\},\ + \\\{40, 41, 42, 43, 44, 45, 46, 47, 48, 49\\\},\ + \\\{50, 51, 52, 53, 54, 55, 56, 57, 58, 59\\\},\ + \\\{60, 61, 62, 63, 64, 65, 66, 67, 68, 69\\\},\ + \\\{70, 71, 72, 73, 74, 75, 76, 77, 78, 79\\\},\ + \\\{80, 81, 82, 83, 84, 85, 86, 87, 88, 89\\\},\ + \\\{90, 91, 92, 93, 94, 95, 96, 97, 98, 99\\\}\\\}" + gdb_test -nonl "output large_2d_array" \ + "\\\{\\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9\\\},\ + \\\{10, 11, 12, 13, 14, 15, 16, 17, 18, 19\\\},\ + \\\{20, 21, 22, 23, 24, 25, 26, 27, 28, 29\\\},\ + \\\{30, 31, 32, 33, 34, 35, 36, 37, 38, 39\\\},\ + \\\{40, 41, 42, 43, 44, 45, 46, 47, 48, 49\\\},\ + \\\{50, 51, 52, 53, 54, 55, 56, 57, 58, 59\\\},\ + \\\{60, 61, 62, 63, 64, 65, 66, 67, 68, 69\\\},\ + \\\{70, 71, 72, 73, 74, 75, 76, 77, 78, 79\\\},\ + \\\{80, 81, 82, 83, 84, 85, 86, 87, 88, 89\\\},\ + \\\{90, 91, 92, 93, 94, 95, 96, 97, 98, 99\\\}\\\}" +} + +# Set the max-value-size so we can only print 51 elements. +set elements 51 +set int_size [get_valueof "/d" "sizeof(large_1d_array\[0\])" "*unknown*"] +gdb_test_no_output "set max-value-size [expr $int_size * $elements]" + +with_test_prefix "with reduced max-value size" { + gdb_test "print large_1d_array" \ + "\r\nvalue requires $decimal bytes, which is more than max-value-size" + gdb_test "output large_1d_array" \ + "\r\nvalue requires $decimal bytes, which is more than max-value-size" + gdb_test "print large_2d_array" \ + "\r\nvalue requires $decimal bytes, which is more than max-value-size" + gdb_test "output large_2d_array" \ + "\r\nvalue requires $decimal bytes, which is more than max-value-size" +} + +gdb_test_no_output "set print elements 3" + +with_test_prefix "with reduced print elements" { + gdb_test "print large_1d_array" \ + " = \\\{0, 1, 2\\.\\.\\.\\\}" + gdb_test -nonl "output large_1d_array" \ + "\\\{0, 1, 2\\.\\.\\.\\\}" + + gdb_test "print \$" \ + " = \\\{0, 1, 2\\.\\.\\.\\\}" \ + "print large_1d_array from history" + gdb_test -nonl "output \$\$" \ + "\\\{0, 1, 2\\.\\.\\.\\\}" \ + "output large_1d_array from history" + + gdb_test "print large_2d_array" \ + " = \\\{\\\{0, 1, 2\\.\\.\\.\\\}, \\\{10, 11, 12\\.\\.\\.\\\},\ + \\\{20, 21, 22\\.\\.\\.\\\}\\.\\.\\.\\\}" + gdb_test -nonl "output large_2d_array" \ + "\\\{\\\{0, 1, 2\\.\\.\\.\\\}, \\\{10, 11, 12\\.\\.\\.\\\},\ + \\\{20, 21, 22\\.\\.\\.\\\}\\.\\.\\.\\\}" + + gdb_test "print \$" \ + " = \\\{\\\{0, 1, 2\\.\\.\\.\\\}, \\\{10, 11, 12\\.\\.\\.\\\},\ + \\\{20, 21, 22\\.\\.\\.\\\}\\.\\.\\.\\\}" \ + "print large_2d_array from history" + gdb_test -nonl "output \$\$" \ + "\\\{\\\{0, 1, 2\\.\\.\\.\\\}, \\\{10, 11, 12\\.\\.\\.\\\},\ + \\\{20, 21, 22\\.\\.\\.\\\}\\.\\.\\.\\\}" \ + "output large_2d_array from history" +} + +gdb_test_no_output "set print elements $elements" + +with_test_prefix "with print elements matching max-value size" { + gdb_test "print \$\$2" \ + " = \\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,\ + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,\ + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,\ + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\ + 48, 49, 50\\.\\.\\.\\\}" \ + "print large_1d_array from history" + gdb_test -nonl "output \$\$3" \ + "\\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,\ + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,\ + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,\ + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\ + 48, 49, 50\\.\\.\\.\\\}" \ + "output large_1d_array from history" + + gdb_test "print \$\$2" \ + " = \\\{\\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9\\\},\ + \\\{10, 11, 12, 13, 14, 15, 16, 17, 18, 19\\\},\ + \\\{20, 21, 22, 23, 24, 25, 26, 27, 28, 29\\\},\ + \\\{30, 31, 32, 33, 34, 35, 36, 37, 38, 39\\\},\ + \\\{40, 41, 42, 43, 44, 45, 46, 47, 48, 49\\\},\ + \\\{50(?:, )\{9\}\\\}(?:,\ + \\\{(?:, )\{9\}\\\})\{4\}\\\}" \ + "print large_2d_array from history" + gdb_test -nonl "output \$\$3" \ + "\\\{\\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9\\\},\ + \\\{10, 11, 12, 13, 14, 15, 16, 17, 18, 19\\\},\ + \\\{20, 21, 22, 23, 24, 25, 26, 27, 28, 29\\\},\ + \\\{30, 31, 32, 33, 34, 35, 36, 37, 38, 39\\\},\ + \\\{40, 41, 42, 43, 44, 45, 46, 47, 48, 49\\\},\ + \\\{50(?:, )\{9\}\\\}(?:,\ + \\\{(?:, )\{9\}\\\})\{4\}\\\}" \ + "output large_2d_array from history" +} + +gdb_test_no_output "set max-value-size unlimited" +gdb_test_no_output "set print elements unlimited" +gdb_test_no_output "set print repeats 3" + +with_test_prefix "with unlimited print elements" { + gdb_test "print \$\$" \ + " = \\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,\ + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,\ + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,\ + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\ + 48, 49, 50, \\\}" \ + "print large_1d_array from history" + gdb_test -nonl "output \$\$2" \ + "\\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,\ + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,\ + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,\ + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\ + 48, 49, 50, \\\}" \ + "output large_1d_array from history" + + gdb_test "print \$\$" \ + " = \\\{\\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9\\\},\ + \\\{10, 11, 12, 13, 14, 15, 16, 17, 18, 19\\\},\ + \\\{20, 21, 22, 23, 24, 25, 26, 27, 28, 29\\\},\ + \\\{30, 31, 32, 33, 34, 35, 36, 37, 38, 39\\\},\ + \\\{40, 41, 42, 43, 44, 45, 46, 47, 48, 49\\\},\ + \\\{50, \\\},\ + \\\{ \\\}\ + \\\}" \ + "print large_2d_array from history" + gdb_test -nonl "output \$\$2" \ + "\\\{\\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9\\\},\ + \\\{10, 11, 12, 13, 14, 15, 16, 17, 18, 19\\\},\ + \\\{20, 21, 22, 23, 24, 25, 26, 27, 28, 29\\\},\ + \\\{30, 31, 32, 33, 34, 35, 36, 37, 38, 39\\\},\ + \\\{40, 41, 42, 43, 44, 45, 46, 47, 48, 49\\\},\ + \\\{50, \\\},\ + \\\{ \\\}\ + \\\}" \ + "output large_2d_array from history" + + gdb_test "print \$\[4\]" \ + " = \\\{40, 41, 42, 43, 44, 45, 46, 47, 48, 49\\\}" \ + "print available large_2d_array row from history" + gdb_test -nonl "output \$\$\[4\]" \ + "\\\{40, 41, 42, 43, 44, 45, 46, 47, 48, 49\\\}" \ + "output available large_2d_array row from history" + + gdb_test "print \$\$\[5\]" \ + " = \\\{50, \\\}" \ + "print partially available large_2d_array row from history" + gdb_test -nonl "output \$\$2\[5\]" \ + "\\\{50, \\\}" \ + "output partially available large_2d_array row from history" + + gdb_test "print \$\$2\[6\]" \ + " = " \ + "print unavailable large_2d_array row from history" + gdb_test -nonl "output \$\$3\[6\]" \ + "" \ + "output unavailable large_2d_array row from history" + + gdb_test "print \$\$3\[5\]\[0\]" \ + " = 50" \ + "print available large_2d_array element from history" + gdb_test -nonl "output \$\$4\[5\]\[0\]" \ + "50" \ + "output available large_2d_array element from history" + + gdb_test "print \$\$4\[5\]\[1\]" \ + " = " \ + "print unavailable large_2d_array element from history" + gdb_test -nonl "output \$\$5\[5\]\[1\]" \ + "" \ + "output unavailable large_2d_array element from history" + + gdb_test "print \$\$5\[5\]\[0\] + \$\$5\[5\]\[1\]" \ + "value is not available" \ + "print expression referring unavailable element from history" + gdb_test "output \$\$5\[5\]\[0\] + \$\$5\[5\]\[1\]" \ + "value is not available" \ + "output expression referring unavailable element from history" +} diff --git a/gdb/testsuite/gdb.fortran/limited-length.exp b/gdb/testsuite/gdb.fortran/limited-length.exp new file mode 100644 index 00000000000..b7e43587421 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/limited-length.exp @@ -0,0 +1,220 @@ +# Copyright 2023 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 . + +# This file tests GDB's limited length array printing. + +load_lib "fortran.exp" + +require allow_fortran_tests + +standard_testfile .f90 + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug f90}]} { + return -1 +} + +if {![fortran_runto_main]} { + perror "Could not run to main." + continue +} + +gdb_breakpoint [gdb_get_line_number "Break Here"] +gdb_continue_to_breakpoint "stop-here" ".*Break Here.*" + +with_test_prefix "with standard max-value size" { + gdb_test "print large_4d_array" \ + " = \\(\\(\\(\\(1, 2, 3\\) \\(4, 5, 6\\) \\(7, 8, 9\\)\\)\ + \\(\\(10, 11, 12\\) \\(13, 14, 15\\) \\(16, 17, 18\\)\\)\ + \\(\\(19, 20, 21\\) \\(22, 23, 24\\) \\(25, 26, 27\\)\\)\\)\ + \\(\\(\\(28, 29, 30\\) \\(31, 32, 33\\) \\(34, 35, 36\\)\\)\ + \\(\\(37, 38, 39\\) \\(40, 41, 42\\) \\(43, 44, 45\\)\\)\ + \\(\\(46, 47, 48\\) \\(49, 50, 51\\) \\(52, 53, 54\\)\\)\\)\ + \\(\\(\\(55, 56, 57\\) \\(58, 59, 60\\) \\(61, 62, 63\\)\\)\ + \\(\\(64, 65, 66\\) \\(67, 68, 69\\) \\(70, 71, 72\\)\\)\ + \\(\\(73, 74, 75\\) \\(76, 77, 78\\)\ + \\(79, 80, 81\\)\\)\\)\\)" + gdb_test -nonl "output large_4d_array" \ + "\\(\\(\\(\\(1, 2, 3\\) \\(4, 5, 6\\) \\(7, 8, 9\\)\\)\ + \\(\\(10, 11, 12\\) \\(13, 14, 15\\) \\(16, 17, 18\\)\\)\ + \\(\\(19, 20, 21\\) \\(22, 23, 24\\) \\(25, 26, 27\\)\\)\\)\ + \\(\\(\\(28, 29, 30\\) \\(31, 32, 33\\) \\(34, 35, 36\\)\\)\ + \\(\\(37, 38, 39\\) \\(40, 41, 42\\) \\(43, 44, 45\\)\\)\ + \\(\\(46, 47, 48\\) \\(49, 50, 51\\) \\(52, 53, 54\\)\\)\\)\ + \\(\\(\\(55, 56, 57\\) \\(58, 59, 60\\) \\(61, 62, 63\\)\\)\ + \\(\\(64, 65, 66\\) \\(67, 68, 69\\) \\(70, 71, 72\\)\\)\ + \\(\\(73, 74, 75\\) \\(76, 77, 78\\) \\(79, 80, 81\\)\\)\\)\\)" + gdb_test "print large_1d_array" \ + " = \\(1, 2, 3, 4, 5, 6, 7, 8, 9,\ + 10, 11, 12, 13, 14, 15, 16, 17, 18,\ + 19, 20, 21, 22, 23, 24, 25, 26, 27,\ + 28, 29, 30, 31, 32, 33, 34, 35, 36,\ + 37, 38, 39, 40, 41, 42, 43, 44, 45,\ + 46, 47, 48, 49, 50, 51, 52, 53, 54,\ + 55, 56, 57, 58, 59, 60, 61, 62, 63,\ + 64, 65, 66, 67, 68, 69, 70, 71, 72,\ + 73, 74, 75, 76, 77, 78, 79, 80, 81\\)" + gdb_test -nonl "output large_1d_array" \ + "\\(1, 2, 3, 4, 5, 6, 7, 8, 9,\ + 10, 11, 12, 13, 14, 15, 16, 17, 18,\ + 19, 20, 21, 22, 23, 24, 25, 26, 27,\ + 28, 29, 30, 31, 32, 33, 34, 35, 36,\ + 37, 38, 39, 40, 41, 42, 43, 44, 45,\ + 46, 47, 48, 49, 50, 51, 52, 53, 54,\ + 55, 56, 57, 58, 59, 60, 61, 62, 63,\ + 64, 65, 66, 67, 68, 69, 70, 71, 72,\ + 73, 74, 75, 76, 77, 78, 79, 80, 81\\)" +} + +# Set the max-value-size so we can only print 50 elements. +set elements 50 +set elem_size [get_valueof "/d" "sizeof(large_1d_array(1))" "*unknown*"] +gdb_test_no_output "set max-value-size [expr $elem_size * $elements]" + +with_test_prefix "with reduced max-value size" { + gdb_test "print large_4d_array" \ + "value requires $decimal bytes, which is more than max-value-size" + gdb_test "output large_4d_array" \ + "value requires $decimal bytes, which is more than max-value-size" + gdb_test "print large_1d_array" \ + "value requires $decimal bytes, which is more than max-value-size" + gdb_test "output large_1d_array" \ + "value requires $decimal bytes, which is more than max-value-size" +} + +with_test_prefix "with reduced print -elements flag" { + gdb_test "print -elements 5 -- large_4d_array" \ + " = \\(\\(\\(\\(1, 2, 3\\) \\(4, 5, \\.\\.\\.\\)\ + \\.\\.\\.\\) \\.\\.\\.\\) \\.\\.\\.\\)" + gdb_test "print -elements 5 -- large_1d_array" \ + " = \\(1, 2, 3, 4, 5, \\.\\.\\.\\)" +} + +gdb_test_no_output "set print elements 5" + +with_test_prefix "with reduced print elements" { + gdb_test "print large_4d_array" \ + " = \\(\\(\\(\\(1, 2, 3\\) \\(4, 5, \\.\\.\\.\\)\ + \\.\\.\\.\\) \\.\\.\\.\\) \\.\\.\\.\\)" + gdb_test -nonl "output large_4d_array" \ + "\\(\\(\\(\\(1, 2, 3\\) \\(4, 5, \\.\\.\\.\\)\ + \\.\\.\\.\\) \\.\\.\\.\\) \\.\\.\\.\\)" + + gdb_test "print \$" \ + " = \\(\\(\\(\\(1, 2, 3\\) \\(4, 5, \\.\\.\\.\\)\ + \\.\\.\\.\\) \\.\\.\\.\\) \\.\\.\\.\\)" \ + "print large_4d_array from history" + gdb_test -nonl "output \$\$" \ + "\\(\\(\\(\\(1, 2, 3\\) \\(4, 5, \\.\\.\\.\\)\ + \\.\\.\\.\\) \\.\\.\\.\\) \\.\\.\\.\\)" \ + "output large_4d_array from history" + + gdb_test "print large_1d_array" \ + " = \\(1, 2, 3, 4, 5, \\.\\.\\.\\)" + gdb_test -nonl "output large_1d_array" \ + "\\(1, 2, 3, 4, 5, \\.\\.\\.\\)" + + gdb_test "print \$" \ + " = \\(1, 2, 3, 4, 5, \\.\\.\\.\\)" \ + "print large_1d_array from history" + gdb_test -nonl "output \$\$" \ + "\\(1, 2, 3, 4, 5, \\.\\.\\.\\)" \ + "output large_1d_array from history" +} + +gdb_test_no_output "set print elements $elements" + +with_test_prefix "with print elements matching max-value size" { + gdb_test "print \$\$2" \ + " = \\(\\(\\(\\(1, 2, 3\\) \\(4, 5, 6\\) \\(7, 8, 9\\)\\)\ + \\(\\(10, 11, 12\\) \\(13, 14, 15\\) \\(16, 17, 18\\)\\)\ + \\(\\(19, 20, 21\\) \\(22, 23, 24\\) \\(25, 26, 27\\)\\)\\)\ + \\(\\(\\(28, 29, 30\\) \\(31, 32, 33\\) \\(34, 35, 36\\)\\)\ + \\(\\(37, 38, 39\\) \\(40, 41, 42\\) \\(43, 44, 45\\)\\)\ + \\(\\(46, 47, 48\\) \\(49, 50, \\.\\.\\.\\) \\.\\.\\.\\)\\)\ + \\.\\.\\.\\)" \ + "print large_4d_array from history" + gdb_test -nonl "output \$\$3" \ + "\\(\\(\\(\\(1, 2, 3\\) \\(4, 5, 6\\) \\(7, 8, 9\\)\\)\ + \\(\\(10, 11, 12\\) \\(13, 14, 15\\) \\(16, 17, 18\\)\\)\ + \\(\\(19, 20, 21\\) \\(22, 23, 24\\) \\(25, 26, 27\\)\\)\\)\ + \\(\\(\\(28, 29, 30\\) \\(31, 32, 33\\) \\(34, 35, 36\\)\\)\ + \\(\\(37, 38, 39\\) \\(40, 41, 42\\) \\(43, 44, 45\\)\\)\ + \\(\\(46, 47, 48\\) \\(49, 50, \\.\\.\\.\\) \\.\\.\\.\\)\\)\ + \\.\\.\\.\\)" \ + "output large_4d_array from history" + + gdb_test "print \$\$2" \ + " = \\(1, 2, 3, 4, 5, 6, 7, 8, 9,\ + 10, 11, 12, 13, 14, 15, 16, 17, 18,\ + 19, 20, 21, 22, 23, 24, 25, 26, 27,\ + 28, 29, 30, 31, 32, 33, 34, 35, 36,\ + 37, 38, 39, 40, 41, 42, 43, 44, 45,\ + 46, 47, 48, 49, 50, \\.\\.\\.\\)" \ + "print large_1d_array from history" + gdb_test -nonl "output \$\$2" \ + "\\(1, 2, 3, 4, 5, 6, 7, 8, 9,\ + 10, 11, 12, 13, 14, 15, 16, 17, 18,\ + 19, 20, 21, 22, 23, 24, 25, 26, 27,\ + 28, 29, 30, 31, 32, 33, 34, 35, 36,\ + 37, 38, 39, 40, 41, 42, 43, 44, 45,\ + 46, 47, 48, 49, 50, \\.\\.\\.\\)" \ + "output large_1d_array from history" +} + +gdb_test_no_output "set max-value-size unlimited" +gdb_test_no_output "set print elements unlimited" +gdb_test_no_output "set print repeats 2" + +with_test_prefix "with unlimited print elements" { + gdb_test "print \$\$" \ + " = \\(\\(\\(\\(1, 2, 3\\) \\(4, 5, 6\\) \\(7, 8, 9\\)\\)\ + \\(\\(10, 11, 12\\) \\(13, 14, 15\\) \\(16, 17, 18\\)\\)\ + \\(\\(19, 20, 21\\) \\(22, 23, 24\\) \\(25, 26, 27\\)\\)\\)\ + \\(\\(\\(28, 29, 30\\) \\(31, 32, 33\\) \\(34, 35, 36\\)\\)\ + \\(\\(37, 38, 39\\) \\(40, 41, 42\\) \\(43, 44, 45\\)\\)\ + \\(\\(46, 47, 48\\) \\(49, 50, \\)\ + \\(, \\)\\)\\)\ + \\(\\(\\(, \\)\ + \\) \\)\\)" \ + "print large_4d_array from history" + gdb_test -nonl "output \$\$2" \ + "\\(\\(\\(\\(1, 2, 3\\) \\(4, 5, 6\\) \\(7, 8, 9\\)\\)\ + \\(\\(10, 11, 12\\) \\(13, 14, 15\\) \\(16, 17, 18\\)\\)\ + \\(\\(19, 20, 21\\) \\(22, 23, 24\\) \\(25, 26, 27\\)\\)\\)\ + \\(\\(\\(28, 29, 30\\) \\(31, 32, 33\\) \\(34, 35, 36\\)\\)\ + \\(\\(37, 38, 39\\) \\(40, 41, 42\\) \\(43, 44, 45\\)\\)\ + \\(\\(46, 47, 48\\) \\(49, 50, \\)\ + \\(, \\)\\)\\)\ + \\(\\(\\(, \\)\ + \\) \\)\\)" \ + "output large_4d_array from history" + + gdb_test "print \$\$" \ + " = \\(1, 2, 3, 4, 5, 6, 7, 8, 9,\ + 10, 11, 12, 13, 14, 15, 16, 17, 18,\ + 19, 20, 21, 22, 23, 24, 25, 26, 27,\ + 28, 29, 30, 31, 32, 33, 34, 35, 36,\ + 37, 38, 39, 40, 41, 42, 43, 44, 45,\ + 46, 47, 48, 49, 50, , \\)" \ + "print large_1d_array from history" + gdb_test -nonl "output \$\$2" \ + "\\(1, 2, 3, 4, 5, 6, 7, 8, 9,\ + 10, 11, 12, 13, 14, 15, 16, 17, 18,\ + 19, 20, 21, 22, 23, 24, 25, 26, 27,\ + 28, 29, 30, 31, 32, 33, 34, 35, 36,\ + 37, 38, 39, 40, 41, 42, 43, 44, 45,\ + 46, 47, 48, 49, 50, , \\)" \ + "output large_1d_array from history" +} diff --git a/gdb/testsuite/gdb.fortran/limited-length.f90 b/gdb/testsuite/gdb.fortran/limited-length.f90 new file mode 100644 index 00000000000..4b8568e1925 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/limited-length.f90 @@ -0,0 +1,39 @@ +! This testcase is part of GDB, the GNU debugger. +! +! Copyright 2023 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 . + +program main + integer(kind=8), dimension (3, 3, 3, 3) :: large_4d_array = reshape ((/ & + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, & + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, & + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, & + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, & + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, & + 78, 79, 80, 81/), (/3, 3, 3, 3/)) + + integer(kind=8), dimension (81) :: large_1d_array = reshape ((/ & + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, & + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, & + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, & + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, & + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, & + 78, 79, 80, 81/), (/81/)) + + print *, "" + print *, "" ! Break Here + print *, large_4d_array + print *, large_1d_array +end program main diff --git a/gdb/valprint.c b/gdb/valprint.c index 04f83f5194a..fe376c25e98 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -2018,13 +2018,21 @@ value_print_array_elements (struct value *val, struct ui_file *stream, UINT_MAX (unlimited). */ if (options->repeat_count_threshold < UINT_MAX) { + bool unavailable = value_entirely_unavailable (element); + bool available = value_entirely_available (element); + while (rep1 < len) { struct value *rep_elt = value_from_component_bitsize (val, elttype, rep1 * bit_stride, bit_stride); - if (!value_contents_eq (element, rep_elt)) + bool repeated = ((available + && value_entirely_available (rep_elt) + && value_contents_eq (element, rep_elt)) + || (unavailable + && value_entirely_unavailable (rep_elt))); + if (!repeated) break; ++reps; ++rep1; diff --git a/gdb/value.c b/gdb/value.c index fbdb07959c6..4be408e6870 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -373,6 +373,14 @@ struct value treated pretty much the same, except not-saved registers have a different string representation and related error strings. */ std::vector optimized_out; + + /* This is only non-zero for values of TYPE_CODE_ARRAY and if the size of + the array in inferior memory is greater than max_value_size. If these + conditions are met then, when the value is loaded from the inferior + GDB will only load a portion of the array into memory, and + limited_length will be set to indicate the length in octets that were + loaded from the inferior. */ + ULONGEST limited_length = 0; }; /* See value.h. */ @@ -1053,6 +1061,94 @@ check_type_length_before_alloc (const struct type *type) } } +/* When this has a value, it is used to limit the number of array elements + of an array that are loaded into memory when an array value is made + non-lazy. */ +static gdb::optional array_length_limiting_element_count; + +/* See value.h. */ +scoped_array_length_limiting::scoped_array_length_limiting (int elements) +{ + m_old_value = array_length_limiting_element_count; + array_length_limiting_element_count.emplace (elements); +} + +/* See value.h. */ +scoped_array_length_limiting::~scoped_array_length_limiting () +{ + array_length_limiting_element_count = m_old_value; +} + +/* Find the inner element type for ARRAY_TYPE. */ + +static struct type * +find_array_element_type (struct type *array_type) +{ + array_type = check_typedef (array_type); + gdb_assert (array_type->code () == TYPE_CODE_ARRAY); + + if (current_language->la_language == language_fortran) + while (array_type->code () == TYPE_CODE_ARRAY) + { + array_type = array_type->target_type (); + array_type = check_typedef (array_type); + } + else + { + array_type = array_type->target_type (); + array_type = check_typedef (array_type); + } + + return array_type; +} + +/* Return the limited length of ARRAY_TYPE, which must be of + TYPE_CODE_ARRAY. This function can only be called when the global + ARRAY_LENGTH_LIMITING_ELEMENT_COUNT has a value. + + The limited length of an array is the smallest of either (1) the total + size of the array type, or (2) the array target type multiplies by the + array_length_limiting_element_count. */ + +static ULONGEST +calculate_limited_array_length (struct type *array_type) +{ + gdb_assert (array_length_limiting_element_count.has_value ()); + + array_type = check_typedef (array_type); + gdb_assert (array_type->code () == TYPE_CODE_ARRAY); + + struct type *elm_type = find_array_element_type (array_type); + ULONGEST len = (elm_type->length () + * (*array_length_limiting_element_count)); + len = std::min (len, array_type->length ()); + + return len; +} + +/* Try to limit ourselves to only fetching the limited number of + elements. However, if this limited number of elements still + puts us over max_value_size, then we still refuse it and + return failure here, which will ultimately throw an error. */ + +static bool +set_limited_array_length (struct value *val) +{ + ULONGEST limit = val->limited_length; + ULONGEST len = value_type (val)->length (); + + if (array_length_limiting_element_count.has_value ()) + len = calculate_limited_array_length (value_type (val)); + + if (limit != 0 && len > limit) + len = limit; + if (len > max_value_size) + return false; + + val->limited_length = max_value_size; + return true; +} + /* Allocate the contents of VAL if it has not been allocated yet. If CHECK_SIZE is true, then apply the usual max-value-size checks. */ @@ -1061,10 +1157,26 @@ allocate_value_contents (struct value *val, bool check_size) { if (!val->contents) { + struct type *enclosing_type = value_enclosing_type (val); + ULONGEST len = enclosing_type->length (); + if (check_size) - check_type_length_before_alloc (val->enclosing_type); - val->contents.reset - ((gdb_byte *) xzalloc (val->enclosing_type->length ())); + { + /* If we are allocating the contents of an array, which + is greater in size than max_value_size, and there is + an element limit in effect, then we can possibly try + to load only a sub-set of the array contents into + GDB's memory. */ + if (value_type (val) == enclosing_type + && value_type (val)->code () == TYPE_CODE_ARRAY + && len > max_value_size + && set_limited_array_length (val)) + len = val->limited_length; + else + check_type_length_before_alloc (enclosing_type); + } + + val->contents.reset ((gdb_byte *) xzalloc (len)); } } @@ -1791,10 +1903,7 @@ value_copy (const value *arg) struct type *encl_type = value_enclosing_type (arg); struct value *val; - if (value_lazy (arg)) - val = allocate_value_lazy (encl_type); - else - val = allocate_value (encl_type, false); + val = allocate_value_lazy (encl_type); val->type = arg->type; VALUE_LVAL (val) = arg->lval; val->location = arg->location; @@ -1811,17 +1920,28 @@ value_copy (const value *arg) val->initialized = arg->initialized; val->unavailable = arg->unavailable; val->optimized_out = arg->optimized_out; + val->parent = arg->parent; + val->limited_length = arg->limited_length; - if (!value_lazy (val) && !value_entirely_optimized_out (val)) + if (!value_lazy (val) + && !(value_entirely_optimized_out (val) + || value_entirely_unavailable (val))) { + ULONGEST length = val->limited_length; + if (length == 0) + length = value_enclosing_type (val)->length (); + gdb_assert (arg->contents != nullptr); - ULONGEST length = value_enclosing_type (arg)->length (); const auto &arg_view = gdb::make_array_view (arg->contents.get (), length); - copy (arg_view, value_contents_all_raw (val)); + + allocate_value_contents (val, false); + gdb::array_view val_contents + = value_contents_all_raw (val).slice (0, length); + + copy (arg_view, val_contents); } - val->parent = arg->parent; if (VALUE_LVAL (val) == lval_computed) { const struct lval_funcs *funcs = val->location.computed.funcs; @@ -1955,12 +2075,34 @@ set_value_component_location (struct value *component, int record_latest_value (struct value *val) { + struct type *enclosing_type = value_enclosing_type (val); + struct type *type = value_type (val); + /* We don't want this value to have anything to do with the inferior anymore. In particular, "set $1 = 50" should not affect the variable from which the value was taken, and fast watchpoints should be able to assume that a value on the value history never changes. */ if (value_lazy (val)) - value_fetch_lazy (val); + { + /* We know that this is a _huge_ array, any attempt to fetch this + is going to cause GDB to throw an error. However, to allow + the array to still be displayed we fetch its contents up to + `max_value_size' and mark anything beyond "unavailable" in + the history. */ + if (type->code () == TYPE_CODE_ARRAY + && type->length () > max_value_size + && array_length_limiting_element_count.has_value () + && enclosing_type == type + && calculate_limited_array_length (type) <= max_value_size) + val->limited_length = max_value_size; + + value_fetch_lazy (val); + } + + ULONGEST limit = val->limited_length; + if (limit != 0) + mark_value_bytes_unavailable (val, limit, + enclosing_type->length () - limit); /* Mark the value as recorded in the history for the availability check. */ val->in_history = true; @@ -4060,10 +4202,23 @@ value_fetch_lazy_memory (struct value *val) CORE_ADDR addr = value_address (val); struct type *type = check_typedef (value_enclosing_type (val)); - if (type->length ()) - read_value_memory (val, 0, value_stack (val), - addr, value_contents_all_raw (val).data (), - type_length_units (type)); + /* Figure out how much we should copy from memory. Usually, this is just + the size of the type, but, for arrays, we might only be loading a + small part of the array (this is only done for very large arrays). */ + int len = 0; + if (val->limited_length > 0) + { + gdb_assert (value_type (val)->code () == TYPE_CODE_ARRAY); + len = val->limited_length; + } + else if (type->length () > 0) + len = type_length_units (type); + + gdb_assert (len >= 0); + + if (len > 0) + read_value_memory (val, 0, value_stack (val), addr, + value_contents_all_raw (val).data (), len); } /* Helper for value_fetch_lazy when the value is in a register. */ diff --git a/gdb/value.h b/gdb/value.h index 80f92597d07..c002ad09b45 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -1228,4 +1228,21 @@ extern void finalize_values (); of floating-point, fixed-point, or integer type. */ extern gdb_mpq value_to_gdb_mpq (struct value *value); +/* While an instance of this class is live, and array values that are + created, that are larger than max_value_size, will be restricted in size + to a particular number of elements. */ + +struct scoped_array_length_limiting +{ + /* Limit any large array values to only contain ELEMENTS elements. */ + scoped_array_length_limiting (int elements); + + /* Restore the previous array value limit. */ + ~scoped_array_length_limiting (); + +private: + /* Used to hold the previous array value element limit. */ + gdb::optional m_old_value; +}; + #endif /* !defined (VALUE_H) */ -- 2.30.2