GDB: Introduce limited array lengths while printing values
authorAndrew Burgess <andrew.burgess@embecosm.com>
Fri, 10 Feb 2023 23:49:19 +0000 (23:49 +0000)
committerMaciej W. Rozycki <macro@embecosm.com>
Fri, 10 Feb 2023 23:49:19 +0000 (23:49 +0000)
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, <unavailable> <repeats 75 times>}
  (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 <macro@embecosm.com>
15 files changed:
gdb/NEWS
gdb/doc/gdb.texinfo
gdb/f-valprint.c
gdb/printcmd.c
gdb/testsuite/gdb.ada/limited-length.exp [new file with mode: 0644]
gdb/testsuite/gdb.ada/limited-length/foo.adb [new file with mode: 0644]
gdb/testsuite/gdb.ada/limited-length/pck.adb [new file with mode: 0644]
gdb/testsuite/gdb.ada/limited-length/pck.ads [new file with mode: 0644]
gdb/testsuite/gdb.base/limited-length.c [new file with mode: 0644]
gdb/testsuite/gdb.base/limited-length.exp [new file with mode: 0644]
gdb/testsuite/gdb.fortran/limited-length.exp [new file with mode: 0644]
gdb/testsuite/gdb.fortran/limited-length.f90 [new file with mode: 0644]
gdb/valprint.c
gdb/value.c
gdb/value.h

index b85923cf80d4cdd54cedf58b0b0f61488b7c24b1..1328f4faa80b40682c10c2ff202b2a253e2d06ad 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
   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 ]
index 7b128053b5ab5cb236fb17d16f4343738c5affe3..0beb45857c35416fa32c1a441e810b50ab274a8b 100644 (file)
@@ -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
index 55dbcc8309f9c93afc254efc73e2c2ee7535fe16..b08613f91534f53d56b411f6af4f5c72d1099a73 100644 (file)
@@ -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.  */
index 7f3551327a860631e05eae4c0c272ca1e43c903e..9bda60d6f806ef79c61cdbcfbe1463e4d119e297 100644 (file)
@@ -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 (file)
index 0000000..1e3afe7
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+
+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(?:, <unavailable>)\{3\}\\)(?:,\
+                 \\(<unavailable>(?:, <unavailable>)\{3\}\\))\{3\}\\),\
+              \\(\\(<unavailable>(?:, <unavailable>)\{3\}\\)(?:,\
+                 \\(<unavailable>(?:, <unavailable>)\{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(?:, <unavailable>)\{3\}\\)(?:,\
+              \\(<unavailable>(?:, <unavailable>)\{3\}\\))\{3\}\\),\
+           \\(\\(<unavailable>(?:, <unavailable>)\{3\}\\)(?:,\
+              \\(<unavailable>(?:, <unavailable>)\{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,\
+              <unavailable> <repeats 31 times>\\)" \
+       "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,\
+           <unavailable> <repeats 31 times>\\)" \
+       "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, <unavailable> <repeats 3 times>\\),\
+                 \\(<unavailable> <repeats 4 times>\\) <repeats 3 times>\\),\
+              \\(\\(<unavailable> <repeats 4 times>\\)\
+                 <repeats 4 times>\\)\\)" \
+       "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, <unavailable> <repeats 3 times>\\),\
+              \\(<unavailable> <repeats 4 times>\\) <repeats 3 times>\\),\
+           \\(\\(<unavailable> <repeats 4 times>\\) <repeats 4 times>\\)\\)" \
+       "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, <unavailable> <repeats 3 times>\\),\
+              \\(<unavailable> <repeats 4 times>\\) <repeats 3 times>\\)" \
+       "print partially available Large_3d_Array row from history"
+    gdb_test -nonl "output \$\$2\[3\]" \
+       "\\(\\(33, <unavailable> <repeats 3 times>\\),\
+           \\(<unavailable> <repeats 4 times>\\) <repeats 3 times>\\)" \
+       "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\]" \
+       " = <unavailable>" \
+       "print unavailable Large_3d_Array row from history"
+    gdb_test -nonl "output \$\$4\[4\]" \
+       "<unavailable>" \
+       "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\]" \
+       " = <unavailable>" \
+       "print unavailable Large_3d_Array element from history"
+    gdb_test -nonl "output \$\$6\[3\]\[1\]\[2\]" \
+       "<unavailable>" \
+       "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 (file)
index 0000000..b950544
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+
+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 (file)
index 0000000..5344302
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+
+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 (file)
index 0000000..2ef2f6c
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+
+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 (file)
index 0000000..177400d
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.  */
+
+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 (file)
index 0000000..2918b1a
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+
+# 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(?:, <unavailable>)\{9\}\\\}(?:,\
+               \\\{<unavailable>(?:, <unavailable>)\{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(?:, <unavailable>)\{9\}\\\}(?:,\
+            \\\{<unavailable>(?:, <unavailable>)\{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, <unavailable> <repeats 49 times>\\\}" \
+       "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, <unavailable> <repeats 49 times>\\\}" \
+       "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, <unavailable> <repeats 9 times>\\\},\
+               \\\{<unavailable> <repeats 10 times>\\\}\
+               <repeats 4 times>\\\}" \
+       "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, <unavailable> <repeats 9 times>\\\},\
+            \\\{<unavailable> <repeats 10 times>\\\}\
+            <repeats 4 times>\\\}" \
+       "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, <unavailable> <repeats 9 times>\\\}" \
+       "print partially available large_2d_array row from history"
+    gdb_test -nonl "output \$\$2\[5\]" \
+       "\\\{50, <unavailable> <repeats 9 times>\\\}" \
+       "output partially available large_2d_array row from history"
+
+    gdb_test "print \$\$2\[6\]" \
+       " = <unavailable>" \
+       "print unavailable large_2d_array row from history"
+    gdb_test -nonl "output \$\$3\[6\]" \
+       "<unavailable>" \
+       "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\]" \
+       " = <unavailable>" \
+       "print unavailable large_2d_array element from history"
+    gdb_test -nonl "output \$\$5\[5\]\[1\]" \
+       "<unavailable>" \
+       "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 (file)
index 0000000..b7e4358
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+
+# 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, <unavailable>\\)\
+                    \\(<unavailable>, <repeats 3 times>\\)\\)\\)\
+              \\(\\(\\(<unavailable>, <repeats 3 times>\\)\
+                    <repeats 3 times>\\) <repeats 3 times>\\)\\)" \
+       "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, <unavailable>\\)\
+                 \\(<unavailable>, <repeats 3 times>\\)\\)\\)\
+           \\(\\(\\(<unavailable>, <repeats 3 times>\\)\
+                 <repeats 3 times>\\) <repeats 3 times>\\)\\)" \
+       "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, <unavailable>, <repeats 31 times>\\)" \
+       "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, <unavailable>, <repeats 31 times>\\)" \
+       "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 (file)
index 0000000..4b8568e
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+
+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
index 04f83f5194adfc6e19fda05fe132dff938c2cba1..fe376c25e9820393c8da217eae63b4885e33b3fd 100644 (file)
@@ -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;
index fbdb07959c6e8f68e07d95665fa79ec409703a73..4be408e687027b5ab3f2962b9d842b348f8fef0e 100644 (file)
@@ -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<range> 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<int> 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<gdb_byte> 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.  */
index 80f92597d077ce7b5a8f33fbdaf4032fbc615faa..c002ad09b45ebd8f07f971991f1d5696c6cfc735 100644 (file)
@@ -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<int> m_old_value;
+};
+
 #endif /* !defined (VALUE_H) */