Index: src/gdb/testsuite/gdb.ada/str_chars.exp
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.ada/str_chars.exp
@@ -0,0 +1,70 @@
+# Copyright 2022 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' command used to control printing of characters
+# in a string, before we created 'set print characters'.  This test makes
+# sure that 'set print elements' doens't effect string printing any more.
+gdb_test_no_output "set print elements 12"
+gdb_test "print Arg" \
+    " = \"abcdefghijklmnopqrstuvwxyz\"" \
+    "print with unlimited character limit, but lower element limit"
+
+# Except when 'set print characters elements' has been used.
+gdb_test_no_output "set print characters elements"
+gdb_test "print Arg" \
+    " = \"abcdefghijkl\"\\.\\.\\." \
+    "print with character limit of elements"
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 2022 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/printcmds.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/printcmds.exp
+++ src/gdb/testsuite/gdb.base/printcmds.exp
@@ -451,11 +451,11 @@ proc test_print_all_chars {} {
 # Test interaction of the number of print elements to print and the
 # repeat count, set to the default of 10.
 
-proc test_print_repeats_10 {} {
+proc test_print_repeats_10_one { setting } {
     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 $setting $x" "$setting $x repeats"
 	for { set e 1 } { $e <= 16 } {incr e } {
 	    set v [expr $e - 1]
 	    set command "p &ctable2\[${v}*16\]"
@@ -495,11 +495,18 @@ 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 $setting set to $x"
 	}
     }
 }
 
+proc test_print_repeats_10 {} {
+    foreach_with_prefix setting { "elements" "characters" } {
+	test_print_repeats_10_one $setting
+    }
+    gdb_test_no_output "set print characters elements"
+}
+
 # This tests whether GDB uses the correct element content offsets
 # (relative to the complete `some_struct' value) when counting value
 # repetitions.
@@ -512,7 +519,7 @@ proc test_print_repeats_embedded_array {
 	"correct element repeats in array embedded at offset > 0"
 }
 
-proc test_print_strings {} {
+proc test_print_strings_one { setting } {
     global gdb_prompt decimal
 
     # We accept "(unsigned char *) " before the string.  char vs. unsigned char
@@ -520,35 +527,35 @@ 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 $setting 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 $setting set to 0"
+    gdb_test_no_output "set print $setting 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 $setting set to 1"
+    gdb_test_no_output "set print $setting 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 $setting set to 5"
+    gdb_test_no_output "set print $setting 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 $setting set to 19"
+    gdb_test_no_output "set print $setting 20"
     gdb_test "p teststring" \
-	" = (.unsigned char .. )?\"teststring contents\"" "p teststring with elements set to 20"
+	" = (.unsigned char .. )?\"teststring contents\"" "p teststring with $setting set to 20"
 
-    gdb_test "p -elements 1 -- teststring" \
+    gdb_test "p -$setting 1 -- teststring" \
 	" = (.unsigned char .. )?\"t\"\\.\\.\\."
-    gdb_test "p -elements 5 -- teststring" \
+    gdb_test "p -$setting 5 -- teststring" \
 	" = (.unsigned char .. )?\"tests\"\\.\\.\\."
-    gdb_test "p -elements 19 -- teststring" \
+    gdb_test "p -$setting 19 -- teststring" \
 	" = (.unsigned char .. )?\"teststring contents\""
-    gdb_test "p -elements 20 -- teststring" \
+    gdb_test "p -$setting 20 -- teststring" \
 	" = (.unsigned char .. )?\"teststring contents\""
 
     gdb_test "print teststring2" \
 	" = \\(charptr\\) \"more contents\""
 
-    gdb_test_no_output "set print elements 8"
+    gdb_test_no_output "set print $setting 8"
 
     # Set the target-charset to ASCII, because the output varies from
     # different charset.
@@ -620,6 +627,26 @@ proc test_print_strings {} {
 	gdb_test "p &ctable1\[31*8\]" \
 	    " = \\(unsigned char \\*\\) <ctable1\\+$decimal> \"\\\\370\\\\371\\\\372\\\\373\\\\374\\\\375\\\\376\\\\377\"..."
     }
+
+    gdb_test_no_output "set print $setting unlimited"
+}
+
+proc test_print_strings {} {
+
+    foreach_with_prefix setting { "elements" "characters" } {
+	test_print_strings_one $setting
+    }
+
+    gdb_test "p -elements 8 -- teststring" \
+	" = (.unsigned char .. )?\"teststring contents\""
+    gdb_test "p -characters 8 -- teststring" \
+	" = (.unsigned char .. )?\"teststri\"\\.\\.\\."
+    gdb_test "p -elements 8 -characters elements -- teststring" \
+	" = (.unsigned char .. )?\"teststri\"\\.\\.\\."
+
+    with_test_prefix strings {
+	gdb_test_no_output "set print characters elements"
+    }
 }
 
 proc test_print_int_arrays {} {
Index: src/gdb/testsuite/gdb.base/setshow.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/setshow.exp
+++ src/gdb/testsuite/gdb.base/setshow.exp
@@ -374,6 +374,27 @@ proc_with_prefix test_setshow_listsize {
     gdb_test "show listsize" "Number of source lines gdb will list by default is 100..*" "show listsize (100)"
 }
 
+proc_with_prefix test_setshow_print_characters {} {
+    clean_restart
+
+    gdb_test "p \$_gdb_setting(\"print characters\")" " = void" \
+	"_gdb_setting print characters default"
+    gdb_test "p \$_gdb_setting_str(\"print characters\")" " = \"elements\"" \
+	"_gdb_setting_str print characters default"
+
+    gdb_test_no_output "set print characters unlimited"
+    gdb_test "p \$_gdb_setting(\"print characters\")" " = 0" \
+	"_gdb_setting print characters unlimited"
+    gdb_test "p \$_gdb_setting_str(\"print characters\")" " = \"unlimited\"" \
+	"_gdb_setting_str print characters unlimited"
+
+    gdb_test_no_output "set print characters 1"
+    gdb_test "p \$_gdb_setting(\"print characters\")" " = 1" \
+	"_gdb_setting print characters 1"
+    gdb_test "p \$_gdb_setting_str(\"print characters\")" " = \"1\"" \
+	"_gdb_setting_str print characters 1"
+}
+
 proc_with_prefix test_setshow_prompt {} {
     clean_restart
 
@@ -493,6 +514,7 @@ test_setshow_height
 test_setshow_history
 test_setshow_language
 test_setshow_listsize
+test_setshow_print_characters
 test_setshow_prompt
 test_setshow_radix
 test_setshow_width
Index: src/gdb/testsuite/gdb.guile/scm-parameter.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.guile/scm-parameter.exp
+++ src/gdb/testsuite/gdb.guile/scm-parameter.exp
@@ -105,6 +105,7 @@ foreach_with_prefix param {
     "listsize"
     "print elements"
     "max-completions"
+    "print characters"
 } {
     set param_range_error "integer -1 out of range"
     set param_type_error \
@@ -118,7 +119,8 @@ foreach_with_prefix param {
 	    set param_get_minus_one -1
 	    set param_set_minus_one ""
 	}
-	"print elements" {
+	"print elements" -
+	"print characters" {
 	    set param_get_zero "#:unlimited"
 	    set param_get_minus_one "#:unlimited"
 	    set param_set_minus_one $param_range_error
@@ -153,6 +155,13 @@ foreach_with_prefix param {
 
     gdb_test "guile (print (parameter-value \"$param\"))" \
 	"#:unlimited" "test value of 'unlimited'"
+
+    if {$param == "print characters"} {
+	gdb_test_no_output "set $param elements" "test set to 'elements'"
+
+	gdb_test "guile (print (parameter-value \"$param\"))" \
+	    "#:elements" "test value of 'elements'"
+    }
 }
 
 foreach_with_prefix kind {
Index: src/gdb/testsuite/gdb.pascal/str-chars.exp
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.pascal/str-chars.exp
@@ -0,0 +1,56 @@
+# Copyright 2022 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" " = 'abcdefghij'\\.\\.\\." \
+    "print message with 'print elements' set to 10"
+
+gdb_test_no_output "set print characters 20"
+gdb_test "print message" " = 'abcdefghijklmnopqrst'\\.\\.\\." \
+    "print message with 'print characters' set to 20"
+
+gdb_test_no_output "set print elements 15"
+gdb_test "print message" " = 'abcdefghijklmnopqrst'\\.\\.\\." \
+    "print message with 'print elements' set to 15"
+
+gdb_test_no_output "set print characters unlimited"
+gdb_test "print message" " = 'abcdefghijklmnopqrstuvwxyz'" \
+    "print message with 'print characters' set to unlimited"
+
+gdb_test_no_output "set print characters elements"
+gdb_test "print message" " = 'abcdefghijklmno'\\.\\.\\." \
+    "print message with 'print characters' set to elements"
Index: src/gdb/testsuite/gdb.pascal/str-chars.pas
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.pascal/str-chars.pas
@@ -0,0 +1,28 @@
+{
+ Copyright 2022 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
@@ -705,13 +705,13 @@ proc_with_prefix test_static_members {}
 }
 
 # Test the max_elements option for gdb.Value.format_string.
-proc_with_prefix test_max_elements {} {
+proc test_max_string_one { setting unlimited } {
   global current_lang
   global default_pointer_regexp
 
   # 200 is the default maximum number of elements, so setting it should
   # not change the output.
-  set opts "max_elements=200"
+  set opts "max_$setting=200"
   with_test_prefix $opts {
     check_format_string "a_point_t" $opts
     check_format_string "a_point_t_pointer" $opts
@@ -722,8 +722,10 @@ proc_with_prefix test_max_elements {} {
     check_format_string "a_binary_string" $opts
     check_format_string "a_binary_string_array" $opts
     check_format_string "a_big_string" $opts
-    check_format_string "an_array" $opts
-    check_format_string "an_array_with_repetition" $opts
+    if { $setting == "elements"} {
+      check_format_string "an_array" $opts
+      check_format_string "an_array_with_repetition" $opts
+    }
     check_format_string "a_symbol_pointer" $opts
 
     if { $current_lang == "c++" } {
@@ -732,7 +734,7 @@ proc_with_prefix test_max_elements {} {
     }
   }
 
-  set opts "max_elements=3"
+  set opts "max_$setting=3"
   with_test_prefix $opts {
     check_format_string "a_point_t" $opts
     check_format_string "a_point_t_pointer" $opts
@@ -749,9 +751,11 @@ proc_with_prefix test_max_elements {} {
       "\"hell\"..."
     check_format_string "a_big_string" $opts \
       [get_cut_big_string 3]
-    check_format_string "an_array" $opts
-    check_format_string "an_array_with_repetition" $opts \
-      "\\{1, 3 <repeats 12 times>...\\}"
+    if { $setting == "elements"} {
+      check_format_string "an_array" $opts
+      check_format_string "an_array_with_repetition" $opts \
+	"\\{1, 3 <repeats 12 times>...\\}"
+    }
     check_format_string "a_symbol_pointer" $opts
 
     if { $current_lang == "c++" } {
@@ -760,9 +764,9 @@ proc_with_prefix test_max_elements {} {
     }
   }
 
-  # Both 1,000 (we don't have that many elements) and 0 (unlimited) should
+  # Both 1,000 (we don't have that many elements) and unlimited should
   # mean no truncation.
-  foreach opts { "max_elements=1000" "max_elements=0" } {
+  foreach opts [list "max_$setting=1000" "max_$setting=$unlimited"] {
     with_test_prefix $opts {
       check_format_string "a_point_t" $opts
       check_format_string "a_point_t_pointer" $opts
@@ -774,8 +778,10 @@ proc_with_prefix test_max_elements {} {
       check_format_string "a_binary_string_array" $opts
       check_format_string "a_big_string" $opts \
         [get_cut_big_string 1000]
-      check_format_string "an_array" $opts
-      check_format_string "an_array_with_repetition" $opts
+      if { $setting == "elements"} {
+	check_format_string "an_array" $opts
+	check_format_string "an_array_with_repetition" $opts
+      }
       check_format_string "a_symbol_pointer" $opts
 
       if { $current_lang == "c++" } {
@@ -785,15 +791,24 @@ proc_with_prefix test_max_elements {} {
     }
   }
 
-  with_temp_option "set print elements 4" "set print elements 200" {
+  with_temp_option "set print $setting 4" "set print $setting 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\"..."
-    check_format_string "an_array_with_repetition" "" \
-      "\\{1, 3 <repeats 12 times>...\\}"
+    if { $setting == "elements"} {
+      check_format_string "an_array_with_repetition" "" \
+	"\\{1, 3 <repeats 12 times>...\\}"
+    }
+  }
+}
+
+proc_with_prefix test_max_string {} {
+  foreach_with_prefix setting { "elements" "characters" } {
+    test_max_string_one $setting \
+      [string map {elements 0 characters 4294967295} $setting]
   }
 }
 
@@ -1153,7 +1168,7 @@ proc_with_prefix test_all_common {} {
   test_deref_refs
   test_actual_objects
   test_static_members
-  test_max_elements
+  test_max_string
   test_max_depth
   test_repeat_threshold
   test_format
Index: src/gdb/testsuite/gdb.python/py-parameter.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.python/py-parameter.exp
+++ src/gdb/testsuite/gdb.python/py-parameter.exp
@@ -338,6 +338,7 @@ proc_with_prefix test_gdb_parameter { }
 	"listsize"
 	"print elements"
 	"max-completions"
+	"print characters"
     } {
 	clean_restart
 
@@ -348,7 +349,8 @@ proc_with_prefix test_gdb_parameter { }
 		set param_get_minus_one -1
 		set param_set_minus_one ""
 	    }
-	    "print elements" {
+	    "print elements" -
+	    "print characters" {
 		set param_get_zero None
 		set param_get_minus_one None
 		set param_set_minus_one $param_range_error
@@ -393,6 +395,15 @@ proc_with_prefix test_gdb_parameter { }
 
 	gdb_test "python print(gdb.parameter('$param'))" \
 	    None "test value of 'unlimited'"
+
+	if {$param == "print characters"} {
+	    gdb_test_no_output \
+		"python gdb.set_parameter('$param', 'elements')" \
+		"test set to 'elements'"
+
+	    gdb_test "python print(gdb.parameter('$param'))" \
+		elements "test value of 'elements'"
+	}
     }
 
     clean_restart
