[v2,5/5] GDB: Introduce limited array lengths while printing values

Message ID alpine.DEB.2.20.2301112357100.7841@tpp.orcam.me.uk
State Superseded
Headers
Series gdb: introduce limited array lengths while printing values |

Commit Message

Maciej W. Rozycki Jan. 12, 2023, 9:02 a.m. UTC
  From: Andrew Burgess <andrew.burgess@embecosm.com>

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>
---
Changes from v1:

- Load `max-value-size' worth data into the value history for limited 
  length accesses and mark the area beyond unavailable.

- Handle the `output' command.

- Expand test coverage.
---
 gdb/NEWS                                     |    6 
 gdb/doc/gdb.texinfo                          |    9 
 gdb/f-valprint.c                             |   32 ++-
 gdb/printcmd.c                               |   16 +
 gdb/testsuite/gdb.ada/limited-length.exp     |  266 +++++++++++++++++++++++++++
 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 |  222 ++++++++++++++++++++++
 gdb/testsuite/gdb.fortran/limited-length.f90 |   39 +++
 gdb/valprint.c                               |   10 -
 gdb/value.c                                  |  201 ++++++++++++++++++--
 gdb/value.h                                  |   17 +
 15 files changed, 1165 insertions(+), 26 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

gdb-aburgess-limited-length-array.diff
  

Comments

Eli Zaretskii Jan. 12, 2023, 10:04 a.m. UTC | #1
> Date: Thu, 12 Jan 2023 09:02:23 +0000 (GMT)
> From: "Maciej W. Rozycki" <macro@embecosm.com>
> cc: Andrew Burgess <aburgess@redhat.com>, Tom Tromey <tom@tromey.com>, 
>  Richard Bunt <Richard.Bunt@arm.com>
> 
> --- src.orig/gdb/NEWS
> +++ src/gdb/NEWS
> @@ -354,6 +354,12 @@ GDB now supports floating-point on Loong
>    Disabling this can cause a performance penalty when there are a lot of
>    symbols to load, but is useful for debugging purposes.
>  
> +* 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 number 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.

The wording here needs to be changed, because max-value-size is not
about the number of elements, it's about the amount of memory needed
for those elements.  So this part:

                                                       but 'print elements'
     is set such that the number of elements to print is less than or equal
     to 'max-value-size'

should be reworded.

> --- src.orig/gdb/doc/gdb.texinfo
> +++ src/gdb/doc/gdb.texinfo
> @@ -11756,6 +11756,14 @@ When @value{GDBN} starts, this limit is
>  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.
>  
> @@ -14171,6 +14179,7 @@ may indicate a value that is incorrectly
>  @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

This part is OK.

Thanks.
  
Maciej W. Rozycki Jan. 12, 2023, 10:58 a.m. UTC | #2
On Thu, 12 Jan 2023, Eli Zaretskii wrote:

> > --- src.orig/gdb/NEWS
> > +++ src/gdb/NEWS
> > @@ -354,6 +354,12 @@ GDB now supports floating-point on Loong
> >    Disabling this can cause a performance penalty when there are a lot of
> >    symbols to load, but is useful for debugging purposes.
> >  
> > +* 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 number 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.
> 
> The wording here needs to be changed, because max-value-size is not
> about the number of elements, it's about the amount of memory needed
> for those elements.  So this part:
> 
>                                                        but 'print elements'
>      is set such that the number of elements to print is less than or equal
>      to 'max-value-size'
> 
> should be reworded.

 Thank you for your review, and thanks for catching this subtlety.  I'll 
replace "number" with "size" above just as in the manual, whether in the 
final version committed or in the next iteration (as appropriate).

  Maciej
  

Patch

Index: src/gdb/NEWS
===================================================================
--- src.orig/gdb/NEWS
+++ src/gdb/NEWS
@@ -354,6 +354,12 @@  GDB now supports floating-point on Loong
   Disabling this can cause a performance penalty when there are a lot of
   symbols to load, but is useful for debugging purposes.
 
+* 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 number 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
 
 maint set backtrace-on-fatal-signal on|off
Index: src/gdb/doc/gdb.texinfo
===================================================================
--- src.orig/gdb/doc/gdb.texinfo
+++ src/gdb/doc/gdb.texinfo
@@ -11756,6 +11756,14 @@  When @value{GDBN} starts, this limit is
 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.
 
@@ -14171,6 +14179,7 @@  may indicate a value that is incorrectly
 @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: src/gdb/f-valprint.c
===================================================================
--- src.orig/gdb/f-valprint.c
+++ src/gdb/f-valprint.c
@@ -261,10 +261,20 @@  class fortran_array_printer_impl : publi
     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 @@  class fortran_array_printer_impl : publi
      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 @@  class fortran_array_printer_impl : publi
 	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: src/gdb/printcmd.c
===================================================================
--- src.orig/gdb/printcmd.c
+++ src/gdb/printcmd.c
@@ -1242,6 +1242,11 @@  print_command_parse_format (const char *
 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 *
 
   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 fro
 
   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 ();
Index: src/gdb/testsuite/gdb.ada/limited-length.exp
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.ada/limited-length.exp
@@ -0,0 +1,266 @@ 
+# 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"
+
+if {[skip_ada_tests]} {
+    return -1
+}
+
+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"
+}
Index: src/gdb/testsuite/gdb.ada/limited-length/foo.adb
===================================================================
--- /dev/null
+++ src/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 <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;
+
Index: src/gdb/testsuite/gdb.ada/limited-length/pck.adb
===================================================================
--- /dev/null
+++ src/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 <http://www.gnu.org/licenses/>.
+
+package body Pck is
+
+   procedure Do_Nothing (A : System.Address) is
+   begin
+      null;
+   end Do_Nothing;
+
+end Pck;
Index: src/gdb/testsuite/gdb.ada/limited-length/pck.ads
===================================================================
--- /dev/null
+++ src/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 <http://www.gnu.org/licenses/>.
+
+with System;
+package Pck is
+   procedure Do_Nothing (A : System.Address);
+end Pck;
Index: src/gdb/testsuite/gdb.base/limited-length.c
===================================================================
--- /dev/null
+++ src/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 <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;
+}
Index: src/gdb/testsuite/gdb.base/limited-length.exp
===================================================================
--- /dev/null
+++ src/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 <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"
+}
Index: src/gdb/testsuite/gdb.fortran/limited-length.exp
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.fortran/limited-length.exp
@@ -0,0 +1,222 @@ 
+# 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"
+
+if {[skip_fortran_tests]} {
+    continue
+}
+
+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"
+}
Index: src/gdb/testsuite/gdb.fortran/limited-length.f90
===================================================================
--- /dev/null
+++ src/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 <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: src/gdb/valprint.c
===================================================================
--- src.orig/gdb/valprint.c
+++ src/gdb/valprint.c
@@ -2018,13 +2018,21 @@  value_print_array_elements (struct value
 	 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: src/gdb/value.c
===================================================================
--- src.orig/gdb/value.c
+++ src/gdb/value.c
@@ -369,6 +369,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.  */
@@ -1046,6 +1054,93 @@  check_type_length_before_alloc (const st
     }
 }
 
+/* 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 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.  */
 
@@ -1054,10 +1149,26 @@  allocate_value_contents (struct value *v
 {
   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));
     }
 }
 
@@ -1789,10 +1900,7 @@  value_copy (const value *arg, bool check
   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, check_size);
+  val = allocate_value_lazy (encl_type);
   val->type = arg->type;
   VALUE_LVAL (val) = arg->lval;
   val->location = arg->location;
@@ -1808,17 +1916,41 @@  value_copy (const value *arg, bool check
   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)))
     {
       gdb_assert (arg->contents != nullptr);
-      ULONGEST length = value_enclosing_type (arg)->length ();
+      allocate_value_contents (val, check_size);
+
+      /* We need to handle the case where the new VAL has its content
+	 buffer limited, but to a different length, than the original
+	 ARG value.  This all gets rather messy.  */
+      ULONGEST src_len, dst_len;
+      if (val->limited_length > 0)
+	dst_len = val->limited_length;
+      else
+	dst_len = value_enclosing_type (val)->length ();
+
+      if (arg->limited_length > 0)
+	src_len = val->limited_length;
+      else
+	src_len = value_enclosing_type (arg)->length ();
+
+      ULONGEST len = std::min (src_len, dst_len);
+      gdb::array_view<gdb_byte> val_contents
+	= value_contents_all_raw (val).slice (0, len);
       const auto &arg_view
-	= gdb::make_array_view (arg->contents.get (), length);
-      copy (arg_view, value_contents_all_raw (val));
+	= gdb::make_array_view (arg->contents.get (), len);
+      copy (arg_view, val_contents);
+
+      if (dst_len < src_len)
+	mark_value_bytes_unavailable (val, dst_len, (src_len - dst_len));
     }
 
-  val->parent = arg->parent;
   if (VALUE_LVAL (val) == lval_computed)
     {
       const struct lval_funcs *funcs = val->location.computed.funcs;
@@ -1961,20 +2093,40 @@  set_value_component_location (struct val
 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);
+    }
 
   /* Don't pretend we have anything available there in the history beyond
      the boundaries of the value recorded.  It's not like inferior memory
      where there is actual stuff underneath.  */
-  ULONGEST length = value_enclosing_type (val)->length ();
+  ULONGEST length = enclosing_type->length ();
   mark_value_bits_unavailable (val, LONGEST_MIN, 0 ^ LONGEST_MIN);
   mark_value_bits_unavailable (val, length * TARGET_CHAR_BIT,
 			       LONGEST_MAX - length * TARGET_CHAR_BIT);
+  if (val->limited_length != 0)
+    mark_value_bytes_unavailable (val, val->limited_length,
+				  length - val->limited_length);
 
   /* We preserve VALUE_LVAL so that the user can find out where it was fetched
      from.  This is a bit dubious, because then *&$1 does not just return $1
@@ -4071,10 +4223,23 @@  value_fetch_lazy_memory (struct value *v
   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: src/gdb/value.h
===================================================================
--- src.orig/gdb/value.h
+++ src/gdb/value.h
@@ -1235,4 +1235,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) */