public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v4 0/6] gdb: introduce limited array lengths while printing values
@ 2023-02-10 14:18 Maciej W. Rozycki
  2023-02-10 14:19 ` [PATCH v4 1/6] GDB: Switch to using C++ standard integer type limits Maciej W. Rozycki
                   ` (6 more replies)
  0 siblings, 7 replies; 14+ messages in thread
From: Maciej W. Rozycki @ 2023-02-10 14:18 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Tom Tromey, Richard Bunt

Hi,

 This is v4 of the patch series, addressing the suggestion made by Tom 
Tromey for v3 as to avoiding the use of explicit ranges for out-of-bounds 
accesses to value history entries.  There's now an extra clean-up WRT the 
use of standard C++ <climits> macros too.  The remaining changes have been 
adjusted as requested and I will commit them where approved along with the 
outstanding ones.

 See individual change descriptions for details.

 I have regression-tested it natively with a `x86_64-linux-gnu' system.  
OK to apply?

  Maciej

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v4 1/6] GDB: Switch to using C++ standard integer type limits
  2023-02-10 14:18 [PATCH v4 0/6] gdb: introduce limited array lengths while printing values Maciej W. Rozycki
@ 2023-02-10 14:19 ` Maciej W. Rozycki
  2023-02-10 21:13   ` Tom Tromey
  2023-02-10 14:19 ` [PATCH v4 2/6] GDB: Ignore `max-value-size' setting with value history accesses Maciej W. Rozycki
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 14+ messages in thread
From: Maciej W. Rozycki @ 2023-02-10 14:19 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Tom Tromey, Richard Bunt

Use <climits> instead of <limits.h> and ditch local fallback definitions 
for minimum and maximum value macros provided by C++11.  Add LONGEST_MAX 
and LONGEST_MIN definitions.
---
New change in v4.
---
 gdb/defs.h                |   33 +--------------------------------
 gdb/gnu-nat.c             |    1 -
 gdbsupport/common-types.h |    8 +++++++-
 3 files changed, 8 insertions(+), 34 deletions(-)

gdb-climits.diff
Index: src/gdb/defs.h
===================================================================
--- src.orig/gdb/defs.h
+++ src/gdb/defs.h
@@ -37,7 +37,7 @@
 #include "bfd.h"
 
 #include <sys/types.h>
-#include <limits.h>
+#include <climits>
 
 /* The libdecnumber library, on which GDB depends, includes a header file
    called gstdint.h instead of relying directly on stdint.h.  GDB, on the
@@ -446,37 +446,6 @@ enum val_prettyformat
 # include "fopen-bin.h"
 #endif
 
-/* Defaults for system-wide constants (if not defined by xm.h, we fake it).
-   FIXME: Assumes 2's complement arithmetic.  */
-
-#if !defined (UINT_MAX)
-#define	UINT_MAX ((unsigned int)(~0))	    /* 0xFFFFFFFF for 32-bits */
-#endif
-
-#if !defined (INT_MAX)
-#define	INT_MAX ((int)(UINT_MAX >> 1))	    /* 0x7FFFFFFF for 32-bits */
-#endif
-
-#if !defined (INT_MIN)
-#define INT_MIN ((int)((int) ~0 ^ INT_MAX)) /* 0x80000000 for 32-bits */
-#endif
-
-#if !defined (ULONG_MAX)
-#define	ULONG_MAX ((unsigned long)(~0L))    /* 0xFFFFFFFF for 32-bits */
-#endif
-
-#if !defined (LONG_MAX)
-#define	LONG_MAX ((long)(ULONG_MAX >> 1))   /* 0x7FFFFFFF for 32-bits */
-#endif
-
-#if !defined (ULONGEST_MAX)
-#define	ULONGEST_MAX (~(ULONGEST)0)        /* 0xFFFFFFFFFFFFFFFF for 64-bits */
-#endif
-
-#if !defined (LONGEST_MAX)                 /* 0x7FFFFFFFFFFFFFFF for 64-bits */
-#define	LONGEST_MAX ((LONGEST)(ULONGEST_MAX >> 1))
-#endif
-
 /* * Convert a LONGEST to an int.  This is used in contexts (e.g. number of
    arguments to a function, number in a value history, register number, etc.)
    where the value must not be larger than can fit in an int.  */
Index: src/gdb/gnu-nat.c
===================================================================
--- src.orig/gdb/gnu-nat.c
+++ src/gdb/gnu-nat.c
@@ -52,7 +52,6 @@ extern "C"
 #include "defs.h"
 
 #include <ctype.h>
-#include <limits.h>
 #include <setjmp.h>
 #include <signal.h>
 #include <sys/ptrace.h>
Index: src/gdbsupport/common-types.h
===================================================================
--- src.orig/gdbsupport/common-types.h
+++ src/gdbsupport/common-types.h
@@ -36,9 +36,15 @@ typedef uint64_t ULONGEST;
 /* * The largest CORE_ADDR value.  */
 #define CORE_ADDR_MAX (~(CORE_ADDR) 0)
 
-/* * The largest ULONGEST value.  */
+/* * The largest ULONGEST value, 0xFFFFFFFFFFFFFFFF for 64-bits.  */
 #define ULONGEST_MAX (~(ULONGEST) 0)
 
+/* * The largest LONGEST value, 0x7FFFFFFFFFFFFFFF for 64-bits.  */
+#define LONGEST_MAX ((LONGEST) (ULONGEST_MAX >> 1))
+
+/* * The smallest LONGEST value, 0x8000000000000000 for 64-bits.  */
+#define LONGEST_MIN ((LONGEST) (~(LONGEST) 0 ^ LONGEST_MAX))
+
 enum tribool { TRIBOOL_UNKNOWN = -1, TRIBOOL_FALSE = 0, TRIBOOL_TRUE = 1 };
 
 #endif /* COMMON_COMMON_TYPES_H */

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v4 2/6] GDB: Ignore `max-value-size' setting with value history accesses
  2023-02-10 14:18 [PATCH v4 0/6] gdb: introduce limited array lengths while printing values Maciej W. Rozycki
  2023-02-10 14:19 ` [PATCH v4 1/6] GDB: Switch to using C++ standard integer type limits Maciej W. Rozycki
@ 2023-02-10 14:19 ` Maciej W. Rozycki
  2023-02-10 14:19 ` [PATCH v4 3/6] GDB: Fix the mess with value byte/bit range types Maciej W. Rozycki
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 14+ messages in thread
From: Maciej W. Rozycki @ 2023-02-10 14:19 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Tom Tromey, Richard Bunt

We have an inconsistency in value history accesses where array element 
accesses cause an error for entries exceeding the currently selected 
`max-value-size' setting even where such accesses successfully complete 
for elements located in the inferior, e.g.:

  (gdb) p/d one
  $1 = 0
  (gdb) p/d one_hundred
  $2 = {0 <repeats 100 times>}
  (gdb) p/d one_hundred[99]
  $3 = 0
  (gdb) set max-value-size 25
  (gdb) p/d one_hundred
  value requires 100 bytes, which is more than max-value-size
  (gdb) p/d one_hundred[99]
  $7 = 0
  (gdb) p/d $2
  value requires 100 bytes, which is more than max-value-size
  (gdb) p/d $2[99]
  value requires 100 bytes, which is more than max-value-size
  (gdb) 

According to our documentation the `max-value-size' setting is a safety 
guard against allocating an overly large amount of memory.  Moreover a 
statement in documentation says, concerning this setting, that: "Setting 
this variable does not affect values that have already been allocated 
within GDB, only future allocations."  While in the implementer-speak 
the sentence may be unambiguous I think the outside user may well infer 
that the setting does not apply to values previously printed.

Therefore rather than just fixing this inconsistency it seems reasonable 
to lift the setting for value history accesses, under an implication 
that by having been retrieved from the debuggee they have already passed 
the safety check.  Do it then, by suppressing the value size check in 
`value_copy' -- under an observation that if the original value has been 
already loaded (i.e. it's not lazy), then it must have previously passed 
said check -- making the last two commands succeed:

  (gdb) p/d $2
  $8 = {0 <repeats 100 times>}
  (gdb) p/d $2 [99]
  $9 = 0
  (gdb) 

Expand the testsuite accordingly, covering both value history handling 
and the use of `value_copy' by `make_cv_value', used by Python code.
---
Changes from v3:

- Clarify the change description as to what the outside user may well
  infer; s/effect/affect/.

Changes from v2:

- Always suppress the size check in `value_copy' (keeping the grammatical 
  fix to the function description).

- Add Python coverage for `make_cv_value' vs `max-value-size'.

New change in v2.
---
 gdb/testsuite/gdb.base/max-value-size.exp |    3 ++
 gdb/testsuite/gdb.python/py-xmethods.exp  |   17 +++++++++++++
 gdb/testsuite/gdb.python/py-xmethods.py   |   17 +++++++++++++
 gdb/value.c                               |   38 ++++++++++++++++++------------
 4 files changed, 61 insertions(+), 14 deletions(-)

gdb-value-history-size.diff
Index: src/gdb/testsuite/gdb.base/max-value-size.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/max-value-size.exp
+++ src/gdb/testsuite/gdb.base/max-value-size.exp
@@ -53,6 +53,9 @@ proc do_value_printing { max_value_size
 	    gdb_test "p/d one_hundred" " = \\{0 <repeats 100 times>\\}"
 	}
 	gdb_test "p/d one_hundred \[99\]" " = 0"
+	# Verify that accessing value history is undisturbed.
+	gdb_test "p/d \$2" " = \\{0 <repeats 100 times>\\}"
+	gdb_test "p/d \$2 \[99\]" " = 0"
     }
 }
 
Index: src/gdb/testsuite/gdb.python/py-xmethods.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.python/py-xmethods.exp
+++ src/gdb/testsuite/gdb.python/py-xmethods.exp
@@ -160,3 +160,20 @@ gdb_test_no_output "enable xmethod progs
 gdb_test "pt e.method('a')" "type = void"
 gdb_test "pt e.method(10)" \
     "NotImplementedError.*Error while fetching result type of an xmethod worker defined in Python."
+
+# Verify `max-value-size' obedience with `gdb.Value.const_value'.
+gdb_test "p a1.getarray()" \
+  "From Python <A_getarray>.* = \\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9\\}" \
+  "after: a1.getarray"
+gdb_test "p b1.getarray()" \
+  "From Python <B_getarray>.* = \\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9\\}" \
+  "after: b1.getarray"
+gdb_test_no_output "python gdb.set_parameter('max-value-size', 16)"
+gdb_test "p a1.getarray()" \
+  "From Python <A_getarray>.*value requires $decimal bytes,\
+   which is more than max-value-size" \
+  "after: a1.getarray (max-value-size)"
+gdb_test "p b1.getarray()" \
+  "From Python <B_getarray>.*value requires $decimal bytes,\
+   which is more than max-value-size" \
+  "after: b1.getarray (max-value-size)"
Index: src/gdb/testsuite/gdb.python/py-xmethods.py
===================================================================
--- src.orig/gdb/testsuite/gdb.python/py-xmethods.py
+++ src/gdb/testsuite/gdb.python/py-xmethods.py
@@ -39,6 +39,11 @@ from gdb.xmethod import SimpleXMethodMat
     return obj["a"]
 
 
+def A_getarray(obj):
+    print("From Python <A_getarray>:")
+    return obj["array"]
+
+
 def A_getarrayind(obj, index):
     print("From Python <A_getarrayind>:")
     return obj["array"][index]
@@ -48,12 +53,18 @@ from gdb.xmethod import SimpleXMethodMat
     return obj["array"][index].reference_value()
 
 
+def B_getarray(obj):
+    print("From Python <B_getarray>:")
+    return obj["array"].const_value()
+
+
 def B_indexoper(obj, index):
     return obj["array"][index].const_value().reference_value()
 
 
 type_A = gdb.parse_and_eval("(dop::A *) 0").type.target()
 type_B = gdb.parse_and_eval("(dop::B *) 0").type.target()
+type_array = gdb.parse_and_eval("(int[10] *) 0").type.target()
 type_int = gdb.parse_and_eval("(int *) 0").type.target()
 
 
@@ -211,12 +222,18 @@ global_dm_list = [
     SimpleXMethodMatcher(r"plus_plus_A", r"^dop::A$", r"operator\+\+", plus_plus_A),
     SimpleXMethodMatcher(r"A_geta", r"^dop::A$", r"^geta$", A_geta),
     SimpleXMethodMatcher(
+        r"A_getarray", r"^dop::A$", r"^getarray$", A_getarray, type_array
+    ),
+    SimpleXMethodMatcher(
         r"A_getarrayind", r"^dop::A$", r"^getarrayind$", A_getarrayind, type_int
     ),
     SimpleXMethodMatcher(
         r"A_indexoper", r"^dop::A$", r"operator\[\]", A_indexoper, type_int
     ),
     SimpleXMethodMatcher(
+        r"B_getarray", r"^dop::B$", r"^getarray$", B_getarray, type_array
+    ),
+    SimpleXMethodMatcher(
         r"B_indexoper", r"^dop::B$", r"operator\[\]", B_indexoper, type_int
     ),
 ]
Index: src/gdb/value.c
===================================================================
--- src.orig/gdb/value.c
+++ src/gdb/value.c
@@ -1034,31 +1034,42 @@ check_type_length_before_alloc (const st
     }
 }
 
-/* Allocate the contents of VAL if it has not been allocated yet.  */
+/* 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.  */
 
 static void
-allocate_value_contents (struct value *val)
+allocate_value_contents (struct value *val, bool check_size)
 {
   if (!val->contents)
     {
-      check_type_length_before_alloc (val->enclosing_type);
+      if (check_size)
+	check_type_length_before_alloc (val->enclosing_type);
       val->contents.reset
 	((gdb_byte *) xzalloc (val->enclosing_type->length ()));
     }
 }
 
-/* Allocate a  value  and its contents for type TYPE.  */
+/* Allocate a value and its contents for type TYPE.  If CHECK_SIZE is true,
+   then apply the usual max-value-size checks.  */
 
-struct value *
-allocate_value (struct type *type)
+static struct value *
+allocate_value (struct type *type, bool check_size)
 {
   struct value *val = allocate_value_lazy (type);
 
-  allocate_value_contents (val);
+  allocate_value_contents (val, check_size);
   val->lazy = 0;
   return val;
 }
 
+/* Allocate a value and its contents for type TYPE.  */
+
+struct value *
+allocate_value (struct type *type)
+{
+  return allocate_value (type, true);
+}
+
 /* Allocate a  value  that has the correct length
    for COUNT repetitions of type TYPE.  */
 
@@ -1169,7 +1180,7 @@ value_contents_raw (struct value *value)
   struct gdbarch *arch = get_value_arch (value);
   int unit_size = gdbarch_addressable_memory_unit_size (arch);
 
-  allocate_value_contents (value);
+  allocate_value_contents (value, true);
 
   ULONGEST length = value_type (value)->length ();
   return gdb::make_array_view
@@ -1179,7 +1190,7 @@ value_contents_raw (struct value *value)
 gdb::array_view<gdb_byte>
 value_contents_all_raw (struct value *value)
 {
-  allocate_value_contents (value);
+  allocate_value_contents (value, true);
 
   ULONGEST length = value_enclosing_type (value)->length ();
   return gdb::make_array_view (value->contents.get (), length);
@@ -1752,9 +1763,8 @@ value_release_to_mark (const struct valu
   return result;
 }
 
-/* Return a copy of the value ARG.
-   It contains the same contents, for same memory address,
-   but it's a different block of storage.  */
+/* Return a copy of the value ARG.  It contains the same contents,
+   for the same memory address, but it's a different block of storage.  */
 
 struct value *
 value_copy (const value *arg)
@@ -1765,7 +1775,7 @@ value_copy (const value *arg)
   if (value_lazy (arg))
     val = allocate_value_lazy (encl_type);
   else
-    val = allocate_value (encl_type);
+    val = allocate_value (encl_type, false);
   val->type = arg->type;
   VALUE_LVAL (val) = arg->lval;
   val->location = arg->location;
@@ -4162,7 +4172,7 @@ void
 value_fetch_lazy (struct value *val)
 {
   gdb_assert (value_lazy (val));
-  allocate_value_contents (val);
+  allocate_value_contents (val, true);
   /* A value is either lazy, or fully fetched.  The
      availability/validity is only established as we try to fetch a
      value.  */

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v4 3/6] GDB: Fix the mess with value byte/bit range types
  2023-02-10 14:18 [PATCH v4 0/6] gdb: introduce limited array lengths while printing values Maciej W. Rozycki
  2023-02-10 14:19 ` [PATCH v4 1/6] GDB: Switch to using C++ standard integer type limits Maciej W. Rozycki
  2023-02-10 14:19 ` [PATCH v4 2/6] GDB: Ignore `max-value-size' setting with value history accesses Maciej W. Rozycki
@ 2023-02-10 14:19 ` Maciej W. Rozycki
  2023-02-10 14:19 ` [PATCH v4 4/6] GDB: Only make data actually retrieved into value history available Maciej W. Rozycki
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 14+ messages in thread
From: Maciej W. Rozycki @ 2023-02-10 14:19 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Tom Tromey, Richard Bunt

Consistently use the LONGEST and ULONGEST types for value byte/bit 
offsets and lengths respectively, avoiding silent truncation for ranges 
exceeding the 32-bit span, which may cause incorrect matching.  Also 
report a conversion overflow on byte ranges that cannot be expressed in 
terms of bits with these data types, e.g.:

  (gdb) print one_hundred[1LL << 58]
  Integer overflow in data location calculation
  (gdb) print one_hundred[(-1LL << 58) - 1]
  Integer overflow in data location calculation
  (gdb)

Previously such accesses would be let through with unpredictable results 
produced.
---
Changes from v3:

- s/slient/silent/ in change description.

No change from v2.

New change in v2.
---
 gdb/value.c |   43 ++++++++++++++++++++++++++-----------------
 gdb/value.h |    8 ++++----
 2 files changed, 30 insertions(+), 21 deletions(-)

gdb-value-range-types.diff
Index: src/gdb/value.c
===================================================================
--- src.orig/gdb/value.c
+++ src/gdb/value.c
@@ -74,7 +74,7 @@ struct range
   LONGEST offset;
 
   /* Length of the range.  */
-  LONGEST length;
+  ULONGEST length;
 
   /* Returns true if THIS is strictly less than OTHER, useful for
      searching.  We keep ranges sorted by offset and coalesce
@@ -97,10 +97,10 @@ struct range
    [offset2, offset2+len2) overlap.  */
 
 static int
-ranges_overlap (LONGEST offset1, LONGEST len1,
-		LONGEST offset2, LONGEST len2)
+ranges_overlap (LONGEST offset1, ULONGEST len1,
+		LONGEST offset2, ULONGEST len2)
 {
-  ULONGEST h, l;
+  LONGEST h, l;
 
   l = std::max (offset1, offset2);
   h = std::min (offset1 + len1, offset2 + len2);
@@ -112,7 +112,7 @@ ranges_overlap (LONGEST offset1, LONGEST
 
 static int
 ranges_contain (const std::vector<range> &ranges, LONGEST offset,
-		LONGEST length)
+		ULONGEST length)
 {
   range what;
 
@@ -380,7 +380,8 @@ get_value_arch (const struct value *valu
 }
 
 int
-value_bits_available (const struct value *value, LONGEST offset, LONGEST length)
+value_bits_available (const struct value *value,
+		      LONGEST offset, ULONGEST length)
 {
   gdb_assert (!value->lazy);
 
@@ -389,8 +390,16 @@ value_bits_available (const struct value
 
 int
 value_bytes_available (const struct value *value,
-		       LONGEST offset, LONGEST length)
+		       LONGEST offset, ULONGEST length)
 {
+  ULONGEST sign = (1ULL << (sizeof (ULONGEST) * 8 - 1)) / TARGET_CHAR_BIT;
+  ULONGEST mask = (sign << 1) - 1;
+
+  if (offset != ((offset & mask) ^ sign) - sign
+      || length != ((length & mask) ^ sign) - sign
+      || (length > 0 && (~offset & (offset + length - 1) & sign) != 0))
+    error (_("Integer overflow in data location calculation"));
+
   return value_bits_available (value,
 			       offset * TARGET_CHAR_BIT,
 			       length * TARGET_CHAR_BIT);
@@ -460,7 +469,7 @@ value_entirely_optimized_out (struct val
 
 static void
 insert_into_bit_range_vector (std::vector<range> *vectorp,
-			      LONGEST offset, LONGEST length)
+			      LONGEST offset, ULONGEST length)
 {
   range newr;
 
@@ -558,8 +567,8 @@ insert_into_bit_range_vector (std::vecto
       if (ranges_overlap (bef.offset, bef.length, offset, length))
 	{
 	  /* #1 */
-	  ULONGEST l = std::min (bef.offset, offset);
-	  ULONGEST h = std::max (bef.offset + bef.length, offset + length);
+	  LONGEST l = std::min (bef.offset, offset);
+	  LONGEST h = std::max (bef.offset + bef.length, offset + length);
 
 	  bef.offset = l;
 	  bef.length = h - l;
@@ -600,7 +609,7 @@ insert_into_bit_range_vector (std::vecto
 	  struct range &r = *i;
 	  if (r.offset <= t.offset + t.length)
 	    {
-	      ULONGEST l, h;
+	      LONGEST l, h;
 
 	      l = std::min (t.offset, r.offset);
 	      h = std::max (t.offset + t.length, r.offset + r.length);
@@ -626,14 +635,14 @@ insert_into_bit_range_vector (std::vecto
 
 void
 mark_value_bits_unavailable (struct value *value,
-			     LONGEST offset, LONGEST length)
+			     LONGEST offset, ULONGEST length)
 {
   insert_into_bit_range_vector (&value->unavailable, offset, length);
 }
 
 void
 mark_value_bytes_unavailable (struct value *value,
-			      LONGEST offset, LONGEST length)
+			      LONGEST offset, ULONGEST length)
 {
   mark_value_bits_unavailable (value,
 			       offset * TARGET_CHAR_BIT,
@@ -786,7 +795,7 @@ static int
 find_first_range_overlap_and_match (struct ranges_and_idx *rp1,
 				    struct ranges_and_idx *rp2,
 				    LONGEST offset1, LONGEST offset2,
-				    LONGEST length, ULONGEST *l, ULONGEST *h)
+				    ULONGEST length, ULONGEST *l, ULONGEST *h)
 {
   rp1->idx = find_first_range_overlap (rp1->ranges, rp1->idx,
 				       offset1, length);
@@ -1306,14 +1315,14 @@ value_contents_all (struct value *value)
 static void
 ranges_copy_adjusted (std::vector<range> *dst_range, int dst_bit_offset,
 		      const std::vector<range> &src_range, int src_bit_offset,
-		      int bit_length)
+		      unsigned int bit_length)
 {
   for (const range &r : src_range)
     {
-      ULONGEST h, l;
+      LONGEST h, l;
 
       l = std::max (r.offset, (LONGEST) src_bit_offset);
-      h = std::min (r.offset + r.length,
+      h = std::min ((LONGEST) (r.offset + r.length),
 		    (LONGEST) src_bit_offset + bit_length);
 
       if (l < h)
Index: src/gdb/value.h
===================================================================
--- src.orig/gdb/value.h
+++ src/gdb/value.h
@@ -505,7 +505,7 @@ extern int value_bits_synthetic_pointer
    byte is unavailable.  */
 
 extern int value_bytes_available (const struct value *value,
-				  LONGEST offset, LONGEST length);
+				  LONGEST offset, ULONGEST length);
 
 /* Given a value, determine whether the contents bits starting at
    OFFSET and extending for LENGTH bits are available.  This returns
@@ -513,7 +513,7 @@ extern int value_bytes_available (const
    bit is unavailable.  */
 
 extern int value_bits_available (const struct value *value,
-				 LONGEST offset, LONGEST length);
+				 LONGEST offset, ULONGEST length);
 
 /* Like value_bytes_available, but return false if any byte in the
    whole object is unavailable.  */
@@ -527,13 +527,13 @@ extern int value_entirely_unavailable (s
    LENGTH bytes as unavailable.  */
 
 extern void mark_value_bytes_unavailable (struct value *value,
-					  LONGEST offset, LONGEST length);
+					  LONGEST offset, ULONGEST length);
 
 /* Mark VALUE's content bits starting at OFFSET and extending for
    LENGTH bits as unavailable.  */
 
 extern void mark_value_bits_unavailable (struct value *value,
-					 LONGEST offset, LONGEST length);
+					 LONGEST offset, ULONGEST length);
 
 /* Compare LENGTH bytes of VAL1's contents starting at OFFSET1 with
    LENGTH bytes of VAL2's contents starting at OFFSET2.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v4 4/6] GDB: Only make data actually retrieved into value history available
  2023-02-10 14:18 [PATCH v4 0/6] gdb: introduce limited array lengths while printing values Maciej W. Rozycki
                   ` (2 preceding siblings ...)
  2023-02-10 14:19 ` [PATCH v4 3/6] GDB: Fix the mess with value byte/bit range types Maciej W. Rozycki
@ 2023-02-10 14:19 ` Maciej W. Rozycki
  2023-02-10 21:16   ` Tom Tromey
  2023-02-10 14:19 ` [PATCH v4 5/6] GDB/testsuite: Add `-nonl' option to `gdb_test' Maciej W. Rozycki
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 14+ messages in thread
From: Maciej W. Rozycki @ 2023-02-10 14:19 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Tom Tromey, Richard Bunt

While it makes sense to allow accessing out-of-bounds elements in the 
debuggee and see whatever there might happen to be there in memory (we 
are a debugger and not a programming rules enforcement facility and we 
want to make people's life easier in chasing bugs), e.g.:

  (gdb) print one_hundred[-1]
  $1 = 0
  (gdb) print one_hundred[100]
  $2 = 0
  (gdb) 

we shouldn't really pretend that we have any meaningful data around 
values recorded in history (what these commands really retrieve are 
current debuggee memory contents outside the original data accessed, 
really confusing in my opinion).  Mark values recorded in history as 
such then and verify accesses to be in-range for them:

  (gdb) print one_hundred[-1]
  $1 = <unavailable>
  (gdb) print one_hundred[100]
  $2 = <unavailable>

Add a suitable test case, which also covers integer overflows in data 
location calculation.
---
Changes from v3:

- Do not mark ranges outside values put in the value history unavailable.  
  Instead annotate values as placed in the value history and verify ranges 
  explicitly at access time for them.  Remove all previous additions for 
  range handling.

Changes from v2:

- Correct the copyright year in new files.

New change in v2.
---
 gdb/testsuite/gdb.base/value-history-unavailable.c   |   29 +++++++
 gdb/testsuite/gdb.base/value-history-unavailable.exp |   73 +++++++++++++++++++
 gdb/valarith.c                                       |   15 +++
 gdb/value.c                                          |   17 ++++
 4 files changed, 133 insertions(+), 1 deletion(-)

gdb-value-history-unavailable.diff
Index: src/gdb/testsuite/gdb.base/value-history-unavailable.c
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.base/value-history-unavailable.c
@@ -0,0 +1,29 @@
+/* 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/>.  */
+
+struct
+{
+  unsigned char x[1024];
+  unsigned char a[1024];
+  unsigned char y[1024];
+} a = { {-1} };
+
+int
+main ()
+{
+  return 0;
+}
Index: src/gdb/testsuite/gdb.base/value-history-unavailable.exp
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.base/value-history-unavailable.exp
@@ -0,0 +1,73 @@
+# 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/>.
+
+# Test GDB's value availability ranges.
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile] } {
+    return -1
+}
+
+if ![runto_main] then {
+    perror "couldn't run to breakpoint"
+    continue
+}
+
+set target_char_mask [get_valueof "/u" "a.x\[0]" "255" "get target char mask"]
+set target_char_bit 0
+for {set i $target_char_mask} {$i > 0} {set i [expr $i >> 1]} {
+    incr target_char_bit
+}
+set target_char_rank -1
+for {set i $target_char_bit} {$i > 0} {set i [expr $i >> 1]} {
+    incr target_char_rank
+}
+
+# Verify accesses to original inferior data.
+gdb_test "print a.a" "\\\$2 = '\\\\000' <repeats 1023 times>"
+gdb_test "print a.a\[-1\]" "\\\$3 = 0 '\\\\000'"
+gdb_test "print a.a\[1024\]" "\\\$4 = 0 '\\\\000'"
+
+# Verify in-range value history accesses.
+gdb_test "print \$2" "\\\$5 = '\\\\000' <repeats 1023 times>"
+gdb_test "print \$2\[0\]" "\\\$6 = 0 '\\\\000'"
+gdb_test "print \$2\[1023\]" "\\\$7 = 0 '\\\\000'"
+
+# Values outside the array recorded will have not been retrieved.
+gdb_test "print \$2\[-1\]" "\\\$8 = <unavailable>"
+gdb_test "print \$2\[1024\]" "\\\$9 = <unavailable>"
+gdb_test "print \$2\[-1LL << 63 - $target_char_rank\]" \
+	"\\\$10 = <unavailable>"
+gdb_test "print \$2\[(1LL << 63 - $target_char_rank) - 1\]" \
+	"\\\$11 = <unavailable>"
+
+# Accesses through pointers in history go straight to the inferior though.
+gdb_test "print \$2\[0\]@1" "\\\$12 = \"\""
+gdb_test "print \$2\[-1\]@1" "\\\$13 = \"\""
+gdb_test "print \$2\[1024\]@1" "\\\$14 = \"\""
+
+# Verify out-of-range value history accesses.
+gdb_test "print \$2\[(-1LL << 63 - $target_char_rank) - 1\]" \
+    "Integer overflow in data location calculation"
+gdb_test "print \$2\[(1LL << 63 - $target_char_rank)\]" \
+    "Integer overflow in data location calculation"
+gdb_test "print \$2\[-1LL << 63\]" \
+    "Integer overflow in data location calculation"
+gdb_test "print \$2\[(1ULL << 63) - 1\]" \
+    "Integer overflow in data location calculation"
+
+# Sanity-check a copy of an unavailable value.
+gdb_test "print \$11" "\\\$15 = <unavailable>"
Index: src/gdb/valarith.c
===================================================================
--- src.orig/gdb/valarith.c
+++ src/gdb/valarith.c
@@ -182,6 +182,21 @@ value_subscript (struct value *array, LO
 	}
 
       index -= *lowerbound;
+
+      /* Do not try to dereference a pointer to an unavailable value.
+	 Instead mock up a new one and give it the original address.  */
+      struct type *elt_type = check_typedef (tarray->target_type ());
+      LONGEST elt_size = type_length_units (elt_type);
+      if (!value_lazy (array)
+	  && !value_bytes_available (array, elt_size * index, elt_size))
+	{
+	  struct value *val = allocate_value (elt_type);
+	  mark_value_bytes_unavailable (val, 0, elt_size);
+	  VALUE_LVAL (val) = lval_memory;
+	  set_value_address (val, value_address (array) + elt_size * index);
+	  return val;
+	}
+
       array = value_coerce_array (array);
     }
 
Index: src/gdb/value.c
===================================================================
--- src.orig/gdb/value.c
+++ src/gdb/value.c
@@ -185,6 +185,7 @@ struct value
       initialized (1),
       stack (0),
       is_zero (false),
+      in_history (false),
       type (type_),
       enclosing_type (type_)
   {
@@ -239,6 +240,9 @@ struct value
      otherwise.  */
   bool is_zero : 1;
 
+  /* True if this a value recorded in value history; false otherwise.  */
+  bool in_history : 1;
+
   /* Location of value (if lval).  */
   union
   {
@@ -385,7 +389,13 @@ value_bits_available (const struct value
 {
   gdb_assert (!value->lazy);
 
-  return !ranges_contain (value->unavailable, offset, length);
+  /* 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 val_len = TARGET_CHAR_BIT * value_enclosing_type (value)->length ();
+  return !((value->in_history
+	    && (offset < 0 || offset + length > val_len))
+	   || ranges_contain (value->unavailable, offset, length));
 }
 
 int
@@ -1797,6 +1807,7 @@ value_copy (const value *arg)
   val->modifiable = arg->modifiable;
   val->stack = arg->stack;
   val->is_zero = arg->is_zero;
+  val->in_history = arg->in_history;
   val->initialized = arg->initialized;
   val->unavailable = arg->unavailable;
   val->optimized_out = arg->optimized_out;
@@ -1950,6 +1961,10 @@ record_latest_value (struct value *val)
      a value on the value history never changes.  */
   if (value_lazy (val))
     value_fetch_lazy (val);
+
+  /* Mark the value as recorded in the history for the availability check.  */
+  val->in_history = true;
+
   /* 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
      but the current contents of that location.  c'est la vie...  */

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v4 5/6] GDB/testsuite: Add `-nonl' option to `gdb_test'
  2023-02-10 14:18 [PATCH v4 0/6] gdb: introduce limited array lengths while printing values Maciej W. Rozycki
                   ` (3 preceding siblings ...)
  2023-02-10 14:19 ` [PATCH v4 4/6] GDB: Only make data actually retrieved into value history available Maciej W. Rozycki
@ 2023-02-10 14:19 ` Maciej W. Rozycki
  2023-02-10 14:19 ` [PATCH v4 6/6] GDB: Introduce limited array lengths while printing values Maciej W. Rozycki
  2023-02-10 21:17 ` [PATCH v4 0/6] gdb: introduce " Tom Tromey
  6 siblings, 0 replies; 14+ messages in thread
From: Maciej W. Rozycki @ 2023-02-10 14:19 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Tom Tromey, Richard Bunt

Add a `-nonl' option to `gdb_test' making it possible to match output 
from commands such as `output' that do not produce a new line sequence 
at the end, e.g.:

  (gdb) output 0
  0(gdb)
---
No change from v3.

No change from v2.

New change in v2.
---
 gdb/testsuite/lib/gdb.exp |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

gdb-test-nonl.diff
Index: src/gdb/testsuite/lib/gdb.exp
===================================================================
--- src.orig/gdb/testsuite/lib/gdb.exp
+++ src/gdb/testsuite/lib/gdb.exp
@@ -1395,6 +1395,8 @@ proc gdb_test_multiline { name args } {
 #   have any effect if -prompt is specified.
 # -lbl specifies that line-by-line matching will be used.
 # -nopass specifies that a PASS should not be issued.
+# -nonl specifies that no \r\n sequence is expected between PATTERN
+#   and the gdb prompt.
 #
 # Returns:
 #    1 if the test failed,
@@ -1410,6 +1412,7 @@ proc gdb_test { args } {
 	{no-prompt-anchor}
 	{lbl}
 	{nopass}
+	{nonl}
     }
 
     lassign $args command pattern message question response
@@ -1424,12 +1427,13 @@ proc gdb_test { args } {
     }
 
     set prompt [fill_in_default_prompt $prompt [expr !${no-prompt-anchor}]]
+    set nl [expr ${nonl} ? {""} : {"\[\r\n\]+"}]
 
     set saw_question 0
 
     set user_code {}
     lappend user_code {
-	-re "\[\r\n\]*(?:$pattern)\[\r\n\]+$prompt" {
+	-re "\[\r\n\]*(?:$pattern)$nl$prompt" {
 	    if { $question != "" & !$saw_question} {
 		fail $message
 	    } elseif {!$nopass} {

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v4 6/6] GDB: Introduce limited array lengths while printing values
  2023-02-10 14:18 [PATCH v4 0/6] gdb: introduce limited array lengths while printing values Maciej W. Rozycki
                   ` (4 preceding siblings ...)
  2023-02-10 14:19 ` [PATCH v4 5/6] GDB/testsuite: Add `-nonl' option to `gdb_test' Maciej W. Rozycki
@ 2023-02-10 14:19 ` Maciej W. Rozycki
  2023-02-13 14:45   ` Simon Marchi
  2023-02-10 21:17 ` [PATCH v4 0/6] gdb: introduce " Tom Tromey
  6 siblings, 1 reply; 14+ messages in thread
From: Maciej W. Rozycki @ 2023-02-10 14:19 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Tom Tromey, Richard Bunt

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 v3:

- Rework changes to `record_latest_value' following the removal of code to 
  mark outside ranges unavailable.

- Update `set_limited_array_length' introductory comment.

- Rebase NEWS update following GDB 13 branching.

Changes from v2:

- Adjust for the `value_copy' update in 1/5.

- Remove the handling of (dst_len != src_len) in `value_copy' where
  `dst_len' is always the same as `src_len' (from the corresponding 
  settings in `val' assigned to from `arg' right beforehand).

- Switch Ada and Fortran test cases to using `allow_ada_tests' and 
  `allow_fortran_tests' respectively.

- Fix a couple of formatting issues involving spaces used instead of tabs.

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     |  264 +++++++++++++++++++++++++++
 gdb/testsuite/gdb.ada/limited-length/foo.adb |   37 +++
 gdb/testsuite/gdb.ada/limited-length/pck.adb |   25 ++
 gdb/testsuite/gdb.ada/limited-length/pck.ads |   21 ++
 gdb/testsuite/gdb.base/limited-length.c      |   48 ++++
 gdb/testsuite/gdb.base/limited-length.exp    |  242 ++++++++++++++++++++++++
 gdb/testsuite/gdb.fortran/limited-length.exp |  220 ++++++++++++++++++++++
 gdb/testsuite/gdb.fortran/limited-length.f90 |   39 +++
 gdb/valprint.c                               |   10 -
 gdb/value.c                                  |  187 +++++++++++++++++--
 gdb/value.h                                  |   17 +
 15 files changed, 1149 insertions(+), 24 deletions(-)
 create mode 100644 gdb/testsuite/gdb.ada/limited-length.exp
 create mode 100644 gdb/testsuite/gdb.ada/limited-length/foo.adb
 create mode 100644 gdb/testsuite/gdb.ada/limited-length/pck.adb
 create mode 100644 gdb/testsuite/gdb.ada/limited-length/pck.ads
 create mode 100644 gdb/testsuite/gdb.base/limited-length.c
 create mode 100644 gdb/testsuite/gdb.base/limited-length.exp
 create mode 100644 gdb/testsuite/gdb.fortran/limited-length.exp
 create mode 100644 gdb/testsuite/gdb.fortran/limited-length.f90

gdb-aburgess-limited-length-array.diff
Index: src/gdb/NEWS
===================================================================
--- src.orig/gdb/NEWS
+++ src/gdb/NEWS
@@ -44,6 +44,12 @@
   keyword already gave an error when used multiple times with the
   watch command, this remains unchanged.
 
+* The 'set print elements' setting now helps when printing large arrays.
+  If an array would otherwise exceed max-value-size, but 'print elements'
+  is set such that the size of elements to print is less than or equal
+  to 'max-value-size', GDB will now still print the array, however only
+  'max-value-size' worth of data will be added into the value history.
+
 * New commands
 
 maintenance print record-instruction [ N ]
Index: src/gdb/doc/gdb.texinfo
===================================================================
--- src.orig/gdb/doc/gdb.texinfo
+++ src/gdb/doc/gdb.texinfo
@@ -11759,6 +11759,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.
 
@@ -14174,6 +14182,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,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"
+}
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,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"
+}
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
@@ -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 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 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 *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));
     }
 }
 
@@ -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 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);
+    }
+
+  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 *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
@@ -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) */

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v4 1/6] GDB: Switch to using C++ standard integer type limits
  2023-02-10 14:19 ` [PATCH v4 1/6] GDB: Switch to using C++ standard integer type limits Maciej W. Rozycki
@ 2023-02-10 21:13   ` Tom Tromey
  0 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2023-02-10 21:13 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches, Andrew Burgess, Tom Tromey, Richard Bunt

>>>>> "Maciej" == Maciej W Rozycki <macro@embecosm.com> writes:

Maciej> Use <climits> instead of <limits.h> and ditch local fallback definitions 
Maciej> for minimum and maximum value macros provided by C++11.  Add LONGEST_MAX 
Maciej> and LONGEST_MIN definitions.
Maciej> ---
Maciej> New change in v4.

Thank you.

Approved-By: Tom Tromey <tom@tromey.com>

Tom

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v4 4/6] GDB: Only make data actually retrieved into value history available
  2023-02-10 14:19 ` [PATCH v4 4/6] GDB: Only make data actually retrieved into value history available Maciej W. Rozycki
@ 2023-02-10 21:16   ` Tom Tromey
  0 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2023-02-10 21:16 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches, Andrew Burgess, Tom Tromey, Richard Bunt

>>>>> "Maciej" == Maciej W Rozycki <macro@embecosm.com> writes:

Maciej> Mark values recorded in history as 
Maciej> such then and verify accesses to be in-range for them:

Makes sense to me.

Approved-By: Tom Tromey <tom@tromey.com>

Tom

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v4 0/6] gdb: introduce limited array lengths while printing values
  2023-02-10 14:18 [PATCH v4 0/6] gdb: introduce limited array lengths while printing values Maciej W. Rozycki
                   ` (5 preceding siblings ...)
  2023-02-10 14:19 ` [PATCH v4 6/6] GDB: Introduce limited array lengths while printing values Maciej W. Rozycki
@ 2023-02-10 21:17 ` Tom Tromey
  2023-02-10 23:50   ` Maciej W. Rozycki
  6 siblings, 1 reply; 14+ messages in thread
From: Tom Tromey @ 2023-02-10 21:17 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches, Andrew Burgess, Tom Tromey, Richard Bunt

>>>>> "Maciej" == Maciej W Rozycki <macro@embecosm.com> writes:

Maciej>  I have regression-tested it natively with a `x86_64-linux-gnu' system.  
Maciej> OK to apply?

Thank you for doing this.  I think this is ok.

Tom

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v4 0/6] gdb: introduce limited array lengths while printing values
  2023-02-10 21:17 ` [PATCH v4 0/6] gdb: introduce " Tom Tromey
@ 2023-02-10 23:50   ` Maciej W. Rozycki
  0 siblings, 0 replies; 14+ messages in thread
From: Maciej W. Rozycki @ 2023-02-10 23:50 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches, Andrew Burgess, Richard Bunt

On Fri, 10 Feb 2023, Tom Tromey wrote:

> Maciej>  I have regression-tested it natively with a `x86_64-linux-gnu' system.  
> Maciej> OK to apply?
> 
> Thank you for doing this.  I think this is ok.

 I have committed the series now.  Thank you for your review.

  Maciej

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v4 6/6] GDB: Introduce limited array lengths while printing values
  2023-02-10 14:19 ` [PATCH v4 6/6] GDB: Introduce limited array lengths while printing values Maciej W. Rozycki
@ 2023-02-13 14:45   ` Simon Marchi
  2023-02-14 19:20     ` Maciej W. Rozycki
  0 siblings, 1 reply; 14+ messages in thread
From: Simon Marchi @ 2023-02-13 14:45 UTC (permalink / raw)
  To: Maciej W. Rozycki, gdb-patches; +Cc: Andrew Burgess, Tom Tromey, Richard Bunt



On 2/10/23 09:19, Maciej W. Rozycki wrote:
> 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 v3:
> 
> - Rework changes to `record_latest_value' following the removal of code to 
>   mark outside ranges unavailable.
> 
> - Update `set_limited_array_length' introductory comment.
> 
> - Rebase NEWS update following GDB 13 branching.
> 
> Changes from v2:
> 
> - Adjust for the `value_copy' update in 1/5.
> 
> - Remove the handling of (dst_len != src_len) in `value_copy' where
>   `dst_len' is always the same as `src_len' (from the corresponding 
>   settings in `val' assigned to from `arg' right beforehand).
> 
> - Switch Ada and Fortran test cases to using `allow_ada_tests' and 
>   `allow_fortran_tests' respectively.
> 
> - Fix a couple of formatting issues involving spaces used instead of tabs.
> 
> 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.

I see:

print -elements 2 -- Large_3d_Array
=================================================================
==25757==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60d000028ed4 at pc 0x7f3ee9c5efd6 bp 0x7ffe215215b0 sp 0x7ffe21520d58
READ of size 64 at 0x60d000028ed4 thread T0
    #0 0x7f3ee9c5efd5 in __interceptor_memmove /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:810
    #1 0x563e8a43bca1 in unsigned char* std::__copy_move<false, true, std::random_access_iterator_tag>::__copy_m<unsigned char>(unsigned char const*, unsigned char const*, unsigned char*) /usr/include/c++/12.2.1/bits/stl_algobase.h:431
    #2 0x563e8a56df07 in unsigned char* std::__copy_move_a2<false, unsigned char const*, unsigned char*>(unsigned char const*, unsigned char const*, unsigned char*) /usr/include/c++/12.2.1/bits/stl_algobase.h:495
    #3 0x563e8a558ada in unsigned char* std::__copy_move_a1<false, unsigned char const*, unsigned char*>(unsigned char const*, unsigned char const*, unsigned char*) /usr/include/c++/12.2.1/bits/stl_algobase.h:522
    #4 0x563e8a538725 in unsigned char* std::__copy_move_a<false, unsigned char const*, unsigned char*>(unsigned char const*, unsigned char const*, unsigned char*) /usr/include/c++/12.2.1/bits/stl_algobase.h:529
    #5 0x563e8a517cda in unsigned char* std::copy<unsigned char const*, unsigned char*>(unsigned char const*, unsigned char const*, unsigned char*) /usr/include/c++/12.2.1/bits/stl_algobase.h:620
    #6 0x563e8a4facff in void gdb::copy<unsigned char const, unsigned char>(gdb::array_view<unsigned char const>, gdb::array_view<unsigned char>) /home/simark/src/binutils-gdb/gdb/../gdbsupport/array-view.h:219
    #7 0x563e8d14c6ea in value_contents_copy_raw /home/simark/src/binutils-gdb/gdb/value.c:1512
    #8 0x563e8d14ced7 in value_contents_copy(value*, long, value*, long, long) /home/simark/src/binutils-gdb/gdb/value.c:1578
    #9 0x563e8d1626fc in value_from_component(value*, type*, long) /home/simark/src/binutils-gdb/gdb/value.c:3991
    #10 0x563e8d16291a in value_from_component_bitsize(value*, type*, long, long) /home/simark/src/binutils-gdb/gdb/value.c:4015
    #11 0x563e8d12c000 in value_print_array_elements(value*, ui_file*, int, value_print_options const*, unsigned int) /home/simark/src/binutils-gdb/gdb/valprint.c:2027
    #12 0x563e8a6145a5 in ada_value_print_array /home/simark/src/binutils-gdb/gdb/ada-valprint.c:931
    #13 0x563e8a615207 in ada_value_print_inner(value*, ui_file*, int, value_print_options const*) /home/simark/src/binutils-gdb/gdb/ada-valprint.c:1075
    #14 0x563e8a4efd35 in ada_language::value_print_inner(value*, ui_file*, int, value_print_options const*) const /home/simark/src/binutils-gdb/gdb/ada-lang.c:13793
    #15 0x563e8d125457 in common_val_print(value*, ui_file*, int, value_print_options const*, language_defn const*) /home/simark/src/binutils-gdb/gdb/valprint.c:1094
    #16 0x563e8a615979 in ada_value_print(value*, ui_file*, value_print_options const*) /home/simark/src/binutils-gdb/gdb/ada-valprint.c:1133
    #17 0x563e8a4efd00 in ada_language::value_print(value*, ui_file*, value_print_options const*) const /home/simark/src/binutils-gdb/gdb/ada-lang.c:13784
    #18 0x563e8d1266a1 in value_print(value*, ui_file*, value_print_options const*) /home/simark/src/binutils-gdb/gdb/valprint.c:1211
    #19 0x563e8c169299 in print_formatted /home/simark/src/binutils-gdb/gdb/printcmd.c:337
    #20 0x563e8c1708e4 in print_value(value*, value_print_options const&) /home/simark/src/binutils-gdb/gdb/printcmd.c:1258
    #21 0x563e8c1713e2 in print_command_1 /home/simark/src/binutils-gdb/gdb/printcmd.c:1372
    #22 0x563e8c171ee7 in print_command /home/simark/src/binutils-gdb/gdb/printcmd.c:1463
    #23 0x563e8ac9adba in do_simple_func /home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:95
    #24 0x563e8acb1aa8 in cmd_func(cmd_list_element*, char const*, int) /home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:2737
    #25 0x563e8cc7f8aa in execute_command(char const*, int) /home/simark/src/binutils-gdb/gdb/top.c:688
    #26 0x563e8b69f9b6 in command_handler(char const*) /home/simark/src/binutils-gdb/gdb/event-top.c:620
    #27 0x563e8b6a0c93 in command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) /home/simark/src/binutils-gdb/gdb/event-top.c:856
    #28 0x563e8cdce8b8 in tui_command_line_handler /home/simark/src/binutils-gdb/gdb/tui/tui-interp.c:104
    #29 0x563e8b69d8a9 in gdb_rl_callback_handler /home/simark/src/binutils-gdb/gdb/event-top.c:250
    #30 0x563e8d2d88a8 in rl_callback_read_char /home/simark/src/binutils-gdb/readline/readline/callback.c:290
    #31 0x563e8b69d29f in gdb_rl_callback_read_char_wrapper_noexcept /home/simark/src/binutils-gdb/gdb/event-top.c:192
    #32 0x563e8b69d4f7 in gdb_rl_callback_read_char_wrapper /home/simark/src/binutils-gdb/gdb/event-top.c:225
    #33 0x563e8b69eeb6 in stdin_event_handler /home/simark/src/binutils-gdb/gdb/event-top.c:545
    #34 0x563e8d680339 in handle_file_event /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:573
    #35 0x563e8d680c7f in gdb_wait_for_event /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:694
    #36 0x563e8d67e940 in gdb_do_one_event(int) /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:264
    #37 0x563e8bdd8f65 in start_event_loop /home/simark/src/binutils-gdb/gdb/main.c:411
    #38 0x563e8bdd93cb in captured_command_loop /home/simark/src/binutils-gdb/gdb/main.c:471
    #39 0x563e8bdde775 in captured_main /home/simark/src/binutils-gdb/gdb/main.c:1310
    #40 0x563e8bdde852 in gdb_main(captured_main_args*) /home/simark/src/binutils-gdb/gdb/main.c:1325
    #41 0x563e8a39759d in main /home/simark/src/binutils-gdb/gdb/gdb.c:32
    #42 0x7f3ee863c78f  (/usr/lib/libc.so.6+0x2378f)
    #43 0x7f3ee863c849 in __libc_start_main (/usr/lib/libc.so.6+0x23849)
    #44 0x563e8a397364 in _start (/home/simark/build/binutils-gdb/gdb/gdb+0xabae364)

0x60d000028ed4 is located 0 bytes to the right of 132-byte region [0x60d000028e50,0x60d000028ed4)
allocated by thread T0 here:
    #0 0x7f3ee9cbf411 in __interceptor_calloc /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:77
    #1 0x563e8a62c4ec in xcalloc /home/simark/src/binutils-gdb/gdb/alloc.c:97
    #2 0x563e8d66cfff in xzalloc(unsigned long) /home/simark/src/binutils-gdb/gdbsupport/common-utils.cc:29
    #3 0x563e8d149569 in allocate_value_contents /home/simark/src/binutils-gdb/gdb/value.c:1179
    #4 0x563e8d1659e5 in value_fetch_lazy(value*) /home/simark/src/binutils-gdb/gdb/value.c:4354
    #5 0x563e8d1546f5 in record_latest_value(value*) /home/simark/src/binutils-gdb/gdb/value.c:2099
    #6 0x563e8c170833 in print_value(value*, value_print_options const&) /home/simark/src/binutils-gdb/gdb/printcmd.c:1250
    #7 0x563e8c1713e2 in print_command_1 /home/simark/src/binutils-gdb/gdb/printcmd.c:1372
    #8 0x563e8c171ee7 in print_command /home/simark/src/binutils-gdb/gdb/printcmd.c:1463
    #9 0x563e8ac9adba in do_simple_func /home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:95
    #10 0x563e8acb1aa8 in cmd_func(cmd_list_element*, char const*, int) /home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:2737
    #11 0x563e8cc7f8aa in execute_command(char const*, int) /home/simark/src/binutils-gdb/gdb/top.c:688
    #12 0x563e8b69f9b6 in command_handler(char const*) /home/simark/src/binutils-gdb/gdb/event-top.c:620
    #13 0x563e8b6a0c93 in command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) /home/simark/src/binutils-gdb/gdb/event-top.c:856
    #14 0x563e8cdce8b8 in tui_command_line_handler /home/simark/src/binutils-gdb/gdb/tui/tui-interp.c:104
    #15 0x563e8b69d8a9 in gdb_rl_callback_handler /home/simark/src/binutils-gdb/gdb/event-top.c:250
    #16 0x563e8d2d88a8 in rl_callback_read_char /home/simark/src/binutils-gdb/readline/readline/callback.c:290
    #17 0x563e8b69d29f in gdb_rl_callback_read_char_wrapper_noexcept /home/simark/src/binutils-gdb/gdb/event-top.c:192
    #18 0x563e8b69d4f7 in gdb_rl_callback_read_char_wrapper /home/simark/src/binutils-gdb/gdb/event-top.c:225
    #19 0x563e8b69eeb6 in stdin_event_handler /home/simark/src/binutils-gdb/gdb/event-top.c:545
    #20 0x563e8d680339 in handle_file_event /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:573
    #21 0x563e8d680c7f in gdb_wait_for_event /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:694
    #22 0x563e8d67e940 in gdb_do_one_event(int) /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:264
    #23 0x563e8bdd8f65 in start_event_loop /home/simark/src/binutils-gdb/gdb/main.c:411
    #24 0x563e8bdd93cb in captured_command_loop /home/simark/src/binutils-gdb/gdb/main.c:471
    #25 0x563e8bdde775 in captured_main /home/simark/src/binutils-gdb/gdb/main.c:1310
    #26 0x563e8bdde852 in gdb_main(captured_main_args*) /home/simark/src/binutils-gdb/gdb/main.c:1325
    #27 0x563e8a39759d in main /home/simark/src/binutils-gdb/gdb/gdb.c:32
    #28 0x7f3ee863c78f  (/usr/lib/libc.so.6+0x2378f)

Simon

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v4 6/6] GDB: Introduce limited array lengths while printing values
  2023-02-13 14:45   ` Simon Marchi
@ 2023-02-14 19:20     ` Maciej W. Rozycki
  2023-02-23 21:16       ` Maciej W. Rozycki
  0 siblings, 1 reply; 14+ messages in thread
From: Maciej W. Rozycki @ 2023-02-14 19:20 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches, Andrew Burgess, Tom Tromey, Richard Bunt

On Mon, 13 Feb 2023, Simon Marchi wrote:

> I see:
> 
> print -elements 2 -- Large_3d_Array
> =================================================================
> ==25757==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60d000028ed4 at pc 0x7f3ee9c5efd6 bp 0x7ffe215215b0 sp 0x7ffe21520d58
> READ of size 64 at 0x60d000028ed4 thread T0

 Thanks for the report and sorry about the breakage.  It did not show up 
in regular testing.  I cannot look into it this week, but I will the next.

  Maciej

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v4 6/6] GDB: Introduce limited array lengths while printing values
  2023-02-14 19:20     ` Maciej W. Rozycki
@ 2023-02-23 21:16       ` Maciej W. Rozycki
  0 siblings, 0 replies; 14+ messages in thread
From: Maciej W. Rozycki @ 2023-02-23 21:16 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches, Andrew Burgess, Tom Tromey, Richard Bunt

On Tue, 14 Feb 2023, Maciej W. Rozycki wrote:

> > I see:
> > 
> > print -elements 2 -- Large_3d_Array
> > =================================================================
> > ==25757==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60d000028ed4 at pc 0x7f3ee9c5efd6 bp 0x7ffe215215b0 sp 0x7ffe21520d58
> > READ of size 64 at 0x60d000028ed4 thread T0
> 
>  Thanks for the report and sorry about the breakage.  It did not show up 
> in regular testing.  I cannot look into it this week, but I will the next.

 Fix now posted: 
<https://sourceware.org/pipermail/gdb-patches/2023-February/197338.html>.  
Thank you for patience.

  Maciej

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2023-02-23 21:16 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-10 14:18 [PATCH v4 0/6] gdb: introduce limited array lengths while printing values Maciej W. Rozycki
2023-02-10 14:19 ` [PATCH v4 1/6] GDB: Switch to using C++ standard integer type limits Maciej W. Rozycki
2023-02-10 21:13   ` Tom Tromey
2023-02-10 14:19 ` [PATCH v4 2/6] GDB: Ignore `max-value-size' setting with value history accesses Maciej W. Rozycki
2023-02-10 14:19 ` [PATCH v4 3/6] GDB: Fix the mess with value byte/bit range types Maciej W. Rozycki
2023-02-10 14:19 ` [PATCH v4 4/6] GDB: Only make data actually retrieved into value history available Maciej W. Rozycki
2023-02-10 21:16   ` Tom Tromey
2023-02-10 14:19 ` [PATCH v4 5/6] GDB/testsuite: Add `-nonl' option to `gdb_test' Maciej W. Rozycki
2023-02-10 14:19 ` [PATCH v4 6/6] GDB: Introduce limited array lengths while printing values Maciej W. Rozycki
2023-02-13 14:45   ` Simon Marchi
2023-02-14 19:20     ` Maciej W. Rozycki
2023-02-23 21:16       ` Maciej W. Rozycki
2023-02-10 21:17 ` [PATCH v4 0/6] gdb: introduce " Tom Tromey
2023-02-10 23:50   ` Maciej W. Rozycki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).