[v3] gdb: split array and string limiting options

Message ID alpine.DEB.2.20.2201042307430.22504@tpp.orcam.me.uk
State New
Headers show
Series
  • [v3] gdb: split array and string limiting options
Related show

Commit Message

Maciej W. Rozycki Jan. 4, 2022, 11:13 p.m.
From: Andrew Burgess <andrew.burgess@embecosm.com>


This commit splits the set/show print elements options into two.  We 
retain set/show print elements for controlling how many elements of an 
array we print, but a new set/show print characters is added which is 
used for controlling how many characters of a string are printed.

The motivation behind this change is to allow users a finer level of 
control over how data is printed, reflecting that, although strings can 
be thought of as arrays of characters, users often want to treat these 
two things differently.

The GDB changes are all pretty straight forward, just changing 
references to the old 'print_max' to reference the new 'print_max_chars' 
setting.

Likewise, the documentation is just updated to reference the new
setting where appropriate.

In the testsuite, most of the changes are places where I've either 
changed to using 'set print characters' instead of 'set print elements', 
or I set both together as the subsequent tests were a mix of arrays and 
strings.

There's new tests for Ada and Pascal, as the string printing code for 
these languages is different than the generic string printing code used 
by other languages.  Modula2 also has different string printing code, 
but (a) this is similar to Pascal, and (b) there are no existing modula2 
tests written in Modula2, so I'm not sure how I'd even test the Modula2 
string printing.

There's also a few places where GDB used 'show print elements', the 
message printed from this command is now different, so required a few 
updates too.

Co-Authored-By: Maciej W. Rozycki <macro@embecosm.com>
---
Changes from v2:

- place the new and the changed command at the right places each in NEWS.

Changes from v1:

- rename `print_smax' setting throughout to `print_max_chars', and
  likewise `show_print_smax' function to `show_print_max_chars',

- document the Python part in the manual,

- update comments for `print_max' and `print_max_chars' in
  `value_print_options',

- fix some typos.
---
 gdb/NEWS                                      |   16 ++++++
 gdb/ada-valprint.c                            |    4 -
 gdb/c-lang.c                                  |    4 -
 gdb/c-valprint.c                              |    4 -
 gdb/doc/gdb.texinfo                           |   36 +++++++++++---
 gdb/doc/python.texi                           |    5 ++
 gdb/language.h                                |    2 
 gdb/m2-lang.c                                 |    2 
 gdb/m2-valprint.c                             |    3 -
 gdb/p-lang.c                                  |    2 
 gdb/p-valprint.c                              |    7 +-
 gdb/printcmd.c                                |    8 +--
 gdb/python/py-value.c                         |    6 ++
 gdb/testsuite/gdb.ada/str_chars.exp           |   64 ++++++++++++++++++++++++++
 gdb/testsuite/gdb.ada/str_chars/foo.adb       |   26 ++++++++++
 gdb/testsuite/gdb.base/default.exp            |    4 -
 gdb/testsuite/gdb.base/examine-backward.exp   |    6 ++
 gdb/testsuite/gdb.base/options.exp            |    1 
 gdb/testsuite/gdb.base/printcmds.exp          |   28 +++++------
 gdb/testsuite/gdb.base/wchar.exp              |    6 +-
 gdb/testsuite/gdb.base/with.exp               |    2 
 gdb/testsuite/gdb.guile/scm-pretty-print.exp  |   12 ++--
 gdb/testsuite/gdb.pascal/str-chars.exp        |   48 +++++++++++++++++++
 gdb/testsuite/gdb.pascal/str-chars.pas        |   28 +++++++++++
 gdb/testsuite/gdb.python/py-format-string.exp |   11 ++--
 gdb/testsuite/gdb.python/py-prettyprint.exp   |    8 ++-
 gdb/testsuite/lib/gdb.exp                     |    2 
 gdb/tracepoint.c                              |    4 -
 gdb/valprint.c                                |   64 ++++++++++++++++++--------
 gdb/valprint.h                                |   10 ++--
 30 files changed, 340 insertions(+), 83 deletions(-)

Comments

Tom Tromey Jan. 14, 2022, 7:53 p.m. | #1
>>>>> "Maciej" == Maciej W Rozycki <macro@embecosm.com> writes:


Maciej> From: Andrew Burgess <andrew.burgess@embecosm.com>
Maciej> This commit splits the set/show print elements options into two.  We 
Maciej> retain set/show print elements for controlling how many elements of an 
Maciej> array we print, but a new set/show print characters is added which is 
Maciej> used for controlling how many characters of a string are printed.

Sorry, I missed that there had been a v2 and v3 when I was looking for
unreviewed patches today.

This version is ok.  Thank you.

Tom

Patch

Index: src/gdb/NEWS
===================================================================
--- src.orig/gdb/NEWS
+++ src/gdb/NEWS
@@ -64,6 +64,15 @@  set debug threads on|off
 show debug threads
   Print additional debug messages about thread creation and deletion.
 
+set print characters LIMIT
+show print characters
+print -characters LIMIT
+  This new setting is like 'set print elements', but controls how many
+  characters of a string are printed.  This functionality used to be
+  covered by 'set print elements', but is now a separate setting.
+  LIMIT can be set to 'unlimited' to print all characters of a string.
+  The default value for LIMIT is 200.
+
 * Changed commands
 
 maint packet
@@ -79,6 +88,13 @@  clone-inferior
   environment' or 'unset environment' commands are also copied to the new
   inferior.
 
+set print elements LIMIT
+show print elements
+print -elements LIMIT
+  This setting no longer affects how many characters of a string are
+  printed, instead the new 'set print characters' setting should be
+  used.
+
 * Python API
 
   ** New function gdb.add_history(), which takes a gdb.Value object
Index: src/gdb/ada-valprint.c
===================================================================
--- src.orig/gdb/ada-valprint.c
+++ src/gdb/ada-valprint.c
@@ -459,7 +459,7 @@  printstr (struct ui_file *stream, struct
       return;
     }
 
-  for (i = 0; i < length && things_printed < options->print_max; i += 1)
+  for (i = 0; i < length && things_printed < options->print_max_chars; i += 1)
     {
       /* Position of the character we are examining
 	 to see whether it is repeated.  */
@@ -700,7 +700,7 @@  ada_val_print_string (struct type *type,
       /* Look for a NULL char.  */
       for (temp_len = 0;
 	   (temp_len < len
-	    && temp_len < options->print_max
+	    && temp_len < options->print_max_chars
 	    && char_at (valaddr + offset_aligned,
 			temp_len, eltlen, byte_order) != 0);
 	   temp_len += 1);
Index: src/gdb/c-lang.c
===================================================================
--- src.orig/gdb/c-lang.c
+++ src/gdb/c-lang.c
@@ -185,8 +185,8 @@  language_defn::printchar (int c, struct
 /* Print the character string STRING, printing at most LENGTH
    characters.  LENGTH is -1 if the string is nul terminated.  Each
    character is WIDTH bytes long.  Printing stops early if the number
-   hits print_max; repeat counts are printed as appropriate.  Print
-   ellipses at the end if we had to stop before printing LENGTH
+   hits print_max_chars; repeat counts are printed as appropriate.
+   Print ellipses at the end if we had to stop before printing LENGTH
    characters, or if FORCE_ELLIPSES.  */
 
 void
Index: src/gdb/c-valprint.c
===================================================================
--- src.orig/gdb/c-valprint.c
+++ src/gdb/c-valprint.c
@@ -271,7 +271,7 @@  c_value_print_array (struct value *val,
 
 	      for (temp_len = 0;
 		   (temp_len < len
-		    && temp_len < options->print_max
+		    && temp_len < options->print_max_chars
 		    && extract_unsigned_integer (valaddr + temp_len * eltlen,
 						 eltlen, byte_order) != 0);
 		   ++temp_len)
@@ -280,7 +280,7 @@  c_value_print_array (struct value *val,
 	      /* Force LA_PRINT_STRING to print ellipses if
 		 we've printed the maximum characters and
 		 the next character is not \000.  */
-	      if (temp_len == options->print_max && temp_len < len)
+	      if (temp_len == options->print_max_chars && temp_len < len)
 		{
 		  ULONGEST ival
 		    = extract_unsigned_integer (valaddr + temp_len * eltlen,
Index: src/gdb/doc/gdb.texinfo
===================================================================
--- src.orig/gdb/doc/gdb.texinfo
+++ src/gdb/doc/gdb.texinfo
@@ -10010,10 +10010,15 @@  Related setting: @ref{set print array}.
 Set printing of array indexes.
 Related setting: @ref{set print array-indexes}.
 
+@item -characters @var{number-of-characters}|@code{unlimited}
+Set limit on string characters to print.  The value @code{unlimited}
+causes there to be no limit.  Related setting: @ref{set print
+characters}.
+
 @item -elements @var{number-of-elements}|@code{unlimited}
-Set limit on string chars or array elements to print.  The value
-@code{unlimited} causes there to be no limit.  Related setting:
-@ref{set print elements}.
+Set limit on array elements to print.  The value @code{unlimited}
+causes there to be no limit.  Related setting: @ref{set print
+elements}.
 
 @item -max-depth @var{depth}|@code{unlimited}
 Set the threshold after which nested structures are replaced with
@@ -11381,6 +11386,23 @@  Stop printing element indexes when displ
 Show whether the index of each element is printed when displaying
 arrays.
 
+@anchor{set print characters}
+@item set print characters @var{number-of-characters}
+@itemx set print characters unlimited
+@cindex number of string characters to print
+@cindex limit on number of printed string characters
+Set a limit on how many characters of a string @value{GDBN} will
+print.  If @value{GDBN} is printing a large string, it stops printing
+after it has printed the number of characters set by the @code{set
+print characters} command.
+When @value{GDBN} starts, this limit is set to 200.
+Setting @var{number-of-characters} to @code{unlimited} or zero means
+that the number of characters to print is unlimited.
+
+@item show print characters
+Display the number of characters of a large string that @value{GDBN}
+will print.
+
 @anchor{set print elements}
 @item set print elements @var{number-of-elements}
 @itemx set print elements unlimited
@@ -11389,13 +11411,13 @@  arrays.
 Set a limit on how many elements of an array @value{GDBN} will print.
 If @value{GDBN} is printing a large array, it stops printing after it has
 printed the number of elements set by the @code{set print elements} command.
-This limit also applies to the display of strings.
 When @value{GDBN} starts, this limit is set to 200.
 Setting @var{number-of-elements} to @code{unlimited} or zero means
 that the number of elements to print is unlimited.
 
 @item show print elements
-Display the number of elements of a large array that @value{GDBN} will print.
+Display the number of elements of a large array that @value{GDBN} will
+print.
 
 @anchor{set print frame-arguments}
 @item set print frame-arguments @var{value}
@@ -14892,7 +14914,7 @@  The optional @var{mods} changes the usua
 @code{s} requests that pointers to chars be handled as strings, in
 particular collecting the contents of the memory being pointed at, up
 to the first zero.  The upper bound is by default the value of the
-@code{print elements} variable; if @code{s} is followed by a decimal
+@code{print characters} variable; if @code{s} is followed by a decimal
 number, that is the upper bound instead.  So for instance
 @samp{collect/s25 mystr} collects as many as 25 characters at
 @samp{mystr}.
@@ -27939,7 +27961,7 @@  of a command.
 (gdb) alias -a show print elms = show print elements
 (gdb) set p elms 20
 (gdb) show p elms
-Limit on string chars or array elements to print is 200.
+Limit on array elements to print is 200.
 @end smallexample
 
 Note that if you are defining an alias of a @samp{set} command,
Index: src/gdb/doc/python.texi
===================================================================
--- src.orig/gdb/doc/python.texi
+++ src/gdb/doc/python.texi
@@ -1020,6 +1020,11 @@  the @emph{declared} type should be used.
 representation of a C@t{++} object, @code{False} if they shouldn't (see
 @code{set print static-members} in @ref{Print Settings}).
 
+@item max_characters
+Number of string characters to print, or @code{0} to print an unlimited
+number of characters (see @code{set print characters} in @ref{Print
+Settings}).
+
 @item max_elements
 Number of array elements to print, or @code{0} to print an unlimited
 number of elements (see @code{set print elements} in @ref{Print
Index: src/gdb/language.h
===================================================================
--- src.orig/gdb/language.h
+++ src/gdb/language.h
@@ -534,7 +534,7 @@  struct language_defn
 			  struct ui_file * stream) const;
 
 /* Print the character string STRING, printing at most LENGTH characters.
-   Printing stops early if the number hits print_max; repeat counts
+   Printing stops early if the number hits print_max_chars; repeat counts
    are printed as appropriate.  Print ellipses at the end if we
    had to stop before printing LENGTH characters, or if FORCE_ELLIPSES.  */
 
Index: src/gdb/m2-lang.c
===================================================================
--- src.orig/gdb/m2-lang.c
+++ src/gdb/m2-lang.c
@@ -169,7 +169,7 @@  m2_language::printstr (struct ui_file *s
       return;
     }
 
-  for (i = 0; i < length && things_printed < options->print_max; ++i)
+  for (i = 0; i < length && things_printed < options->print_max_chars; ++i)
     {
       /* Position of the character we are examining
 	 to see whether it is repeated.  */
Index: src/gdb/m2-valprint.c
===================================================================
--- src.orig/gdb/m2-valprint.c
+++ src/gdb/m2-valprint.c
@@ -332,7 +332,8 @@  m2_language::value_print_inner (struct v
 		  /* Look for a NULL char.  */
 		  for (temp_len = 0;
 		       (valaddr[temp_len]
-			&& temp_len < len && temp_len < options->print_max);
+			&& temp_len < len
+			&& temp_len < options->print_max_chars);
 		       temp_len++);
 		  len = temp_len;
 		}
Index: src/gdb/p-lang.c
===================================================================
--- src.orig/gdb/p-lang.c
+++ src/gdb/p-lang.c
@@ -253,7 +253,7 @@  pascal_language::printstr (struct ui_fil
       return;
     }
 
-  for (i = 0; i < length && things_printed < options->print_max; ++i)
+  for (i = 0; i < length && things_printed < options->print_max_chars; ++i)
     {
       /* Position of the character we are examining
 	 to see whether it is repeated.  */
Index: src/gdb/p-valprint.c
===================================================================
--- src.orig/gdb/p-valprint.c
+++ src/gdb/p-valprint.c
@@ -109,9 +109,10 @@  pascal_language::value_print_inner (stru
 
 		    /* Look for a NULL char.  */
 		    for (temp_len = 0;
-			 extract_unsigned_integer (valaddr + temp_len * eltlen,
-						   eltlen, byte_order)
-			   && temp_len < len && temp_len < options->print_max;
+			 (extract_unsigned_integer
+			    (valaddr + temp_len * eltlen, eltlen, byte_order)
+			  && temp_len < len
+			  && temp_len < options->print_max_chars);
 			 temp_len++);
 		    len = temp_len;
 		  }
Index: src/gdb/printcmd.c
===================================================================
--- src.orig/gdb/printcmd.c
+++ src/gdb/printcmd.c
@@ -968,11 +968,11 @@  find_string_backward (struct gdbarch *gd
 	  int offset = (chars_to_read - i - 1) * char_size;
 
 	  if (integer_is_zero (&buffer[offset], char_size)
-	      || chars_counted == options->print_max)
+	      || chars_counted == options->print_max_chars)
 	    {
-	      /* Found '\0' or reached print_max.  As OFFSET is the offset to
-		 '\0', we add CHAR_SIZE to return the start address of
-		 a string.  */
+	      /* Found '\0' or reached print_max_chars.  As OFFSET
+		 is the offset to '\0', we add CHAR_SIZE to return
+		 the start address of a string.  */
 	      --count;
 	      string_start_addr = addr + offset + char_size;
 	      chars_counted = 0;
Index: src/gdb/python/py-value.c
===================================================================
--- src.orig/gdb/python/py-value.c
+++ src/gdb/python/py-value.c
@@ -641,6 +641,7 @@  valpy_format_string (PyObject *self, PyO
       "actual_objects",		/* See set print object on|off.  */
       "static_members",		/* See set print static-members on|off.  */
       /* C non-bool options.  */
+      "max_characters", 	/* See set print characters N.  */
       "max_elements", 		/* See set print elements N.  */
       "max_depth",		/* See set print max-depth N.  */
       "repeat_threshold",	/* See set print repeats.  */
@@ -686,7 +687,7 @@  valpy_format_string (PyObject *self, PyO
   char *format = NULL;
   if (!gdb_PyArg_ParseTupleAndKeywords (args,
 					kw,
-					"|O!O!O!O!O!O!O!O!O!O!IIIs",
+					"|O!O!O!O!O!O!O!O!O!O!IIIIs",
 					keywords,
 					&PyBool_Type, &raw_obj,
 					&PyBool_Type, &pretty_arrays_obj,
@@ -698,6 +699,7 @@  valpy_format_string (PyObject *self, PyO
 					&PyBool_Type, &deref_refs_obj,
 					&PyBool_Type, &actual_objects_obj,
 					&PyBool_Type, &static_members_obj,
+					&opts.print_max_chars,
 					&opts.print_max,
 					&opts.max_depth,
 					&opts.repeat_count_threshold,
@@ -731,6 +733,8 @@  valpy_format_string (PyObject *self, PyO
      unlimited, and 0 is a valid choice.  */
   if (opts.print_max == 0)
     opts.print_max = UINT_MAX;
+  if (opts.print_max_chars == 0)
+    opts.print_max_chars = UINT_MAX;
   if (opts.repeat_count_threshold == 0)
     opts.repeat_count_threshold = UINT_MAX;
 
Index: src/gdb/testsuite/gdb.ada/str_chars.exp
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.ada/str_chars.exp
@@ -0,0 +1,64 @@ 
+# Copyright 2021 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 'set print characters' setting works for Ada strings.
+
+load_lib "ada.exp"
+
+if { [skip_ada_tests] } { return -1 }
+
+standard_ada_testfile foo
+
+if {[gdb_compile_ada "${srcfile}" "${binfile}" executable [list debug ]] != "" } {
+  return -1
+}
+
+clean_restart ${testfile}
+
+set bp_location [gdb_get_line_number "STOP" ${testdir}/foo.adb]
+if ![runto "foo.adb:$bp_location" ] then {
+  return -1
+}
+
+gdb_test "print Arg" \
+    " = \"abcdefghijklmnopqrstuvwxyz\"" \
+    "print with default settings"
+
+gdb_test_no_output "set print characters 26"
+gdb_test "print Arg" \
+    " = \"abcdefghijklmnopqrstuvwxyz\"" \
+    "print with character limit of 26"
+
+gdb_test "print -characters 11 -- Arg" \
+    " = \"abcdefghijk\"\\.\\.\\." \
+    "print with character limit of 11"
+
+gdb_test_no_output "set print characters 10"
+gdb_test "print Arg" \
+    " = \"abcdefghij\"\\.\\.\\." \
+    "print with character limit of 10"
+
+gdb_test_no_output "set print characters unlimited"
+gdb_test "print Arg" \
+    " = \"abcdefghijklmnopqrstuvwxyz\"" \
+    "print with unlimited character limit"
+
+# The 'set print elements' used to control printing of characters in a
+# string, before we created 'set print characters'.  This test ensures
+# that 'set print elements' doens't effect string printing any more.
+gdb_test_no_output "set print elements 10"
+gdb_test "print Arg" \
+    " = \"abcdefghijklmnopqrstuvwxyz\"" \
+    "print with unlimited character limit, but lower element limit"
Index: src/gdb/testsuite/gdb.ada/str_chars/foo.adb
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.ada/str_chars/foo.adb
@@ -0,0 +1,26 @@ 
+--  Copyright 2021 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/>.
+
+procedure Foo is
+
+   procedure Blah (Arg : String) is
+   begin
+     null; -- STOP
+   end;
+
+begin
+
+   Blah ("abcdefghijklmnopqrstuvwxyz");
+end Foo;
Index: src/gdb/testsuite/gdb.base/default.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/default.exp
+++ src/gdb/testsuite/gdb.base/default.exp
@@ -667,7 +667,7 @@  gdb_test "show print asm-demangle" "Dema
 #test show print demangle
 gdb_test "show print demangle" "Demangling of encoded C\[+\]+/ObjC names when displaying symbols is on."
 #test show print elements
-gdb_test "show print elements" "Limit on string chars or array elements to print is 200."
+gdb_test "show print elements" "Limit on array elements to print is 200."
 #test show print object
 gdb_test "show print object" "Printing of object's derived type based on vtable info is on."
 #test show print pretty
@@ -702,7 +702,7 @@  gdb_test "show write" "Writing into exec
 set show_confirm_seen 0
 set show_prompt_seen 0
 gdb_test_multiple "show" "show" {
-    -re "confirm:  *Whether to confirm potentially dangerous operations is on.(\[^\r\n\]*\[\r\n\])+history filename:  *The filename in which to record the command history is (\[^\r\n\]*\[\r\n\])+history save:  *Saving of the history record on exit is on.(\[^\r\n\]*\[\r\n\])+history size:  *The size of the command history is(\[^\r\n\]*\[\r\n\])+listsize:  *Number of source lines gdb will list by default is 10(\[^\r\n]*\[\r\n\])+print elements:  *Limit on string chars or array elements to print is 200." {
+    -re "confirm:  *Whether to confirm potentially dangerous operations is on.(\[^\r\n\]*\[\r\n\])+history filename:  *The filename in which to record the command history is (\[^\r\n\]*\[\r\n\])+history save:  *Saving of the history record on exit is on.(\[^\r\n\]*\[\r\n\])+history size:  *The size of the command history is(\[^\r\n\]*\[\r\n\])+listsize:  *Number of source lines gdb will list by default is 10(\[^\r\n]*\[\r\n\])+print elements:  *Limit on array elements to print is 200." {
 	verbose "Confirm dislayed"
 	set show_confirm_seen 1
 	exp_continue
Index: src/gdb/testsuite/gdb.base/examine-backward.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/examine-backward.exp
+++ src/gdb/testsuite/gdb.base/examine-backward.exp
@@ -56,6 +56,7 @@  with_test_prefix "memory page boundary"
     set boundary [get_first_mapped_address]
     if {![is_address_zero_readable] && $boundary != 0} {
         gdb_test_no_output "set print elements 0"
+        gdb_test_no_output "set print characters 0"
         gdb_test_sequence "x/3s ${boundary}" "take 3 strings forward" {
             "0x"
             "0x"
@@ -145,6 +146,7 @@  gdb_test_no_output "set charset ASCII"
 
 with_test_prefix "char-width=1, print-max=20" {
     gdb_test_no_output "set print elements 20"
+    gdb_test_no_output "set print characters 20"
     gdb_test_sequence "x/6s &TestStrings" "take 6 strings forward" {
         "\"ABCDEFGHIJKLMNOPQRST\"\.\.\."
         "\"UVWXYZ\""
@@ -187,6 +189,7 @@  with_test_prefix "char-width=1, print-ma
 
 with_test_prefix "char-width=2, print-max=20" {
     gdb_test_no_output "set print elements 20"
+    gdb_test_no_output "set print characters 20"
     gdb_test_sequence "x/6sh &TestStringsH" "take 6 strings forward" {
         "u\"ABCDEFGHIJKLMNOPQRST\"\.\.\."
         "u\"UVWXYZ\""
@@ -229,6 +232,7 @@  with_test_prefix "char-width=2, print-ma
 
 with_test_prefix "char-width=4, print-max=20" {
     gdb_test_no_output "set print elements 20"
+    gdb_test_no_output "set print characters 20"
     gdb_test_sequence "x/6sw &TestStringsW" "take 6 strings forward" {
         "U\"ABCDEFGHIJKLMNOPQRST\"\.\.\."
         "U\"UVWXYZ\""
@@ -271,6 +275,7 @@  with_test_prefix "char-width=4, print-ma
 
 with_test_prefix "char-width=2, print-max=0" {
     gdb_test_no_output "set print elements 0"
+    gdb_test_no_output "set print characters 0"
     gdb_test_sequence "x/6sh &TestStringsH" "take 6 strings forward" {
         "u\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\""
         "u\"\""
@@ -314,6 +319,7 @@  with_test_prefix "char-width=2, print-ma
 
 with_test_prefix "char-width=1, print-max=4" {
     gdb_test_no_output "set print elements 4"
+    gdb_test_no_output "set print characters 4"
     gdb_test_sequence "x/9s &TestStrings" "take 9 strings forward" {
         "\"ABCD\"\.\.\."
         "\"EFGH\"\.\.\."
Index: src/gdb/testsuite/gdb.base/options.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/options.exp
+++ src/gdb/testsuite/gdb.base/options.exp
@@ -165,6 +165,7 @@  proc_with_prefix test-print {{prefix ""}
 	"-address"
 	"-array"
 	"-array-indexes"
+	"-characters"
 	"-elements"
 	"-max-depth"
 	"-memory-tag-violations"
Index: src/gdb/testsuite/gdb.base/printcmds.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/printcmds.exp
+++ src/gdb/testsuite/gdb.base/printcmds.exp
@@ -438,7 +438,7 @@  proc test_print_repeats_10 {} {
     global gdb_prompt decimal
 
     for { set x 1 } { $x <= 16 } { incr x } {
-	gdb_test_no_output "set print elements $x" "elements $x repeats"
+	gdb_test_no_output "set print characters $x" "set print characters $x repeats"
 	for { set e 1 } { $e <= 16 } {incr e } {
 	    set v [expr $e - 1]
 	    set command "p &ctable2\[${v}*16\]"
@@ -478,7 +478,7 @@  proc test_print_repeats_10 {} {
 		set xstr "${xstr}\[.\]\[.\]\[.\]"
 	    }
 	    set string " = \[(\]unsigned char \[*\]\[)\] <ctable2(\\+$decimal)?> ${a}${xstr}"
-	    gdb_test "$command" "$string" "$command with print elements set to $x"
+	    gdb_test "$command" "$string" "$command with print characters set to $x"
 	}
     }
 }
@@ -503,26 +503,26 @@  proc test_print_strings {} {
 
     # Test that setting print elements unlimited doesn't completely suppress
     # printing; this was a bug in older gdb's.
-    gdb_test_no_output "set print elements 0"
+    gdb_test_no_output "set print characters 0"
     gdb_test "p teststring" \
-	" = (.unsigned char .. )?\"teststring contents\"" "p teststring with elements set to 0"
-    gdb_test_no_output "set print elements 1"
+	" = (.unsigned char .. )?\"teststring contents\"" "p teststring with characters set to 0"
+    gdb_test_no_output "set print characters 1"
     gdb_test "p teststring" \
-	" = (.unsigned char .. )?\"t\"\\.\\.\\." "p teststring with elements set to 1"
-    gdb_test_no_output "set print elements 5"
+	" = (.unsigned char .. )?\"t\"\\.\\.\\." "p teststring with characters set to 1"
+    gdb_test_no_output "set print characters 5"
     gdb_test "p teststring" \
-	" = (.unsigned char .. )?\"tests\"\\.\\.\\." "p teststring with elements set to 5"
-    gdb_test_no_output "set print elements 19"
+	" = (.unsigned char .. )?\"tests\"\\.\\.\\." "p teststring with characters set to 5"
+    gdb_test_no_output "set print characters 19"
     gdb_test "p teststring" \
-	" = (.unsigned char .. )?\"teststring contents\"" "p teststring with elements set to 19"
-    gdb_test_no_output "set print elements 20"
+	" = (.unsigned char .. )?\"teststring contents\"" "p teststring with characters set to 19"
+    gdb_test_no_output "set print characters 20"
     gdb_test "p teststring" \
-	" = (.unsigned char .. )?\"teststring contents\"" "p teststring with elements set to 20"
+	" = (.unsigned char .. )?\"teststring contents\"" "p teststring with characters set to 20"
 
     gdb_test "print teststring2" \
 	" = \\(charptr\\) \"more contents\""
 
-    gdb_test_no_output "set print elements 8"
+    gdb_test_no_output "set print characters 8"
 
     # Set the target-charset to ASCII, because the output varies from
     # different charset.
@@ -693,7 +693,7 @@  proc test_print_char_arrays {} {
 proc test_print_string_constants {} {
     global gdb_prompt
 
-    gdb_test_no_output "set print elements 50"
+    gdb_test_no_output "set print characters 50"
 
     if [target_info exists gdb,cannot_call_functions] {
 	unsupported "this target can not call functions"
Index: src/gdb/testsuite/gdb.base/wchar.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/wchar.exp
+++ src/gdb/testsuite/gdb.base/wchar.exp
@@ -62,13 +62,13 @@  gdb_test_no_output "set print null on"
 gdb_test "print repeat" "= L\"A\", '$cent' <repeats 21 times>, \"B\"" \
     "print repeat (print null on)"
 
-gdb_test_no_output "set print elements 3"
+gdb_test_no_output "set print characters 3"
 
 gdb_test "print repeat" "= L\"A$cent$cent\"\.\.\." \
-    "print repeat (print elements 3)"
+    "print repeat (print characters 3)"
 
 gdb_test "print repeat_p" "= $hex L\"A$cent$cent\"\.\.\." \
-    "print repeat_p (print elements 3)"
+    "print repeat_p (print characters 3)"
 
 # From PR cli/14977, but here because it requires wchar_t.
 gdb_test "printf \"%ls\\n\", 0" "\\(null\\)"
Index: src/gdb/testsuite/gdb.base/with.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/with.exp
+++ src/gdb/testsuite/gdb.base/with.exp
@@ -252,7 +252,7 @@  with_test_prefix "errors" {
     gdb_test "with print elements 1 -- unknowncommand" \
 	"Undefined command: \"unknowncommand\"\\.  Try \"help\"\\."
     gdb_test "show print elements" \
-	"Limit on string chars or array elements to print is 200\\."
+	"Limit on array elements to print is 200\\."
 }
 
 # Check completion.
Index: src/gdb/testsuite/gdb.guile/scm-pretty-print.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.guile/scm-pretty-print.exp
+++ src/gdb/testsuite/gdb.guile/scm-pretty-print.exp
@@ -76,13 +76,15 @@  proc run_lang_tests {exefile lang} {
 		" = \{.*<Vbase1> = pp class name: Vbase1.*<Vbase2> = \{.*<VirtualTest> = pp value variable is: 1,.*members of Vbase2:.*_vptr.Vbase2 = $hex.*<Vbase3> = \{.*members of Vbase3.*members of Derived:.*value = 2.*"
 	    gdb_test "print ns " "\"embedded\\\\000null\\\\000string\"" \
 		"print ns with 200 elements"
-	    gdb_test_no_output "set print elements 3" ""
+	    gdb_test_no_output "set print characters 3" ""
 	    gdb_test "print ns" "emb\.\.\.." \
-		"print ns with 3 elements"
-	    gdb_test_no_output "set print elements 10" ""
+		"print ns with 3 characters"
+	    gdb_test "print -characters 4 -- ns" "embe\.\.\.." \
+		"print ns with 4 characters"
+	    gdb_test_no_output "set print characters 10" ""
 	    gdb_test "print ns" "embedded\\\\000n\.\.\.." \
-		"print ns with 10 elements"
-	    gdb_test_no_output "set print elements 200" ""
+		"print ns with 10 characters"
+	    gdb_test_no_output "set print characters 200" ""
 	}
 
 	if { ![is_address_zero_readable] } {
Index: src/gdb/testsuite/gdb.pascal/str-chars.exp
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.pascal/str-chars.exp
@@ -0,0 +1,48 @@ 
+# Copyright 2021 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 "pascal.exp"
+
+standard_testfile .pas
+
+if {[gdb_compile_pascal "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug ]] != "" } {
+  return -1
+}
+
+clean_restart ${testfile}
+gdb_breakpoint ${srcfile}:[gdb_get_line_number "set breakpoint 1 here"]
+
+# Verify that "start" lands inside the right procedure.
+if { [gdb_start_cmd] < 0 } {
+    untested start
+    return -1
+}
+
+gdb_continue_to_breakpoint "continue to breakpoint"
+
+gdb_test "print message" " = 'abcdefghijklmnopqrstuvwxyz'" \
+    "print message with the default settings"
+
+gdb_test_no_output "set print elements 10"
+gdb_test "print message" " = 'abcdefghijklmnopqrstuvwxyz'" \
+    "print message with 'print elements' set to 10"
+
+gdb_test_no_output "set print characters 10"
+gdb_test "print message" " = 'abcdefghij'\\.\\.\\." \
+    "print message with 'print characters' set to 10"
+
+gdb_test_no_output "set print characters unlimited"
+gdb_test "print message" " = 'abcdefghijklmnopqrstuvwxyz'" \
+    "print message with 'print characters' set to unlimited"
Index: src/gdb/testsuite/gdb.pascal/str-chars.pas
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.pascal/str-chars.pas
@@ -0,0 +1,28 @@ 
+{
+ Copyright 2021 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/>.
+}
+
+program str_char;
+
+var
+   message : string;
+
+begin
+
+   message := 'abcdefghijklmnopqrstuvwxyz';
+   writeln (message)	{ set breakpoint 1 here }
+
+end.
Index: src/gdb/testsuite/gdb.python/py-format-string.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.python/py-format-string.exp
+++ src/gdb/testsuite/gdb.python/py-format-string.exp
@@ -638,7 +638,7 @@  proc_with_prefix test_max_elements {} {
 
   # 200 is the default maximum number of elements, so setting it should
   # not change the output.
-  set opts "max_elements=200"
+  set opts "max_elements=200, max_characters=200"
   with_test_prefix $opts {
     check_format_string "a_point_t" $opts
     check_format_string "a_point_t_pointer" $opts
@@ -659,7 +659,7 @@  proc_with_prefix test_max_elements {} {
     }
   }
 
-  set opts "max_elements=3"
+  set opts "max_elements=3, max_characters=3"
   with_test_prefix $opts {
     check_format_string "a_point_t" $opts
     check_format_string "a_point_t_pointer" $opts
@@ -689,7 +689,7 @@  proc_with_prefix test_max_elements {} {
 
   # Both 1,000 (we don't have that many elements) and 0 (unlimited) should
   # mean no truncation.
-  foreach opts { "max_elements=1000" "max_elements=0" } {
+  foreach opts { "max_elements=1000, max_characters=1000" "max_elements=0, max_characters=0" } {
     with_test_prefix $opts {
       check_format_string "a_point_t" $opts
       check_format_string "a_point_t_pointer" $opts
@@ -712,13 +712,16 @@  proc_with_prefix test_max_elements {} {
     }
   }
 
-  with_temp_option "set print elements 4" "set print elements 200" {
+  with_temp_option "set print characters 4" "set print characters 200" {
     check_format_string "a_string" "" \
       "${default_pointer_regexp} \"hell\"..."
     check_format_string "a_binary_string" "" \
       "${default_pointer_regexp} \"hell\"..."
     check_format_string "a_binary_string_array" "" \
       "\"hell\"..."
+  }
+
+  with_temp_option "set print elements 4" "set print elements 200" {
     check_format_string "an_array_with_repetition" "" \
       "\\{1, 3 <repeats 12 times>...\\}"
   }
Index: src/gdb/testsuite/gdb.python/py-prettyprint.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.python/py-prettyprint.exp
+++ src/gdb/testsuite/gdb.python/py-prettyprint.exp
@@ -80,13 +80,15 @@  proc run_lang_tests {exefile lang} {
 	    " = \{.*<Vbase1> = pp class name: Vbase1.*<Vbase2> = \{.*<VirtualTest> = pp value variable is: 1,.*members of Vbase2:.*_vptr.Vbase2 = $hex.*<Vbase3> = \{.*members of Vbase3.*members of Derived:.*value = 2.*"
 	gdb_test "print ns " "\"embedded\\\\000null\\\\000string\"" \
 	    "print ns with default element limit"
-	gdb_test_no_output "set print elements 3"
+	gdb_test_no_output "set print characters 3"
 	gdb_test "print ns" "emb\.\.\.." \
 	    "print ns with element limit of 3"
-	gdb_test_no_output "set print elements 10"
+	gdb_test "print -characters 4 -- ns" "embe\.\.\.." \
+	    "print ns with element limit of 4"
+	gdb_test_no_output "set print characters 10"
 	gdb_test "print ns" "embedded\\\\000n\.\.\.." \
 	    "print ns with element limit of 10"
-	gdb_test_no_output "set print elements 200"
+	gdb_test_no_output "set print characters 200"
     }
 
     if { ![is_address_zero_readable] } {
Index: src/gdb/testsuite/lib/gdb.exp
===================================================================
--- src.orig/gdb/testsuite/lib/gdb.exp
+++ src/gdb/testsuite/lib/gdb.exp
@@ -6442,7 +6442,7 @@  gdb_caching_proc gdb_has_argv0 {
 	set old_elements "200"
 	set test "show print elements"
 	gdb_test_multiple $test $test {
-	    -re "Limit on string chars or array elements to print is (\[^\r\n\]+)\\.\r\n$gdb_prompt $" {
+	    -re "Limit on array elements to print is (\[^\r\n\]+)\\.\r\n$gdb_prompt $" {
 		set old_elements $expect_out(1,string)
 	    }
 	}
Index: src/gdb/tracepoint.c
===================================================================
--- src.orig/gdb/tracepoint.c
+++ src/gdb/tracepoint.c
@@ -545,9 +545,9 @@  decode_agent_options (const char *exp, i
       if (target_supports_string_tracing ())
 	{
 	  /* Allow an optional decimal number giving an explicit maximum
-	     string length, defaulting it to the "print elements" value;
+	     string length, defaulting it to the "print characters" value;
 	     so "collect/s80 mystr" gets at most 80 bytes of string.  */
-	  *trace_string = opts.print_max;
+	  *trace_string = opts.print_max_chars;
 	  exp++;
 	  if (*exp >= '0' && *exp <= '9')
 	    *trace_string = atoi (exp);
Index: src/gdb/valprint.c
===================================================================
--- src.orig/gdb/valprint.c
+++ src/gdb/valprint.c
@@ -97,8 +97,11 @@  static void val_print_type_code_flags (s
 				       int embedded_offset,
 				       struct ui_file *stream);
 
-#define PRINT_MAX_DEFAULT 200	/* Start print_max off at this value.  */
-#define PRINT_MAX_DEPTH_DEFAULT 20	/* Start print_max_depth off at this value. */
+/* Start print_max and print_max_chars at this value.  */
+#define PRINT_MAX_DEFAULT 200
+
+/* Start print_max_depth at this value. */
+#define PRINT_MAX_DEPTH_DEFAULT 20
 
 struct value_print_options user_print_options =
 {
@@ -110,6 +113,7 @@  struct value_print_options user_print_op
   1,				/* addressprint */
   0,				/* objectprint */
   PRINT_MAX_DEFAULT,		/* print_max */
+  PRINT_MAX_DEFAULT,		/* print_max_chars */
   10,				/* repeat_count_threshold */
   0,				/* output_format */
   0,				/* format */
@@ -152,13 +156,25 @@  get_formatted_print_options (struct valu
   opts->format = format;
 }
 
+/* Implement 'show print elements'.  */
+
 static void
 show_print_max (struct ui_file *file, int from_tty,
 		struct cmd_list_element *c, const char *value)
 {
   fprintf_filtered (file,
-		    _("Limit on string chars or array "
-		      "elements to print is %s.\n"),
+		    _("Limit on array elements to print is %s.\n"),
+		    value);
+}
+
+/* Implement 'show print characters'.  */
+
+static void
+show_print_max_chars (struct ui_file *file, int from_tty,
+		      struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file,
+		    _("Limit on string characters to print is %s.\n"),
 		    value);
 }
 
@@ -2601,9 +2617,9 @@  print_converted_chars_to_obstack (struct
 /* Print the character string STRING, printing at most LENGTH
    characters.  LENGTH is -1 if the string is nul terminated.  TYPE is
    the type of each character.  OPTIONS holds the printing options;
-   printing stops early if the number hits print_max; repeat counts
-   are printed as appropriate.  Print ellipses at the end if we had to
-   stop before printing LENGTH characters, or if FORCE_ELLIPSES.
+   printing stops early if the number hits print_max_chars; repeat
+   counts are printed as appropriate.  Print ellipses at the end if we
+   had to stop before printing LENGTH characters, or if FORCE_ELLIPSES.
    QUOTE_CHAR is the character to print at each end of the string.  If
    C_STYLE_TERMINATOR is true, and the last character is 0, then it is
    omitted.  */
@@ -2657,7 +2673,7 @@  generic_printstr (struct ui_file *stream
   /* Convert characters until the string is over or the maximum
      number of printed characters has been reached.  */
   i = 0;
-  while (i < options->print_max)
+  while (i < options->print_max_chars)
     {
       int r;
 
@@ -2709,7 +2725,7 @@  generic_printstr (struct ui_file *stream
 /* Print a string from the inferior, starting at ADDR and printing up to LEN
    characters, of WIDTH bytes a piece, to STREAM.  If LEN is -1, printing
    stops at the first null byte, otherwise printing proceeds (including null
-   bytes) until either print_max or LEN characters have been printed,
+   bytes) until either print_max_chars or LEN characters have been printed,
    whichever is smaller.  ENCODING is the name of the string's
    encoding.  It can be NULL, in which case the target encoding is
    assumed.  */
@@ -2731,15 +2747,16 @@  val_print_string (struct type *elttype,
   int width = TYPE_LENGTH (elttype);
 
   /* First we need to figure out the limit on the number of characters we are
-     going to attempt to fetch and print.  This is actually pretty simple.  If
-     LEN >= zero, then the limit is the minimum of LEN and print_max.  If
-     LEN is -1, then the limit is print_max.  This is true regardless of
-     whether print_max is zero, UINT_MAX (unlimited), or something in between,
-     because finding the null byte (or available memory) is what actually
-     limits the fetch.  */
+     going to attempt to fetch and print.  This is actually pretty simple.
+     If LEN >= zero, then the limit is the minimum of LEN and print_max_chars.
+     If LEN is -1, then the limit is print_max_chars.  This is true regardless
+     of whether print_max_chars is zero, UINT_MAX (unlimited), or something in
+     between, because finding the null byte (or available memory) is what
+     actually limits the fetch.  */
 
-  fetchlimit = (len == -1 ? options->print_max : std::min ((unsigned) len,
-							   options->print_max));
+  fetchlimit = (len == -1
+		? options->print_max_chars
+		: std::min ((unsigned) len, options->print_max_chars));
 
   err = read_string (addr, len, width, fetchlimit, byte_order,
 		     &buffer, &bytes_read);
@@ -3020,8 +3037,17 @@  static const gdb::option::option_def val
     "elements",
     [] (value_print_options *opt) { return &opt->print_max; },
     show_print_max, /* show_cmd_cb */
-    N_("Set limit on string chars or array elements to print."),
-    N_("Show limit on string chars or array elements to print."),
+    N_("Set limit on array elements to print."),
+    N_("Show limit on array elements to print."),
+    N_("\"unlimited\" causes there to be no limit."),
+  },
+
+  uinteger_option_def {
+    "characters",
+    [] (value_print_options *opt) { return &opt->print_max_chars; },
+    show_print_max_chars, /* show_cmd_cb */
+    N_("Set limit on string chars to print."),
+    N_("Show limit on string chars to print."),
     N_("\"unlimited\" causes there to be no limit."),
   },
 
Index: src/gdb/valprint.h
===================================================================
--- src.orig/gdb/valprint.h
+++ src/gdb/valprint.h
@@ -48,12 +48,14 @@  struct value_print_options
      in its vtables.  */
   bool objectprint;
 
-  /* Maximum number of chars to print for a string pointer value or vector
-     contents, or UINT_MAX for no limit.  Note that "set print elements 0"
-     stores UINT_MAX in print_max, which displays in a show command as
-     "unlimited".  */
+  /* Maximum number of elements to print for vector contents, or UINT_MAX
+     for no limit.  Note that "set print elements 0" stores UINT_MAX in
+     print_max, which displays in a show command as "unlimited".  */
   unsigned int print_max;
 
+  /* Maximum number of string chars to print for a string pointer value.  */
+  unsigned int print_max_chars;
+
   /* Print repeat counts if there are more than this many repetitions
      of an element in an array.  */
   unsigned int repeat_count_threshold;