Index: src/gdb/cli/cli-cmds.c
===================================================================
--- src.orig/gdb/cli/cli-cmds.c
+++ src/gdb/cli/cli-cmds.c
@@ -2213,22 +2213,40 @@ value_from_setting (const setting &var,
 {
   switch (var.type ())
     {
+    case var_uinteger:
     case var_integer:
-      if (var.get<int> () == INT_MAX)
-	return value_from_longest (builtin_type (gdbarch)->builtin_int,
-				   0);
-      else
-	return value_from_longest (builtin_type (gdbarch)->builtin_int,
-				   var.get<int> ());
-    case var_zinteger:
-      return value_from_longest (builtin_type (gdbarch)->builtin_int,
-				 var.get<int> ());
+    case var_pinteger:
+      {
+	LONGEST value
+	  = (var.type () == var_uinteger
+	     ? static_cast<LONGEST> (var.get<unsigned int> ())
+	     : static_cast<LONGEST> (var.get<int> ()));
+
+	if (var.extra_literals () != nullptr)
+	  for (const literal_def *l = var.extra_literals ();
+	       l->literal != nullptr;
+	       l++)
+	    if (value == l->use)
+	      {
+		if (l->val.has_value ())
+		  value = *l->val;
+		else
+		  return allocate_value (builtin_type (gdbarch)->builtin_void);
+		break;
+	      }
+
+	if (var.type () == var_uinteger)
+	  return
+	    value_from_ulongest (builtin_type (gdbarch)->builtin_unsigned_int,
+				 static_cast<unsigned int> (value));
+	else
+	  return
+	    value_from_longest (builtin_type (gdbarch)->builtin_int,
+				static_cast<int> (value));
+      }
     case var_boolean:
       return value_from_longest (builtin_type (gdbarch)->builtin_int,
 				 var.get<bool> () ? 1 : 0);
-    case var_zuinteger_unlimited:
-      return value_from_longest (builtin_type (gdbarch)->builtin_int,
-				 var.get<int> ());
     case var_auto_boolean:
       {
 	int val;
@@ -2250,17 +2268,6 @@ value_from_setting (const setting &var,
 	return value_from_longest (builtin_type (gdbarch)->builtin_int,
 				   val);
       }
-    case var_uinteger:
-      if (var.get<unsigned int> () == UINT_MAX)
-	return value_from_ulongest
-	  (builtin_type (gdbarch)->builtin_unsigned_int, 0);
-      else
-	return value_from_ulongest
-	  (builtin_type (gdbarch)->builtin_unsigned_int,
-	   var.get<unsigned int> ());
-    case var_zuinteger:
-      return value_from_ulongest (builtin_type (gdbarch)->builtin_unsigned_int,
-				  var.get<unsigned int> ());
     case var_string:
     case var_string_noescape:
     case var_optional_filename:
@@ -2330,13 +2337,11 @@ str_value_from_setting (const setting &v
 {
   switch (var.type ())
     {
+    case var_uinteger:
     case var_integer:
-    case var_zinteger:
+    case var_pinteger:
     case var_boolean:
-    case var_zuinteger_unlimited:
     case var_auto_boolean:
-    case var_uinteger:
-    case var_zuinteger:
       {
 	std::string cmd_val = get_setshow_command_value_string (var);
 
Index: src/gdb/cli/cli-decode.c
===================================================================
--- src.orig/gdb/cli/cli-decode.c
+++ src/gdb/cli/cli-decode.c
@@ -496,6 +496,8 @@ empty_func (const char *args, int from_t
    TYPE is set_cmd or show_cmd.
    THECLASS is as in add_cmd.
    VAR_TYPE is the kind of thing we are setting.
+   EXTRA_LITERALS if non-NULL define extra literals to be accepted in lieu of
+   a number for integer variables.
    ARGS is a pre-validated type-erased reference to the variable being
    controlled by this command.
    DOC is the documentation string.  */
@@ -505,6 +507,7 @@ add_set_or_show_cmd (const char *name,
 		     enum cmd_types type,
 		     enum command_class theclass,
 		     var_types var_type,
+		     const literal_def *extra_literals,
 		     const setting::erased_args &arg,
 		     const char *doc,
 		     struct cmd_list_element **list)
@@ -513,7 +516,7 @@ add_set_or_show_cmd (const char *name,
 
   gdb_assert (type == set_cmd || type == show_cmd);
   c->type = type;
-  c->var.emplace (var_type, arg);
+  c->var.emplace (var_type, extra_literals, arg);
 
   /* This needs to be something besides NULL so that this isn't
      treated as a help class.  */
@@ -523,10 +526,12 @@ add_set_or_show_cmd (const char *name,
 
 /* Add element named NAME to both command lists SET_LIST and SHOW_LIST.
    THECLASS is as in add_cmd.  VAR_TYPE is the kind of thing we are
-   setting.  ARGS is a pre-validated type-erased reference to the
-   variable being controlled by this command.  SET_FUNC and SHOW_FUNC
-   are the callback functions (if non-NULL).  SET_DOC, SHOW_DOC and
-   HELP_DOC are the documentation strings.
+   setting.  EXTRA_LITERALS if non-NULL define extra literals to be
+   accepted in lieu of a number for integer variables.  ARGS is a
+   pre-validated type-erased reference to the variable being controlled
+   by this command.  SET_FUNC and SHOW_FUNC are the callback functions
+   (if non-NULL).  SET_DOC, SHOW_DOC and HELP_DOC are the documentation
+   strings.
 
    Return the newly created set and show commands.  */
 
@@ -534,6 +539,7 @@ static set_show_commands
 add_setshow_cmd_full_erased (const char *name,
 			     enum command_class theclass,
 			     var_types var_type,
+			     const literal_def *extra_literals,
 			     const setting::erased_args &args,
 			     const char *set_doc, const char *show_doc,
 			     const char *help_doc,
@@ -557,14 +563,16 @@ add_setshow_cmd_full_erased (const char
       full_set_doc = make_unique_xstrdup (set_doc);
       full_show_doc = make_unique_xstrdup (show_doc);
     }
-  set = add_set_or_show_cmd (name, set_cmd, theclass, var_type, args,
+  set = add_set_or_show_cmd (name, set_cmd, theclass, var_type,
+			     extra_literals, args,
 			     full_set_doc.release (), set_list);
   set->doc_allocated = 1;
 
   if (set_func != NULL)
     set->func = set_func;
 
-  show = add_set_or_show_cmd (name, show_cmd, theclass, var_type, args,
+  show = add_set_or_show_cmd (name, show_cmd, theclass, var_type,
+			      extra_literals, args,
 			      full_show_doc.release (), show_list);
   show->doc_allocated = 1;
   show->show_value_func = show_func;
@@ -575,14 +583,41 @@ add_setshow_cmd_full_erased (const char
   return {set, show};
 }
 
+/* Completes on integer commands that support extra literals.  */
+
+static void
+integer_literals_completer (struct cmd_list_element *c,
+			    completion_tracker &tracker,
+			    const char *text, const char *word)
+{
+  const literal_def *extra_literals = c->var->extra_literals ();
+
+  if (*text == '\0')
+    {
+      tracker.add_completion (make_unique_xstrdup ("NUMBER"));
+      for (const literal_def *l = extra_literals;
+	   l->literal != nullptr;
+	   l++)
+	tracker.add_completion (make_unique_xstrdup (l->literal));
+    }
+  else
+    for (const literal_def *l = extra_literals;
+	 l->literal != nullptr;
+	 l++)
+      if (startswith (l->literal, text))
+	tracker.add_completion (make_unique_xstrdup (l->literal));
+}
+
 /* Add element named NAME to both command lists SET_LIST and SHOW_LIST.
    THECLASS is as in add_cmd.  VAR_TYPE is the kind of thing we are
    setting.  VAR is address of the variable being controlled by this
-   command.  If nullptr is given as VAR, then both SET_SETTING_FUNC and
-   GET_SETTING_FUNC must be provided.  SET_SETTING_FUNC and GET_SETTING_FUNC
-   are callbacks used to access and modify the underlying property,
-   whatever its storage is.  SET_FUNC and SHOW_FUNC are the callback
-   functions (if non-NULL).  SET_DOC, SHOW_DOC and HELP_DOC are the
+   command.  EXTRA_LITERALS if non-NULL define extra literals to be
+   accepted in lieu of a number for integer variables.  If nullptr is
+   given as VAR, then both SET_SETTING_FUNC and GET_SETTING_FUNC must
+   be provided.  SET_SETTING_FUNC and GET_SETTING_FUNC are callbacks
+   used to access and modify the underlying property, whatever its
+   storage is.  SET_FUNC and SHOW_FUNC are the callback functions
+   (if non-NULL).  SET_DOC, SHOW_DOC and HELP_DOC are the
    documentation strings.
 
    Return the newly created set and show commands.  */
@@ -592,6 +627,7 @@ static set_show_commands
 add_setshow_cmd_full (const char *name,
 		      enum command_class theclass,
 		      var_types var_type, T *var,
+		      const literal_def *extra_literals,
 		      const char *set_doc, const char *show_doc,
 		      const char *help_doc,
 		      typename setting_func_types<T>::set set_setting_func,
@@ -604,16 +640,43 @@ add_setshow_cmd_full (const char *name,
   auto erased_args
     = setting::erase_args (var_type, var,
 			   set_setting_func, get_setting_func);
+  auto cmds = add_setshow_cmd_full_erased (name,
+					   theclass,
+					   var_type, extra_literals,
+					   erased_args,
+					   set_doc, show_doc,
+					   help_doc,
+					   set_func,
+					   show_func,
+					   set_list,
+					   show_list);
 
-  return add_setshow_cmd_full_erased (name,
-				      theclass,
-				      var_type, erased_args,
-				      set_doc, show_doc,
-				      help_doc,
-				      set_func,
-				      show_func,
-				      set_list,
-				      show_list);
+  if (extra_literals != nullptr)
+    set_cmd_completer (cmds.set, integer_literals_completer);
+
+  return cmds;
+}
+
+/* Same as above but omitting EXTRA_LITERALS.  */
+
+template<typename T>
+static set_show_commands
+add_setshow_cmd_full (const char *name,
+		      enum command_class theclass,
+		      var_types var_type, T *var,
+		      const char *set_doc, const char *show_doc,
+		      const char *help_doc,
+		      typename setting_func_types<T>::set set_setting_func,
+		      typename setting_func_types<T>::get get_setting_func,
+		      cmd_func_ftype *set_func,
+		      show_value_ftype *show_func,
+		      struct cmd_list_element **set_list,
+		      struct cmd_list_element **show_list)
+{
+  return add_setshow_cmd_full (name, theclass, var_type, var, nullptr,
+			       set_doc, show_doc, help_doc,
+			       set_setting_func, get_setting_func,
+			       set_func, show_func, set_list, show_list);
 }
 
 /* Add element named NAME to command list LIST (the list for set or
@@ -982,25 +1045,6 @@ add_setshow_optional_filename_cmd (const
   return cmds;
 }
 
-/* Completes on literal "unlimited".  Used by integer commands that
-   support a special "unlimited" value.  */
-
-static void
-integer_unlimited_completer (struct cmd_list_element *ignore,
-			     completion_tracker &tracker,
-			     const char *text, const char *word)
-{
-  static const char * const keywords[] =
-    {
-      "unlimited",
-      NULL,
-    };
-
-  if (*text == '\0')
-    tracker.add_completion (make_unique_xstrdup ("NUMBER"));
-  complete_on_enum (tracker, keywords, text, word);
-}
-
 /* Add element named NAME to both the set and show command LISTs (the
    list for set/show or some sublist thereof).  THECLASS is as in
    add_cmd.  VAR is address of the variable which will contain the
@@ -1009,6 +1053,55 @@ integer_unlimited_completer (struct cmd_
 
 set_show_commands
 add_setshow_integer_cmd (const char *name, enum command_class theclass,
+			 int *var, const literal_def *extra_literals,
+			 const char *set_doc, const char *show_doc,
+			 const char *help_doc,
+			 cmd_func_ftype *set_func,
+			 show_value_ftype *show_func,
+			 struct cmd_list_element **set_list,
+			 struct cmd_list_element **show_list)
+{
+  set_show_commands commands
+    = add_setshow_cmd_full<int> (name, theclass, var_integer, var,
+				 extra_literals, set_doc, show_doc,
+				 help_doc, nullptr, nullptr, set_func,
+				 show_func, set_list, show_list);
+  return commands;
+}
+
+/* Same as above but using a getter and a setter function instead of a pointer
+   to a global storage buffer.  */
+
+set_show_commands
+add_setshow_integer_cmd (const char *name, command_class theclass,
+			 const literal_def *extra_literals,
+			 const char *set_doc, const char *show_doc,
+			 const char *help_doc,
+			 setting_func_types<int>::set set_func,
+			 setting_func_types<int>::get get_func,
+			 show_value_ftype *show_func,
+			 cmd_list_element **set_list,
+			 cmd_list_element **show_list)
+{
+  auto cmds = add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr,
+					 extra_literals, set_doc, show_doc,
+					 help_doc, set_func, get_func, nullptr,
+					 show_func, set_list, show_list);
+  return cmds;
+}
+
+/* Accept `unlimited' or 0, translated internally to INT_MAX.  */
+const literal_def integer_unlimited_literals[] =
+  {
+    { "unlimited", INT_MAX, 0 },
+    { nullptr }
+  };
+
+/* Same as above but using `integer_unlimited_literals', with a pointer
+   to a global storage buffer.  */
+
+set_show_commands
+add_setshow_integer_cmd (const char *name, enum command_class theclass,
 			 int *var,
 			 const char *set_doc, const char *show_doc,
 			 const char *help_doc,
@@ -1019,12 +1112,10 @@ add_setshow_integer_cmd (const char *nam
 {
   set_show_commands commands
     = add_setshow_cmd_full<int> (name, theclass, var_integer, var,
+				 integer_unlimited_literals,
 				 set_doc, show_doc, help_doc,
 				 nullptr, nullptr, set_func,
 				 show_func, set_list, show_list);
-
-  set_cmd_completer (commands.set, integer_unlimited_completer);
-
   return commands;
 }
 
@@ -1042,12 +1133,54 @@ add_setshow_integer_cmd (const char *nam
 			 cmd_list_element **show_list)
 {
   auto cmds = add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr,
+					 integer_unlimited_literals,
 					 set_doc, show_doc, help_doc, set_func,
 					 get_func, nullptr, show_func, set_list,
 					 show_list);
+  return cmds;
+}
 
-  set_cmd_completer (cmds.set, integer_unlimited_completer);
+/* Add element named NAME to both the set and show command LISTs (the
+   list for set/show or some sublist thereof).  CLASS is as in
+   add_cmd.  VAR is address of the variable which will contain the
+   value.  SET_DOC and SHOW_DOC are the documentation strings.  */
+
+set_show_commands
+add_setshow_pinteger_cmd (const char *name, enum command_class theclass,
+			  int *var, const literal_def *extra_literals,
+			  const char *set_doc, const char *show_doc,
+			  const char *help_doc,
+			  cmd_func_ftype *set_func,
+			  show_value_ftype *show_func,
+			  struct cmd_list_element **set_list,
+			  struct cmd_list_element **show_list)
+{
+  set_show_commands commands
+    = add_setshow_cmd_full<int> (name, theclass, var_pinteger, var,
+				 extra_literals, set_doc, show_doc,
+				 help_doc, nullptr, nullptr, set_func,
+				 show_func, set_list, show_list);
+  return commands;
+}
+
+/* Same as above but using a getter and a setter function instead of a pointer
+   to a global storage buffer.  */
 
+set_show_commands
+add_setshow_pinteger_cmd (const char *name, command_class theclass,
+			  const literal_def *extra_literals,
+			  const char *set_doc, const char *show_doc,
+			  const char *help_doc,
+			  setting_func_types<int>::set set_func,
+			  setting_func_types<int>::get get_func,
+			  show_value_ftype *show_func,
+			  cmd_list_element **set_list,
+			  cmd_list_element **show_list)
+{
+  auto cmds = add_setshow_cmd_full<int> (name, theclass, var_pinteger, nullptr,
+					 extra_literals, set_doc, show_doc,
+					 help_doc, set_func, get_func, nullptr,
+					 show_func, set_list, show_list);
   return cmds;
 }
 
@@ -1058,7 +1191,7 @@ add_setshow_integer_cmd (const char *nam
 
 set_show_commands
 add_setshow_uinteger_cmd (const char *name, enum command_class theclass,
-			  unsigned int *var,
+			  unsigned int *var, const literal_def *extra_literals,
 			  const char *set_doc, const char *show_doc,
 			  const char *help_doc,
 			  cmd_func_ftype *set_func,
@@ -1068,12 +1201,9 @@ add_setshow_uinteger_cmd (const char *na
 {
   set_show_commands commands
     = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, var,
-					  set_doc, show_doc, help_doc,
-					  nullptr, nullptr, set_func,
+					  extra_literals, set_doc, show_doc,
+					  help_doc, nullptr, nullptr, set_func,
 					  show_func, set_list, show_list);
-
-  set_cmd_completer (commands.set, integer_unlimited_completer);
-
   return commands;
 }
 
@@ -1082,6 +1212,7 @@ add_setshow_uinteger_cmd (const char *na
 
 set_show_commands
 add_setshow_uinteger_cmd (const char *name, command_class theclass,
+			  const literal_def *extra_literals,
 			  const char *set_doc, const char *show_doc,
 			  const char *help_doc,
 			  setting_func_types<unsigned int>::set set_func,
@@ -1091,13 +1222,63 @@ add_setshow_uinteger_cmd (const char *na
 			  cmd_list_element **show_list)
 {
   auto cmds = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
-						  nullptr, set_doc, show_doc,
-						  help_doc, set_func, get_func,
-						  nullptr, show_func, set_list,
+						  nullptr, extra_literals,
+						  set_doc, show_doc, help_doc,
+						  set_func, get_func, nullptr,
+						  show_func, set_list,
 						  show_list);
+  return cmds;
+}
 
-  set_cmd_completer (cmds.set, integer_unlimited_completer);
+/* Accept `unlimited' or 0, translated internally to UINT_MAX.  */
+const literal_def uinteger_unlimited_literals[] =
+  {
+    { "unlimited", UINT_MAX, 0 },
+    { nullptr }
+  };
+
+/* Same as above but using `uinteger_unlimited_literals', with a pointer
+   to a global storage buffer.  */
+
+set_show_commands
+add_setshow_uinteger_cmd (const char *name, enum command_class theclass,
+			  unsigned int *var,
+			  const char *set_doc, const char *show_doc,
+			  const char *help_doc,
+			  cmd_func_ftype *set_func,
+			  show_value_ftype *show_func,
+			  struct cmd_list_element **set_list,
+			  struct cmd_list_element **show_list)
+{
+  set_show_commands commands
+    = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, var,
+					  uinteger_unlimited_literals,
+					  set_doc, show_doc, help_doc, nullptr,
+					  nullptr, set_func, show_func,
+					  set_list, show_list);
+  return commands;
+}
+
+/* Same as above but using a getter and a setter function instead of a pointer
+   to a global storage buffer.  */
 
+set_show_commands
+add_setshow_uinteger_cmd (const char *name, command_class theclass,
+			  const char *set_doc, const char *show_doc,
+			  const char *help_doc,
+			  setting_func_types<unsigned int>::set set_func,
+			  setting_func_types<unsigned int>::get get_func,
+			  show_value_ftype *show_func,
+			  cmd_list_element **set_list,
+			  cmd_list_element **show_list)
+{
+  auto cmds = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
+						  nullptr,
+						  uinteger_unlimited_literals,
+						  set_doc, show_doc, help_doc,
+						  set_func, get_func, nullptr,
+						  show_func, set_list,
+						  show_list);
   return cmds;
 }
 
@@ -1116,7 +1297,7 @@ add_setshow_zinteger_cmd (const char *na
 			  struct cmd_list_element **set_list,
 			  struct cmd_list_element **show_list)
 {
-  return add_setshow_cmd_full<int> (name, theclass, var_zinteger, var,
+  return add_setshow_cmd_full<int> (name, theclass, var_integer, var,
 				    set_doc, show_doc, help_doc,
 				    nullptr, nullptr, set_func,
 				    show_func, set_list, show_list);
@@ -1135,12 +1316,22 @@ add_setshow_zinteger_cmd (const char *na
 			  cmd_list_element **set_list,
 			  cmd_list_element **show_list)
 {
-  return add_setshow_cmd_full<int> (name, theclass, var_zinteger, nullptr,
+  return add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr,
 				    set_doc, show_doc, help_doc, set_func,
 				    get_func, nullptr, show_func, set_list,
 				    show_list);
 }
 
+/* Accept `unlimited' or -1, using -1 internally.  */
+const literal_def pinteger_unlimited_literals[] =
+  {
+    { "unlimited", -1, -1 },
+    { nullptr }
+  };
+
+/* Same as above but using `pinteger_unlimited_literals', with a pointer
+   to a global storage buffer.  */
+
 set_show_commands
 add_setshow_zuinteger_unlimited_cmd (const char *name,
 				     enum command_class theclass,
@@ -1154,13 +1345,11 @@ add_setshow_zuinteger_unlimited_cmd (con
 				     struct cmd_list_element **show_list)
 {
   set_show_commands commands
-    = add_setshow_cmd_full<int> (name, theclass, var_zuinteger_unlimited, var,
+    = add_setshow_cmd_full<int> (name, theclass, var_pinteger, var,
+				 pinteger_unlimited_literals,
 				 set_doc, show_doc, help_doc, nullptr,
 				 nullptr, set_func, show_func, set_list,
 				 show_list);
-
-  set_cmd_completer (commands.set, integer_unlimited_completer);
-
   return commands;
 }
 
@@ -1178,13 +1367,11 @@ add_setshow_zuinteger_unlimited_cmd (con
 				     cmd_list_element **show_list)
 {
   auto cmds
-    = add_setshow_cmd_full<int> (name, theclass, var_zuinteger_unlimited,
-				 nullptr, set_doc, show_doc, help_doc, set_func,
+    = add_setshow_cmd_full<int> (name, theclass, var_pinteger, nullptr,
+				 pinteger_unlimited_literals,
+				 set_doc, show_doc, help_doc, set_func,
 				 get_func, nullptr, show_func, set_list,
 				 show_list);
-
-  set_cmd_completer (cmds.set, integer_unlimited_completer);
-
   return cmds;
 }
 
@@ -1203,7 +1390,7 @@ add_setshow_zuinteger_cmd (const char *n
 			   struct cmd_list_element **set_list,
 			   struct cmd_list_element **show_list)
 {
-  return add_setshow_cmd_full<unsigned int> (name, theclass, var_zuinteger,
+  return add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
 					     var, set_doc, show_doc, help_doc,
 					     nullptr, nullptr, set_func,
 					     show_func, set_list, show_list);
@@ -1222,7 +1409,7 @@ add_setshow_zuinteger_cmd (const char *n
 			   cmd_list_element **set_list,
 			   cmd_list_element **show_list)
 {
-  return add_setshow_cmd_full<unsigned int> (name, theclass, var_zuinteger,
+  return add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
 					     nullptr, set_doc, show_doc,
 					     help_doc, set_func, get_func,
 					     nullptr, show_func, set_list,
Index: src/gdb/cli/cli-option.c
===================================================================
--- src.orig/gdb/cli/cli-option.c
+++ src/gdb/cli/cli-option.c
@@ -38,7 +38,7 @@ union option_value
   /* For var_uinteger options.  */
   unsigned int uinteger;
 
-  /* For var_zuinteger_unlimited options.  */
+  /* For var_integer and var_pinteger options.  */
   int integer;
 
   /* For var_enum options.  */
@@ -356,42 +356,52 @@ parse_option (gdb::array_view<const opti
 	return option_def_and_value {*match, match_ctx, val};
       }
     case var_uinteger:
-    case var_zuinteger_unlimited:
+    case var_integer:
+    case var_pinteger:
       {
-	if (completion != nullptr)
+	if (completion != nullptr && match->extra_literals != nullptr)
 	  {
+	    /* Convenience to let the user know what the option can
+	       accept.  Make sure there's no common prefix between
+	       "NUMBER" and all the strings when adding new ones,
+	       so that readline doesn't do a partial match.  */
 	    if (**args == '\0')
 	      {
-		/* Convenience to let the user know what the option
-		   can accept.  Note there's no common prefix between
-		   the strings on purpose, so that readline doesn't do
-		   a partial match.  */
 		completion->tracker.add_completion
 		  (make_unique_xstrdup ("NUMBER"));
-		completion->tracker.add_completion
-		  (make_unique_xstrdup ("unlimited"));
+		for (const literal_def *l = match->extra_literals;
+		     l->literal != nullptr;
+		     l++)
+		  completion->tracker.add_completion
+		    (make_unique_xstrdup (l->literal));
 		return {};
 	      }
-	    else if (startswith ("unlimited", *args))
+	    else
 	      {
-		completion->tracker.add_completion
-		  (make_unique_xstrdup ("unlimited"));
-		return {};
+		bool completions = false;
+		for (const literal_def *l = match->extra_literals;
+		     l->literal != nullptr;
+		     l++)
+		  if (startswith (l->literal, *args))
+		    {
+		      completion->tracker.add_completion
+			(make_unique_xstrdup (l->literal));
+		      completions = true;
+		    }
+		if (completions)
+		  return {};
 	      }
 	  }
 
-	if (match->type == var_zuinteger_unlimited)
-	  {
-	    option_value val;
-	    val.integer = parse_cli_var_zuinteger_unlimited (args, false);
-	    return option_def_and_value {*match, match_ctx, val};
-	  }
+	LONGEST v = parse_cli_var_integer (match->type,
+					   match->extra_literals,
+					   args, false);
+	option_value val;
+	if (match->type == var_uinteger)
+	  val.uinteger = v;
 	else
-	  {
-	    option_value val;
-	    val.uinteger = parse_cli_var_uinteger (match->type, args, false);
-	    return option_def_and_value {*match, match_ctx, val};
-	  }
+	  val.integer = v;
+	return option_def_and_value {*match, match_ctx, val};
       }
     case var_enum:
       {
@@ -593,7 +603,8 @@ save_option_value_in_ctx (gdb::optional<
       *ov->option.var_address.uinteger (ov->option, ov->ctx)
 	= ov->value->uinteger;
       break;
-    case var_zuinteger_unlimited:
+    case var_integer:
+    case var_pinteger:
       *ov->option.var_address.integer (ov->option, ov->ctx)
 	= ov->value->integer;
       break;
@@ -664,8 +675,20 @@ get_val_type_str (const option_def &opt,
     case var_boolean:
       return "[on|off]";
     case var_uinteger:
-    case var_zuinteger_unlimited:
-      return "NUMBER|unlimited";
+    case var_integer:
+    case var_pinteger:
+      {
+	buffer = "NUMBER";
+	if (opt.extra_literals != nullptr)
+	  for (const literal_def *l = opt.extra_literals;
+	       l->literal != nullptr;
+	       l++)
+	    {
+	      buffer += '|';
+	      buffer += l->literal;
+	    }
+	return buffer.c_str ();
+      }
     case var_enum:
       {
 	buffer = "";
@@ -789,20 +812,31 @@ add_setshow_cmds_for_options (command_cl
 	{
 	  add_setshow_uinteger_cmd (option.name, cmd_class,
 				    option.var_address.uinteger (option, data),
+				    option.extra_literals,
 				    option.set_doc, option.show_doc,
 				    option.help_doc,
 				    nullptr, option.show_cmd_cb,
 				    set_list, show_list);
 	}
-      else if (option.type == var_zuinteger_unlimited)
+      else if (option.type == var_integer)
 	{
-	  add_setshow_zuinteger_unlimited_cmd
-	    (option.name, cmd_class,
-	     option.var_address.integer (option, data),
-	     option.set_doc, option.show_doc,
-	     option.help_doc,
-	     nullptr, option.show_cmd_cb,
-	     set_list, show_list);
+	  add_setshow_integer_cmd (option.name, cmd_class,
+				   option.var_address.integer (option, data),
+				   option.extra_literals,
+				   option.set_doc, option.show_doc,
+				   option.help_doc,
+				   nullptr, option.show_cmd_cb,
+				   set_list, show_list);
+	}
+      else if (option.type == var_pinteger)
+	{
+	  add_setshow_pinteger_cmd (option.name, cmd_class,
+				    option.var_address.integer (option, data),
+				    option.extra_literals,
+				    option.set_doc, option.show_doc,
+				    option.help_doc,
+				    nullptr, option.show_cmd_cb,
+				    set_list, show_list);
 	}
       else if (option.type == var_enum)
 	{
Index: src/gdb/cli/cli-option.h
===================================================================
--- src.orig/gdb/cli/cli-option.h
+++ src/gdb/cli/cli-option.h
@@ -49,12 +49,13 @@ struct option_def
      used to create the option's "set/show" commands.  */
   constexpr option_def (const char *name_,
 			var_types var_type_,
+			const literal_def *extra_literals_,
 			erased_get_var_address_ftype *erased_get_var_address_,
 			show_value_ftype *show_cmd_cb_,
 			const char *set_doc_,
 			const char *show_doc_,
 			const char *help_doc_)
-    : name (name_), type (var_type_),
+    : name (name_), type (var_type_), extra_literals (extra_literals_),
       erased_get_var_address (erased_get_var_address_),
       var_address {},
       show_cmd_cb (show_cmd_cb_),
@@ -68,6 +69,9 @@ struct option_def
   /* The option's type.  */
   var_types type;
 
+  /* Extra literals, such as `unlimited', accepted in lieu of a number.  */
+  const literal_def *extra_literals;
+
   /* A function that gets the controlling variable's address, type
      erased.  */
   erased_get_var_address_ftype *erased_get_var_address;
@@ -160,7 +164,7 @@ struct boolean_option_def : option_def
 		      const char *set_doc_,
 		      const char *show_doc_ = nullptr,
 		      const char *help_doc_ = nullptr)
-    : option_def (long_option_, var_boolean,
+    : option_def (long_option_, var_boolean, nullptr,
 		  (erased_get_var_address_ftype *) get_var_address_cb_,
 		  show_cmd_cb_,
 		  set_doc_, show_doc_, help_doc_)
@@ -207,37 +211,59 @@ struct uinteger_option_def : option_def
 {
   uinteger_option_def (const char *long_option_,
 		       unsigned int *(*get_var_address_cb_) (Context *),
+		       const literal_def *extra_literals_,
 		       show_value_ftype *show_cmd_cb_,
 		       const char *set_doc_,
 		       const char *show_doc_ = nullptr,
 		       const char *help_doc_ = nullptr)
-    : option_def (long_option_, var_uinteger,
+    : option_def (long_option_, var_uinteger, extra_literals_,
 		  (erased_get_var_address_ftype *) get_var_address_cb_,
 		  show_cmd_cb_,
 		  set_doc_, show_doc_, help_doc_)
   {
     var_address.uinteger = detail::get_var_address<unsigned int, Context>;
   }
+
+  uinteger_option_def (const char *long_option_,
+		       unsigned int *(*get_var_address_cb_) (Context *),
+		       show_value_ftype *show_cmd_cb_,
+		       const char *set_doc_,
+		       const char *show_doc_ = nullptr,
+		       const char *help_doc_ = nullptr)
+    : uinteger_option_def (long_option_, get_var_address_cb_, nullptr,
+			   show_cmd_cb_, set_doc_, show_doc_, help_doc_)
+  { /* Nothing.  */ }
 };
 
-/* A var_zuinteger_unlimited command line option.  */
+/* A var_pinteger command line option.  */
 
 template<typename Context>
-struct zuinteger_unlimited_option_def : option_def
+struct pinteger_option_def : option_def
 {
-  zuinteger_unlimited_option_def (const char *long_option_,
-				  int *(*get_var_address_cb_) (Context *),
-				  show_value_ftype *show_cmd_cb_,
-				  const char *set_doc_,
-				  const char *show_doc_ = nullptr,
-				  const char *help_doc_ = nullptr)
-    : option_def (long_option_, var_zuinteger_unlimited,
+  pinteger_option_def (const char *long_option_,
+		       int *(*get_var_address_cb_) (Context *),
+		       const literal_def *extra_literals_,
+		       show_value_ftype *show_cmd_cb_,
+		       const char *set_doc_,
+		       const char *show_doc_ = nullptr,
+		       const char *help_doc_ = nullptr)
+    : option_def (long_option_, var_pinteger, extra_literals_,
 		  (erased_get_var_address_ftype *) get_var_address_cb_,
 		  show_cmd_cb_,
 		  set_doc_, show_doc_, help_doc_)
   {
     var_address.integer = detail::get_var_address<int, Context>;
   }
+
+  pinteger_option_def (const char *long_option_,
+		       int *(*get_var_address_cb_) (Context *),
+		       show_value_ftype *show_cmd_cb_,
+		       const char *set_doc_,
+		       const char *show_doc_ = nullptr,
+		       const char *help_doc_ = nullptr)
+    : pinteger_option_def (long_option_, get_var_address_cb_, nullptr,
+			   show_cmd_cb_, set_doc_, show_doc_, help_doc_)
+  { /* Nothing.  */ }
 };
 
 /* An var_enum command line option.  */
@@ -252,7 +278,7 @@ struct enum_option_def : option_def
 		   const char *set_doc_,
 		   const char *show_doc_ = nullptr,
 		   const char *help_doc_ = nullptr)
-    : option_def (long_option_, var_enum,
+    : option_def (long_option_, var_enum, nullptr,
 		  (erased_get_var_address_ftype *) get_var_address_cb_,
 		  show_cmd_cb_,
 		  set_doc_, show_doc_, help_doc_)
@@ -273,7 +299,7 @@ struct string_option_def : option_def
 		     const char *set_doc_,
 		     const char *show_doc_ = nullptr,
 		     const char *help_doc_ = nullptr)
-    : option_def (long_option_, var_string,
+    : option_def (long_option_, var_string, nullptr,
 		  (erased_get_var_address_ftype *) get_var_address_cb_,
 		  show_cmd_cb_,
 		  set_doc_, show_doc_, help_doc_)
Index: src/gdb/cli/cli-setshow.c
===================================================================
--- src.orig/gdb/cli/cli-setshow.c
+++ src/gdb/cli/cli-setshow.c
@@ -149,10 +149,11 @@ deprecated_show_value_hack (struct ui_fi
     }
 }
 
-/* Returns true if ARG is "unlimited".  */
+/* Returns true and the value in VAL if ARG is an accepted literal.  */
 
 static bool
-is_unlimited_literal (const char **arg, bool expression)
+get_literal_val (LONGEST &val, const literal_def *extra_literals,
+		 const char **arg, bool expression)
 {
   *arg = skip_spaces (*arg);
 
@@ -162,85 +163,104 @@ is_unlimited_literal (const char **arg,
 
   size_t len = p - *arg;
 
-  if (len > 0 && strncmp ("unlimited", *arg, len) == 0)
-    {
-      *arg += len;
-
-      /* If parsing an expression (i.e., parsing for a "set" command),
-	 anything after "unlimited" is junk.  For options, anything
-	 after "unlimited" might be a command argument or another
-	 option.  */
-      if (expression)
+  if (len > 0 && extra_literals != nullptr)
+    for (const literal_def *l = extra_literals;
+	 l->literal != nullptr;
+	 l++)
+      if (strncmp (l->literal, *arg, len) == 0)
 	{
-	  const char *after = skip_spaces (*arg);
-	  if (*after != '\0')
-	    error (_("Junk after \"%.*s\": %s"),
-		   (int) len, unl_start, after);
-	}
+	  *arg += len;
 
-      return true;
-    }
+	  /* If parsing an expression (i.e., parsing for a "set" command),
+	     anything after the literal is junk.  For options, anything
+	     after the literal might be a command argument or another
+	     option.  */
+	  if (expression)
+	    {
+	      const char *after = skip_spaces (*arg);
+	      if (*after != '\0')
+		error (_("Junk after \"%.*s\": %s"),
+		       (int) len, unl_start, after);
+	    }
+
+	  val = l->use;
+	  return true;
+	}
 
   return false;
 }
 
 /* See cli-setshow.h.  */
 
-unsigned int
-parse_cli_var_uinteger (var_types var_type, const char **arg,
-			bool expression)
+LONGEST
+parse_cli_var_integer (var_types var_type, const literal_def *extra_literals,
+		       const char **arg, bool expression)
 {
   LONGEST val;
 
   if (*arg == nullptr || **arg == '\0')
     {
-      if (var_type == var_uinteger)
-	error_no_arg (_("integer to set it to, or \"unlimited\""));
-      else
+      if (extra_literals == nullptr)
 	error_no_arg (_("integer to set it to"));
-    }
-
-  if (var_type == var_uinteger && is_unlimited_literal (arg, expression))
-    val = 0;
-  else if (expression)
-    val = parse_and_eval_long (*arg);
-  else
-    val = get_ulongest (arg);
-
-  if (var_type == var_uinteger && val == 0)
-    val = UINT_MAX;
-  else if (val < 0
-	   /* For var_uinteger, don't let the user set the value
-	      to UINT_MAX directly, as that exposes an
-	      implementation detail to the user interface.  */
-	   || (var_type == var_uinteger && val >= UINT_MAX)
-	   || (var_type == var_zuinteger && val > UINT_MAX))
-    error (_("integer %s out of range"), plongest (val));
-
-  return val;
-}
-
-/* See cli-setshow.h.  */
+      else
+	{
+	  std::string buffer = "";
+	  size_t count = 0;
 
-int
-parse_cli_var_zuinteger_unlimited (const char **arg, bool expression)
-{
-  LONGEST val;
+	  for (const literal_def *l = extra_literals;
+	       l->literal != nullptr;
+	       l++, count++)
+	    {
+	      if (count != 0)
+		buffer += ", ";
+	      buffer = buffer + '"' + l->literal + '"';
+	    }
+	  if (count > 1)
+	    error_no_arg
+	      (string_printf (_("integer to set it to, or one of: %s"),
+			      buffer.c_str ()).c_str ());
+	  else
+	    error_no_arg
+	      (string_printf (_("integer to set it to, or %s"),
+			      buffer.c_str ()).c_str ());
+	}
+    }
 
-  if (*arg == nullptr || **arg == '\0')
-    error_no_arg (_("integer to set it to, or \"unlimited\""));
+  if (!get_literal_val (val, extra_literals, arg, expression))
+    {
+      if (expression)
+	val = parse_and_eval_long (*arg);
+      else
+	val = get_ulongest (arg);
 
-  if (is_unlimited_literal (arg, expression))
-    val = -1;
-  else if (expression)
-    val = parse_and_eval_long (*arg);
-  else
-    val = get_ulongest (arg);
+      enum tribool allowed = TRIBOOL_UNKNOWN;
+      if (extra_literals != nullptr)
+	{
+	  for (const literal_def *l = extra_literals;
+	       l->literal != nullptr;
+	       l++)
+	    if (l->val.has_value () && val == *l->val)
+	      {
+		allowed = TRIBOOL_TRUE;
+		val = l->use;
+		break;
+	      }
+	    else if (val == l->use)
+	      allowed = TRIBOOL_FALSE;
+	}
 
-  if (val > INT_MAX)
-    error (_("integer %s out of range"), plongest (val));
-  else if (val < -1)
-    error (_("only -1 is allowed to set as unlimited"));
+      if (allowed == TRIBOOL_UNKNOWN)
+	{
+	  if (val > UINT_MAX || val < INT_MIN
+	      || (var_type == var_uinteger && val < 0)
+	      || (var_type == var_integer && val > INT_MAX)
+	      || (var_type == var_pinteger && val < 0)
+	      || (var_type == var_pinteger && val > INT_MAX))
+	    allowed = TRIBOOL_FALSE;
+	}
+      if (allowed == TRIBOOL_FALSE)
+	error (_("integer %s out of range"), plongest (val));
+    }
 
   return val;
 }
@@ -405,41 +425,18 @@ do_set_command (const char *arg, int fro
       option_changed = c->var->set<enum auto_boolean> (parse_auto_binary_operation (arg));
       break;
     case var_uinteger:
-    case var_zuinteger:
       option_changed
-	= c->var->set<unsigned int> (parse_cli_var_uinteger (c->var->type (),
-							     &arg, true));
+	= c->var->set<unsigned int> (parse_cli_var_integer (c->var->type (),
+							    c->var->
+							    extra_literals (),
+							    &arg, true));
       break;
     case var_integer:
-    case var_zinteger:
-      {
-	LONGEST val;
-
-	if (*arg == '\0')
-	  {
-	    if (c->var->type () == var_integer)
-	      error_no_arg (_("integer to set it to, or \"unlimited\""));
-	    else
-	      error_no_arg (_("integer to set it to"));
-	  }
-
-	if (c->var->type () == var_integer && is_unlimited_literal (&arg, true))
-	  val = 0;
-	else
-	  val = parse_and_eval_long (arg);
-
-	if (val == 0 && c->var->type () == var_integer)
-	  val = INT_MAX;
-	else if (val < INT_MIN
-		 /* For var_integer, don't let the user set the value
-		    to INT_MAX directly, as that exposes an
-		    implementation detail to the user interface.  */
-		 || (c->var->type () == var_integer && val >= INT_MAX)
-		 || (c->var->type () == var_zinteger && val > INT_MAX))
-	  error (_("integer %s out of range"), plongest (val));
-
-	option_changed = c->var->set<int> (val);
-      }
+    case var_pinteger:
+      option_changed
+	= c->var->set<int> (parse_cli_var_integer (c->var->type (),
+						   c->var->extra_literals (),
+						   &arg, true));
       break;
     case var_enum:
       {
@@ -454,10 +451,6 @@ do_set_command (const char *arg, int fro
 	option_changed = c->var->set<const char *> (match);
       }
       break;
-    case var_zuinteger_unlimited:
-      option_changed = c->var->set<int>
-	(parse_cli_var_zuinteger_unlimited (&arg, true));
-      break;
     default:
       error (_("gdb internal error: bad var_type in do_setshow_command"));
     }
@@ -551,7 +544,6 @@ do_set_command (const char *arg, int fro
 	  }
 	  break;
 	case var_uinteger:
-	case var_zuinteger:
 	  {
 	    char s[64];
 
@@ -560,8 +552,7 @@ do_set_command (const char *arg, int fro
 	  }
 	  break;
 	case var_integer:
-	case var_zinteger:
-	case var_zuinteger_unlimited:
+	case var_pinteger:
 	  {
 	    char s[64];
 
@@ -623,36 +614,32 @@ get_setshow_command_value_string (const
 	}
       break;
     case var_uinteger:
-    case var_zuinteger:
-      {
-	const unsigned int value = var.get<unsigned int> ();
-
-	if (var.type () == var_uinteger
-	    && value == UINT_MAX)
-	  stb.puts ("unlimited");
-	else
-	  stb.printf ("%u", value);
-      }
-      break;
     case var_integer:
-    case var_zinteger:
+    case var_pinteger:
       {
-	const int value = var.get<int> ();
+	bool printed = false;
+	const LONGEST value
+	  = (var.type () == var_uinteger
+	     ? static_cast<LONGEST> (var.get<unsigned int> ())
+	     : static_cast<LONGEST> (var.get<int> ()));
 
-	if (var.type () == var_integer
-	    && value == INT_MAX)
-	  stb.puts ("unlimited");
-	else
-	  stb.printf ("%d", value);
-      }
-      break;
-    case var_zuinteger_unlimited:
-      {
-	const int value = var.get<int> ();
-	if (value == -1)
-	  stb.puts ("unlimited");
-	else
-	  stb.printf ("%d", value);
+	if (var.extra_literals () != nullptr)
+	  for (const literal_def *l = var.extra_literals ();
+	       l->literal != nullptr;
+	       l++)
+	    if (value == l->use)
+	      {
+		stb.puts (l->literal);
+		printed = true;
+		break;
+	      }
+	if (!printed)
+	  {
+	    if (var.type () == var_uinteger)
+	      stb.printf ("%u", static_cast<unsigned int> (value));
+	    else
+	      stb.printf ("%d", static_cast<int> (value));
+	  }
       }
       break;
     default:
Index: src/gdb/cli/cli-setshow.h
===================================================================
--- src.orig/gdb/cli/cli-setshow.h
+++ src/gdb/cli/cli-setshow.h
@@ -29,21 +29,19 @@ extern int parse_cli_boolean_value (cons
    past a successfully parsed value.  */
 extern int parse_cli_boolean_value (const char **arg);
 
-/* Parse ARG, an option to a var_uinteger or var_zuinteger variable.
-   Either returns the parsed value on success or throws an error.  If
-   EXPRESSION is true, *ARG is parsed as an expression; otherwise, it
-   is parsed with get_ulongest.  It's not possible to parse the
+/* Parse ARG, an option to a var_uinteger, var_integer or var_pinteger
+   variable.  Return the parsed value on success or throw an error.  If
+   EXTRA_LITERALS is non-null, then interpret those literals accordingly.
+   If EXPRESSION is true, *ARG is parsed as an expression; otherwise,
+   it is parsed with get_ulongest.  It's not possible to parse the
    integer as an expression when there may be valid input after the
    integer, such as when parsing command options.  E.g., "print
    -elements NUMBER -obj --".  In such case, parsing as an expression
    would parse "-obj --" as part of the expression as well.  */
-extern unsigned int parse_cli_var_uinteger (var_types var_type,
-					    const char **arg,
-					    bool expression);
-
-/* Like parse_cli_var_uinteger, for var_zuinteger_unlimited.  */
-extern int parse_cli_var_zuinteger_unlimited (const char **arg,
-					      bool expression);
+extern LONGEST parse_cli_var_integer (var_types var_type,
+				      const literal_def *extra_literals,
+				      const char **arg,
+				      bool expression);
 
 /* Parse ARG, an option to a var_enum variable.  ENUM is a
    null-terminated array of possible values. Either returns the parsed
Index: src/gdb/command.h
===================================================================
--- src.orig/gdb/command.h
+++ src/gdb/command.h
@@ -84,16 +84,18 @@ enum var_types
        value.  */
     var_auto_boolean,
 
-    /* Unsigned Integer.  *VAR is an unsigned int.  The user can type
-       0 to mean "unlimited", which is stored in *VAR as UINT_MAX.  */
+    /* Unsigned Integer.  *VAR is an unsigned int.  In the Guile and Python
+       APIs 0 means unlimited, which is stored in *VAR as UINT_MAX.  */
     var_uinteger,
 
-    /* Like var_uinteger but signed.  *VAR is an int.  The user can
-       type 0 to mean "unlimited", which is stored in *VAR as
-       INT_MAX.  The only remaining use of it is the Python API.
-       Don't use it elsewhere.  */
+    /* Like var_uinteger but signed.  *VAR is an int.  In the Guile and
+       Python APIs 0 means unlimited, which is stored in *VAR as INT_MAX.  */
     var_integer,
 
+    /* Like var_integer but negative numbers are not allowed,
+       except for special values.  *VAR is an int.  */
+    var_pinteger,
+
     /* String which the user enters with escapes (e.g. the user types
        \n and it is a real newline in the stored string).
        *VAR is a std::string, "" if the string is empty.  */
@@ -106,22 +108,27 @@ enum var_types
     var_optional_filename,
     /* String which stores a filename.  (*VAR) is a std::string.  */
     var_filename,
-    /* ZeroableInteger.  *VAR is an int.  Like var_integer except
-       that zero really means zero.  */
-    var_zinteger,
-    /* ZeroableUnsignedInteger.  *VAR is an unsigned int.  Zero really
-       means zero.  */
-    var_zuinteger,
-    /* ZeroableUnsignedInteger with unlimited value.  *VAR is an int,
-       but its range is [0, INT_MAX].  -1 stands for unlimited and
-       other negative numbers are not allowed.  */
-    var_zuinteger_unlimited,
     /* Enumerated type.  Can only have one of the specified values.
        *VAR is a char pointer to the name of the element that we
        find.  */
     var_enum
   };
 
+/* A structure describing an extra literal accepted and shown in place
+   of a number.  */
+struct literal_def
+{
+  /* The literal to define, e.g. "unlimited".  */
+  const char *literal;
+
+  /* The number to substitute internally for LITERAL or VAL;
+     the use of this number is not allowed (unless the same as VAL).  */
+  LONGEST use;
+
+  /* An optional number accepted that stands for the literal.  */
+  gdb::optional<LONGEST> val;
+};
+
 /* Return true if a setting of type VAR_TYPE is backed with type T.
 
    This function is left without definition intentionally.  This template is
@@ -152,15 +159,14 @@ inline bool var_type_uses<enum auto_bool
 template<>
 inline bool var_type_uses<unsigned int> (var_types t)
 {
-  return (t == var_uinteger || t == var_zinteger || t == var_zuinteger);
+  return t == var_uinteger;
 }
 
 /* Return true if a setting of type T is backed by an int variable.  */
 template<>
 inline bool var_type_uses<int> (var_types t)
 {
-  return (t == var_integer || t == var_zinteger
-	  || t == var_zuinteger_unlimited);
+  return t == var_integer || t == var_pinteger;
 }
 
 /* Return true if a setting of type T is backed by a std::string variable.  */
@@ -218,8 +224,9 @@ struct setting
 
      Type T must match the var type VAR_TYPE (see VAR_TYPE_USES).  */
   template<typename T>
-  setting (var_types var_type, T *var)
-    : m_var_type (var_type), m_var (var)
+  setting (var_types var_type, T *var,
+	   const literal_def *extra_literals = nullptr)
+    : m_var_type (var_type), m_var (var), m_extra_literals (extra_literals)
   {
     gdb_assert (var != nullptr);
     gdb_assert (var_type_uses<T> (var_type));
@@ -258,12 +265,14 @@ struct setting
     };
   }
 
-  /* Create a setting backed by pre-validated type-erased args.
-     ERASED_VAR's fields' real types must match the var type VAR_TYPE
-     (see VAR_TYPE_USES).  */
-  setting (var_types var_type, const erased_args &args)
+  /* Create a setting backed by pre-validated type-erased args and using
+     EXTRA_LITERALS.  ERASED_VAR's fields' real types must match the var
+     type VAR_TYPE (see VAR_TYPE_USES).  */
+  setting (var_types var_type, const literal_def *extra_literals,
+	   const erased_args &args)
     : m_var_type (var_type),
       m_var (args.var),
+      m_extra_literals (extra_literals),
       m_getter (args.getter),
       m_setter (args.setter)
   {
@@ -294,6 +303,10 @@ struct setting
   var_types type () const
   { return m_var_type; }
 
+  /* Access any extra literals accepted.  */
+  const literal_def *extra_literals () const
+  { return m_extra_literals; }
+
   /* Return the current value.
 
      The template parameter T is the type of the variable used to store the
@@ -356,6 +369,9 @@ struct setting
      non-nullptr.  */
   void *m_var = nullptr;
 
+  /* Any extra literals accepted.  */
+  const literal_def *m_extra_literals = nullptr;
+
   /* Pointer to a user provided getter.  */
   erased_func m_getter = nullptr;
 
@@ -651,6 +667,11 @@ typedef void (show_value_ftype) (struct
    instead print the value out directly.  */
 extern show_value_ftype deprecated_show_value_hack;
 
+/* Various sets of extra literals accepted.  */
+extern const literal_def integer_unlimited_literals[];
+extern const literal_def uinteger_unlimited_literals[];
+extern const literal_def pinteger_unlimited_literals[];
+
 extern set_show_commands add_setshow_enum_cmd
   (const char *name, command_class theclass, const char *const *enumlist,
    const char **var, const char *set_doc, const char *show_doc,
@@ -747,6 +768,20 @@ extern set_show_commands add_setshow_opt
    cmd_list_element **show_list);
 
 extern set_show_commands add_setshow_integer_cmd
+  (const char *name, command_class theclass, int *var,
+   const literal_def *extra_literals, const char *set_doc,
+   const char *show_doc, const char *help_doc, cmd_func_ftype *set_func,
+   show_value_ftype *show_func, cmd_list_element **set_list,
+   cmd_list_element **show_list);
+
+extern set_show_commands add_setshow_integer_cmd
+  (const char *name, command_class theclass, const literal_def *extra_literals,
+   const char *set_doc, const char *show_doc, const char *help_doc,
+   setting_func_types<int>::set set_func,
+   setting_func_types<int>::get get_func, show_value_ftype *show_func,
+   cmd_list_element **set_list, cmd_list_element **show_list);
+
+extern set_show_commands add_setshow_integer_cmd
   (const char *name, command_class theclass, int *var, const char *set_doc,
    const char *show_doc, const char *help_doc, cmd_func_ftype *set_func,
    show_value_ftype *show_func, cmd_list_element **set_list,
@@ -759,6 +794,34 @@ extern set_show_commands add_setshow_int
    setting_func_types<int>::get get_func, show_value_ftype *show_func,
    cmd_list_element **set_list, cmd_list_element **show_list);
 
+extern set_show_commands add_setshow_pinteger_cmd
+  (const char *name, command_class theclass, int *var,
+   const literal_def *extra_literals, const char *set_doc,
+   const char *show_doc, const char *help_doc, cmd_func_ftype *set_func,
+   show_value_ftype *show_func, cmd_list_element **set_list,
+   cmd_list_element **show_list);
+
+extern set_show_commands add_setshow_pinteger_cmd
+  (const char *name, command_class theclass, const literal_def *extra_literals,
+   const char *set_doc, const char *show_doc, const char *help_doc,
+   setting_func_types<int>::set set_func,
+   setting_func_types<int>::get get_func, show_value_ftype *show_func,
+   cmd_list_element **set_list, cmd_list_element **show_list);
+
+extern set_show_commands add_setshow_uinteger_cmd
+  (const char *name, command_class theclass, unsigned int *var,
+   const literal_def *extra_literals,
+   const char *set_doc, const char *show_doc, const char *help_doc,
+   cmd_func_ftype *set_func, show_value_ftype *show_func,
+   cmd_list_element **set_list, cmd_list_element **show_list);
+
+extern set_show_commands add_setshow_uinteger_cmd
+  (const char *name, command_class theclass, const literal_def *extra_literals,
+   const char *set_doc, const char *show_doc, const char *help_doc,
+   setting_func_types<unsigned int>::set set_func,
+   setting_func_types<unsigned int>::get get_func, show_value_ftype *show_func,
+   cmd_list_element **set_list, cmd_list_element **show_list);
+
 extern set_show_commands add_setshow_uinteger_cmd
   (const char *name, command_class theclass, unsigned int *var,
    const char *set_doc, const char *show_doc, const char *help_doc,
Index: src/gdb/doc/python.texi
===================================================================
--- src.orig/gdb/doc/python.texi
+++ src/gdb/doc/python.texi
@@ -4611,14 +4611,18 @@ Python, true and false are represented u
 @findex PARAM_UINTEGER
 @findex gdb.PARAM_UINTEGER
 @item gdb.PARAM_UINTEGER
-The value is an unsigned integer.  The value of 0 should be
-interpreted to mean ``unlimited''.
+The value is an unsigned integer.  The value of @code{None} should be
+interpreted to mean ``unlimited'' (literal @code{'unlimited'} can also
+be used to set that value), and the value of 0 is reserved and should
+not be used.
 
 @findex PARAM_INTEGER
 @findex gdb.PARAM_INTEGER
 @item gdb.PARAM_INTEGER
-The value is a signed integer.  The value of 0 should be interpreted
-to mean ``unlimited''.
+The value is a signed integer.  The value of @code{None} should be
+interpreted to mean ``unlimited'' (literal @code{'unlimited'} can also
+be used to set that value), and the value of 0 is reserved and should
+not be used.
 
 @findex PARAM_STRING
 @findex gdb.PARAM_STRING
@@ -4648,21 +4652,23 @@ The value is a filename.  This is just l
 @findex PARAM_ZINTEGER
 @findex gdb.PARAM_ZINTEGER
 @item gdb.PARAM_ZINTEGER
-The value is an integer.  This is like @code{PARAM_INTEGER}, except 0
-is interpreted as itself.
+The value is a signed integer.  This is like @code{PARAM_INTEGER},
+except that 0 is allowed and the value of @code{None} is not supported.
 
 @findex PARAM_ZUINTEGER
 @findex gdb.PARAM_ZUINTEGER
 @item gdb.PARAM_ZUINTEGER
-The value is an unsigned integer.  This is like @code{PARAM_INTEGER},
-except 0 is interpreted as itself, and the value cannot be negative.
+The value is an unsigned integer.  This is like @code{PARAM_UINTEGER},
+except that 0 is allowed and the value of @code{None} is not supported.
 
 @findex PARAM_ZUINTEGER_UNLIMITED
 @findex gdb.PARAM_ZUINTEGER_UNLIMITED
 @item gdb.PARAM_ZUINTEGER_UNLIMITED
-The value is a signed integer.  This is like @code{PARAM_ZUINTEGER},
-except the special value -1 should be interpreted to mean
-``unlimited''.  Other negative values are not allowed.
+The value is a signed integer.  This is like @code{PARAM_INTEGER}
+including that the value of @code{None} should be interpreted to mean
+``unlimited'' (literal @code{'unlimited'} can also be used to set that
+value), except that 0 is allowed, and the value cannot be negative,
+except the special value -1 is returned for the setting of ``unlimited''.
 
 @findex PARAM_ENUM
 @findex gdb.PARAM_ENUM
Index: src/gdb/guile/scm-param.c
===================================================================
--- src.orig/gdb/guile/scm-param.c
+++ src/gdb/guile/scm-param.c
@@ -75,9 +75,15 @@ struct param_smob
   /* One of the COMMAND_* constants.  */
   enum command_class cmd_class;
 
+  /* Guile parameter type name.  */
+  const char *pname;
+
   /* The type of the parameter.  */
   enum var_types type;
 
+  /* Extra literals, such as `unlimited', accepted in lieu of a number.  */
+  const literal_def *extra_literals;
+
   /* The docs for the parameter.  */
   char *set_doc;
   char *show_doc;
@@ -110,6 +116,49 @@ struct param_smob
   SCM containing_scm;
 };
 
+/* Guile parameter types as in PARAMETER_TYPES later on.  */
+
+enum param_types
+{
+  param_boolean,
+  param_auto_boolean,
+  param_zinteger,
+  param_uinteger,
+  param_zuinteger,
+  param_zuinteger_unlimited,
+  param_string,
+  param_string_noescape,
+  param_optional_filename,
+  param_filename,
+  param_enum,
+};
+
+/* Translation from Guile parameters to GDB variable types.  Keep in the
+   same order as PARAM_TYPES due to C++'s lack of designated initializers.  */
+
+static const struct
+{
+  /* The type of the parameter.  */
+  enum var_types type;
+
+  /* Extra literals, such as `unlimited', accepted in lieu of a number.  */
+  const literal_def *extra_literals;
+}
+param_to_var[] =
+{
+  { var_boolean },
+  { var_auto_boolean },
+  { var_integer },
+  { var_uinteger, uinteger_unlimited_literals },
+  { var_uinteger },
+  { var_pinteger, pinteger_unlimited_literals },
+  { var_string },
+  { var_string_noescape },
+  { var_optional_filename },
+  { var_filename },
+  { var_enum }
+};
+
 /* Wraps a setting around an existing param_smob.  This abstraction
    is used to manipulate the value in S->VALUE in a type safe manner using
    the setting interface.  */
@@ -117,18 +166,20 @@ struct param_smob
 static setting
 make_setting (param_smob *s)
 {
-  if (var_type_uses<bool> (s->type))
-    return setting (s->type, &s->value.boolval);
-  else if (var_type_uses<int> (s->type))
-    return setting (s->type, &s->value.intval);
-  else if (var_type_uses<auto_boolean> (s->type))
-    return setting (s->type, &s->value.autoboolval);
-  else if (var_type_uses<unsigned int> (s->type))
-    return setting (s->type, &s->value.uintval);
-  else if (var_type_uses<std::string> (s->type))
-    return setting (s->type, s->value.stringval);
-  else if (var_type_uses<const char *> (s->type))
-    return setting (s->type, &s->value.cstringval);
+  enum var_types type = s->type;
+
+  if (var_type_uses<bool> (type))
+    return setting (type, &s->value.boolval);
+  else if (var_type_uses<int> (type))
+    return setting (type, &s->value.intval, s->extra_literals);
+  else if (var_type_uses<auto_boolean> (type))
+    return setting (type, &s->value.autoboolval);
+  else if (var_type_uses<unsigned int> (type))
+    return setting (type, &s->value.uintval, s->extra_literals);
+  else if (var_type_uses<std::string> (type))
+    return setting (type, s->value.stringval);
+  else if (var_type_uses<const char *> (type))
+    return setting (type, &s->value.cstringval);
   else
     gdb_assert_not_reached ("unhandled var type");
 }
@@ -149,10 +200,9 @@ static SCM set_doc_keyword;
 static SCM show_doc_keyword;
 static SCM initial_value_keyword;
 static SCM auto_keyword;
-static SCM unlimited_keyword;
 
 static int pascm_is_valid (param_smob *);
-static const char *pascm_param_type_name (enum var_types type);
+static const char *pascm_param_type_name (enum param_types type);
 static SCM pascm_param_value (const setting &var, int arg_pos,
 			      const char *func_name);
 
@@ -171,7 +221,7 @@ pascm_print_param_smob (SCM self, SCM po
   if (! pascm_is_valid (p_smob))
     scm_puts (" {invalid}", port);
 
-  gdbscm_printf (port, " %s ", pascm_param_type_name (p_smob->type));
+  gdbscm_printf (port, " %s ", p_smob->pname);
 
   value = pascm_param_value (make_setting (p_smob), GDBSCM_ARG_NONE, NULL);
   scm_display (value, port);
@@ -369,7 +419,9 @@ pascm_show_func (struct ui_file *file, i
    function.  */
 
 static set_show_commands
-add_setshow_generic (enum var_types param_type, enum command_class cmd_class,
+add_setshow_generic (enum var_types param_type,
+		     const literal_def *extra_literals,
+		     enum command_class cmd_class,
 		     char *cmd_name, param_smob *self,
 		     char *set_doc, char *show_doc, char *help_doc,
 		     cmd_func_ftype *set_func,
@@ -398,32 +450,26 @@ add_setshow_generic (enum var_types para
 
     case var_uinteger:
       commands = add_setshow_uinteger_cmd (cmd_name, cmd_class,
-					   &self->value.uintval, set_doc,
-					   show_doc, help_doc, set_func,
-					   show_func, set_list, show_list);
-      break;
-
-    case var_zinteger:
-      commands = add_setshow_zinteger_cmd (cmd_name, cmd_class,
-					   &self->value.intval, set_doc,
+					   &self->value.uintval,
+					   extra_literals, set_doc,
 					   show_doc, help_doc, set_func,
 					   show_func, set_list, show_list);
       break;
 
-    case var_zuinteger:
-      commands = add_setshow_zuinteger_cmd (cmd_name, cmd_class,
-					    &self->value.uintval, set_doc,
-					    show_doc, help_doc, set_func,
-					    show_func, set_list, show_list);
+    case var_integer:
+      commands = add_setshow_integer_cmd (cmd_name, cmd_class,
+					  &self->value.intval,
+					  extra_literals, set_doc,
+					  show_doc, help_doc, set_func,
+					  show_func, set_list, show_list);
       break;
 
-    case var_zuinteger_unlimited:
-      commands = add_setshow_zuinteger_unlimited_cmd (cmd_name, cmd_class,
-						      &self->value.intval,
-						      set_doc, show_doc,
-						      help_doc, set_func,
-						      show_func, set_list,
-						      show_list);
+    case var_pinteger:
+      commands = add_setshow_pinteger_cmd (cmd_name, cmd_class,
+					   &self->value.intval,
+					   extra_literals, set_doc,
+					   show_doc, help_doc, set_func,
+					   show_func, set_list, show_list);
       break;
 
     case var_string:
@@ -532,19 +578,17 @@ compute_enum_list (SCM enum_values_scm,
 
 static const scheme_integer_constant parameter_types[] =
 {
-  /* Note: var_integer is deprecated, and intentionally does not
-     appear here.  */
-  { "PARAM_BOOLEAN", var_boolean }, /* ARI: var_boolean */
-  { "PARAM_AUTO_BOOLEAN", var_auto_boolean },
-  { "PARAM_ZINTEGER", var_zinteger },
-  { "PARAM_UINTEGER", var_uinteger },
-  { "PARAM_ZUINTEGER", var_zuinteger },
-  { "PARAM_ZUINTEGER_UNLIMITED", var_zuinteger_unlimited },
-  { "PARAM_STRING", var_string },
-  { "PARAM_STRING_NOESCAPE", var_string_noescape },
-  { "PARAM_OPTIONAL_FILENAME", var_optional_filename },
-  { "PARAM_FILENAME", var_filename },
-  { "PARAM_ENUM", var_enum },
+  { "PARAM_BOOLEAN", param_boolean }, /* ARI: param_boolean */
+  { "PARAM_AUTO_BOOLEAN", param_auto_boolean },
+  { "PARAM_ZINTEGER", param_zinteger },
+  { "PARAM_UINTEGER", param_uinteger },
+  { "PARAM_ZUINTEGER", param_zuinteger },
+  { "PARAM_ZUINTEGER_UNLIMITED", param_zuinteger_unlimited },
+  { "PARAM_STRING", param_string },
+  { "PARAM_STRING_NOESCAPE", param_string_noescape },
+  { "PARAM_OPTIONAL_FILENAME", param_optional_filename },
+  { "PARAM_FILENAME", param_filename },
+  { "PARAM_ENUM", param_enum },
 
   END_INTEGER_CONSTANTS
 };
@@ -568,7 +612,7 @@ pascm_valid_parameter_type_p (int param_
 /* Return PARAM_TYPE as a string.  */
 
 static const char *
-pascm_param_type_name (enum var_types param_type)
+pascm_param_type_name (enum param_types param_type)
 {
   int i;
 
@@ -588,10 +632,6 @@ pascm_param_type_name (enum var_types pa
 static SCM
 pascm_param_value (const setting &var, int arg_pos, const char *func_name)
 {
-  /* Note: We *could* support var_integer here in case someone is trying to get
-     the value of a Python-created parameter (which is the only place that
-     still supports var_integer).  To further discourage its use we do not.  */
-
   switch (var.type ())
     {
     case var_string:
@@ -631,20 +671,29 @@ pascm_param_value (const setting &var, i
 	  return auto_keyword;
       }
 
-    case var_zuinteger_unlimited:
-      if (var.get<int> () == -1)
-	return unlimited_keyword;
-      gdb_assert (var.get<int> () >= 0);
-      /* Fall through.  */
-    case var_zinteger:
-      return scm_from_int (var.get<int> ());
-
     case var_uinteger:
-      if (var.get<unsigned int> ()== UINT_MAX)
-	return unlimited_keyword;
-      /* Fall through.  */
-    case var_zuinteger:
-      return scm_from_uint (var.get<unsigned int> ());
+    case var_integer:
+    case var_pinteger:
+      {
+	LONGEST value
+	  = (var.type () == var_uinteger
+	     ? static_cast<LONGEST> (var.get<unsigned int> ())
+	     : static_cast<LONGEST> (var.get<int> ()));
+
+	if (var.extra_literals () != nullptr)
+	  for (const literal_def *l = var.extra_literals ();
+	       l->literal != nullptr;
+	       l++)
+	    if (value == l->use)
+	      return scm_from_latin1_keyword (l->literal);
+	if (var.type () == var_pinteger)
+	  gdb_assert (value >= 0);
+
+	if (var.type () == var_uinteger)
+	  return scm_from_uint (static_cast<unsigned int> (value));
+	else
+	  return scm_from_int (static_cast<int> (value));
+      }
 
     default:
       break;
@@ -735,53 +784,91 @@ pascm_set_param_value_x (param_smob *p_s
 	var.set<enum auto_boolean> (AUTO_BOOLEAN_FALSE);
       break;
 
-    case var_zinteger:
+    case var_integer:
     case var_uinteger:
-    case var_zuinteger:
-    case var_zuinteger_unlimited:
-      if (var.type () == var_uinteger
-	  || var.type () == var_zuinteger_unlimited)
-	{
-	  SCM_ASSERT_TYPE (scm_is_integer (value)
-			   || scm_is_eq (value, unlimited_keyword),
-			   value, arg_pos, func_name,
-			   _("integer or #:unlimited"));
-	  if (scm_is_eq (value, unlimited_keyword))
+    case var_pinteger:
+      {
+	const literal_def *extra_literals = p_smob->extra_literals;
+	enum tribool allowed = TRIBOOL_UNKNOWN;
+	enum var_types var_type = var.type ();
+	bool integer = scm_is_integer (value);
+	bool keyword = scm_is_keyword (value);
+	std::string buffer = "";
+	size_t count = 0;
+	LONGEST val;
+
+	if (extra_literals != nullptr)
+	  for (const literal_def *l = extra_literals;
+	       l->literal != nullptr;
+	       l++, count++)
 	    {
-	      if (var.type () == var_uinteger)
-		var.set<unsigned int> (UINT_MAX);
-	      else
-		var.set<int> (-1);
-	      break;
+	      if (count != 0)
+		buffer += ", ";
+	      buffer = buffer + "#:" + l->literal;
+	      if (keyword
+		  && allowed == TRIBOOL_UNKNOWN
+		  && scm_is_eq (value,
+				scm_from_latin1_keyword (l->literal)))
+		{
+		  val = l->use;
+		  allowed = TRIBOOL_TRUE;
+		}
 	    }
-	}
-      else
-	{
-	  SCM_ASSERT_TYPE (scm_is_integer (value), value, arg_pos, func_name,
-			   _("integer"));
-	}
 
-      if (var.type () == var_uinteger
-	  || var.type () == var_zuinteger)
-	{
-	  unsigned int u = scm_to_uint (value);
+	if (allowed == TRIBOOL_UNKNOWN)
+	  {
+	    if (extra_literals == nullptr)
+	      SCM_ASSERT_TYPE (integer, value, arg_pos, func_name,
+			       _("integer"));
+	    else if (count > 1)
+	      SCM_ASSERT_TYPE (integer, value, arg_pos, func_name,
+			       string_printf (_("integer or one of: %s"),
+					      buffer.c_str ()).c_str ());
+	    else
+	      SCM_ASSERT_TYPE (integer, value, arg_pos, func_name,
+			       string_printf (_("integer or %s"),
+					      buffer.c_str ()).c_str ());
 
-	  if (var.type () == var_uinteger && u == 0)
-	    u = UINT_MAX;
-	  var.set<unsigned int> (u);
-	}
-      else
-	{
-	  int i = scm_to_int (value);
+	    val = (var_type == var_uinteger
+		   ? static_cast<LONGEST> (scm_to_uint (value))
+		   : static_cast<LONGEST> (scm_to_int (value)));
 
-	  if (var.type () == var_zuinteger_unlimited && i < -1)
-	    {
-	      gdbscm_out_of_range_error (func_name, arg_pos, value,
-					 _("must be >= -1"));
+	    if (extra_literals != nullptr)
+	      for (const literal_def *l = extra_literals;
+		   l->literal != nullptr;
+		   l++)
+		{
+		  if (l->val.has_value () && val == *l->val)
+		    {
+		      allowed = TRIBOOL_TRUE;
+		      val = l->use;
+		      break;
+		    }
+		  else if (val == l->use)
+		    allowed = TRIBOOL_FALSE;
+		}
 	    }
-	  var.set<int> (i);
-	}
-      break;
+
+	if (allowed == TRIBOOL_UNKNOWN)
+	  {
+	    if (val > UINT_MAX || val < INT_MIN
+		|| (var_type == var_uinteger && val < 0)
+		|| (var_type == var_integer && val > INT_MAX)
+		|| (var_type == var_pinteger && val < 0)
+		|| (var_type == var_pinteger && val > INT_MAX))
+	      allowed = TRIBOOL_FALSE;
+	  }
+	if (allowed == TRIBOOL_FALSE)
+	  gdbscm_out_of_range_error (func_name, arg_pos, value,
+				     _("integer out of range"));
+
+	if (var_type == var_uinteger)
+	  var.set<unsigned int> (static_cast<unsigned int> (val));
+	else
+	  var.set<int> (static_cast<int> (val));
+
+	break;
+      }
 
     default:
       gdb_assert_not_reached ("bad parameter type");
@@ -858,7 +945,7 @@ gdbscm_make_parameter (SCM name_scm, SCM
   char *s;
   char *name;
   int cmd_class = no_class;
-  int param_type = var_boolean; /* ARI: var_boolean */
+  int param_type = param_boolean; /* ARI: param_boolean */
   SCM enum_list_scm = SCM_BOOL_F;
   SCM set_func = SCM_BOOL_F, show_func = SCM_BOOL_F;
   char *doc = NULL, *set_doc = NULL, *show_doc = NULL;
@@ -913,12 +1000,12 @@ gdbscm_make_parameter (SCM name_scm, SCM
 				 scm_from_int (param_type),
 				 _("invalid parameter type argument"));
     }
-  if (enum_list_arg_pos > 0 && param_type != var_enum)
+  if (enum_list_arg_pos > 0 && param_type != param_enum)
     {
       gdbscm_misc_error (FUNC_NAME, enum_list_arg_pos, enum_list_scm,
 		_("#:enum-values can only be provided with PARAM_ENUM"));
     }
-  if (enum_list_arg_pos < 0 && param_type == var_enum)
+  if (enum_list_arg_pos < 0 && param_type == param_enum)
     {
       gdbscm_misc_error (FUNC_NAME, GDBSCM_ARG_NONE, SCM_BOOL_F,
 			 _("PARAM_ENUM requires an enum-values argument"));
@@ -933,7 +1020,7 @@ gdbscm_make_parameter (SCM name_scm, SCM
       SCM_ASSERT_TYPE (gdbscm_is_procedure (show_func), show_func,
 		       show_func_arg_pos, FUNC_NAME, _("procedure"));
     }
-  if (param_type == var_enum)
+  if (param_type == param_enum)
     {
       /* Note: enum_list lives in GC space, so we don't have to worry about
 	 freeing it if we later throw an exception.  */
@@ -950,7 +1037,10 @@ gdbscm_make_parameter (SCM name_scm, SCM
      freeing them if we throw an exception.  */
   p_smob->name = name;
   p_smob->cmd_class = (enum command_class) cmd_class;
-  p_smob->type = (enum var_types) param_type;
+  p_smob->pname
+    = pascm_param_type_name (static_cast<enum param_types> (param_type));
+  p_smob->type = param_to_var[param_type].type;
+  p_smob->extra_literals = param_to_var[param_type].extra_literals;
   p_smob->doc = doc;
   p_smob->set_doc = set_doc;
   p_smob->show_doc = show_doc;
@@ -1031,7 +1121,8 @@ gdbscm_register_parameter_x (SCM self)
   try
     {
       p_smob->commands = add_setshow_generic
-	(p_smob->type, p_smob->cmd_class, p_smob->cmd_name, p_smob,
+	(p_smob->type, p_smob->extra_literals,
+	 p_smob->cmd_class, p_smob->cmd_name, p_smob,
 	 p_smob->set_doc, p_smob->show_doc, p_smob->doc,
 	 (gdbscm_is_procedure (p_smob->set_func) ? pascm_set_func : NULL),
 	 (gdbscm_is_procedure (p_smob->show_func) ? pascm_show_func : NULL),
@@ -1203,5 +1294,4 @@ gdbscm_initialize_parameters (void)
   show_doc_keyword = scm_from_latin1_keyword ("show-doc");
   initial_value_keyword = scm_from_latin1_keyword ("initial-value");
   auto_keyword = scm_from_latin1_keyword ("auto");
-  unlimited_keyword = scm_from_latin1_keyword ("unlimited");
 }
Index: src/gdb/maint-test-options.c
===================================================================
--- src.orig/gdb/maint-test-options.c
+++ src/gdb/maint-test-options.c
@@ -61,13 +61,15 @@
    available kinds of commands (boolean, enum, flag, string, uinteger):
 
     (gdb) maint test-options require-delimiter -[TAB]
-    -bool      -enum      -flag      -string     -uinteger   -xx1       -xx2
+    -bool                -pinteger-unlimited  -xx1
+    -enum                -string              -xx2
+    -flag                -uinteger-unlimited
 
     (gdb) maint test-options require-delimiter -bool o[TAB]
     off  on
     (gdb) maint test-options require-delimiter -enum [TAB]
     xxx  yyy  zzz
-    (gdb) maint test-options require-delimiter -uinteger [TAB]
+    (gdb) maint test-options require-delimiter -uinteger-unlimited [TAB]
     NUMBER     unlimited
 
    '-xx1' and '-xx2' are flag options too.  They exist in order to
@@ -76,14 +78,14 @@
   Invoking the commands makes them print out the options parsed:
 
    (gdb) maint test-options unknown-is-error -flag -enum yyy cmdarg
-   -flag 1 -xx1 0 -xx2 0 -bool 0 -enum yyy -uint 0 -zuint-unl 0 -- cmdarg
+   -flag 1 -xx1 0 -xx2 0 -bool 0 -enum yyy -uint-unl 0 -pint-unl 0 -string '' -- cmdarg
 
    (gdb) maint test-options require-delimiter -flag -enum yyy cmdarg
-   -flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint 0  -zuint-unl 0 -- -flag -enum yyy cmdarg
+   -flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl 0 -pint-unl 0 -string '' -- -flag -enum yyy cmdarg
    (gdb) maint test-options require-delimiter -flag -enum yyy cmdarg --
    Unrecognized option at: cmdarg --
    (gdb) maint test-options require-delimiter -flag -enum yyy -- cmdarg
-   -flag 1 -xx1 0 -xx2 0 -bool 0 -enum yyy -uint 0 -zuint-unl 0 -- cmdarg
+   -flag 1 -xx1 0 -xx2 0 -bool 0 -enum yyy -uint-unl 0 -pint-unl 0 -string '' -- cmdarg
 
   The "maint show test-options-completion-result" command exists in
   order to do something similar for completion:
@@ -131,8 +133,8 @@ struct test_options_opts
   bool xx2_opt = false;
   bool boolean_opt = false;
   const char *enum_opt = test_options_enum_values_xxx;
-  unsigned int uint_opt = 0;
-  int zuint_unl_opt = 0;
+  unsigned int uint_unl_opt = 0;
+  int pint_unl_opt = 0;
   std::string string_opt;
 
   test_options_opts () = default;
@@ -145,18 +147,18 @@ struct test_options_opts
   {
     gdb_printf (file,
 		_("-flag %d -xx1 %d -xx2 %d -bool %d "
-		  "-enum %s -uint %s -zuint-unl %s -string '%s' -- %s\n"),
+		  "-enum %s -uint-unl %s -pint-unl %s -string '%s' -- %s\n"),
 		flag_opt,
 		xx1_opt,
 		xx2_opt,
 		boolean_opt,
 		enum_opt,
-		(uint_opt == UINT_MAX
+		(uint_unl_opt == UINT_MAX
 		 ? "unlimited"
-		 : pulongest (uint_opt)),
-		(zuint_unl_opt == -1
+		 : pulongest (uint_unl_opt)),
+		(pint_unl_opt == -1
 		 ? "unlimited"
-		 : plongest (zuint_unl_opt)),
+		 : plongest (pint_unl_opt)),
 		string_opt.c_str (),
 		args);
   }
@@ -203,22 +205,24 @@ static const gdb::option::option_def tes
     N_("An enum option."),
   },
 
-  /* A uinteger option.  */
+  /* A uinteger + "unlimited" option.  */
   gdb::option::uinteger_option_def<test_options_opts> {
-    "uinteger",
-    [] (test_options_opts *opts) { return &opts->uint_opt; },
+    "uinteger-unlimited",
+    [] (test_options_opts *opts) { return &opts->uint_unl_opt; },
+    uinteger_unlimited_literals,
     nullptr, /* show_cmd_cb */
     N_("A uinteger option."),
     nullptr, /* show_doc */
     N_("A help doc that spawns\nmultiple lines."),
   },
 
-  /* A zuinteger_unlimited option.  */
-  gdb::option::zuinteger_unlimited_option_def<test_options_opts> {
-    "zuinteger-unlimited",
-    [] (test_options_opts *opts) { return &opts->zuint_unl_opt; },
+  /* A pinteger + "unlimited" option.  */
+  gdb::option::pinteger_option_def<test_options_opts> {
+    "pinteger-unlimited",
+    [] (test_options_opts *opts) { return &opts->pint_unl_opt; },
+    pinteger_unlimited_literals,
     nullptr, /* show_cmd_cb */
-    N_("A zuinteger-unlimited option."),
+    N_("A pinteger-unlimited option."),
     nullptr, /* show_doc */
     nullptr, /* help_doc */
   },
Index: src/gdb/python/py-param.c
===================================================================
--- src.orig/gdb/python/py-param.c
+++ src/gdb/python/py-param.c
@@ -28,24 +28,70 @@
 #include "language.h"
 #include "arch-utils.h"
 
+/* Python parameter types as in PARM_CONSTANTS below.  */
+
+enum param_types
+{
+  param_boolean,
+  param_auto_boolean,
+  param_uinteger,
+  param_integer,
+  param_string,
+  param_string_noescape,
+  param_optional_filename,
+  param_filename,
+  param_zinteger,
+  param_zuinteger,
+  param_zuinteger_unlimited,
+  param_enum,
+}
+param_types;
+
+/* Translation from Python parameters to GDB variable types.  Keep in the
+   same order as PARAM_TYPES due to C++'s lack of designated initializers.  */
+
+static const struct
+{
+  /* The type of the parameter.  */
+  enum var_types type;
+
+  /* Extra literals, such as `unlimited', accepted in lieu of a number.  */
+  const literal_def *extra_literals;
+}
+param_to_var[] =
+{
+  { var_boolean },
+  { var_auto_boolean },
+  { var_uinteger, uinteger_unlimited_literals },
+  { var_integer, integer_unlimited_literals },
+  { var_string },
+  { var_string_noescape },
+  { var_optional_filename },
+  { var_filename },
+  { var_integer },
+  { var_uinteger },
+  { var_pinteger, pinteger_unlimited_literals },
+  { var_enum }
+};
+
 /* Parameter constants and their values.  */
 static struct {
   const char *name;
   int value;
 } parm_constants[] =
 {
-  { "PARAM_BOOLEAN", var_boolean }, /* ARI: var_boolean */
-  { "PARAM_AUTO_BOOLEAN", var_auto_boolean },
-  { "PARAM_UINTEGER", var_uinteger },
-  { "PARAM_INTEGER", var_integer },
-  { "PARAM_STRING", var_string },
-  { "PARAM_STRING_NOESCAPE", var_string_noescape },
-  { "PARAM_OPTIONAL_FILENAME", var_optional_filename },
-  { "PARAM_FILENAME", var_filename },
-  { "PARAM_ZINTEGER", var_zinteger },
-  { "PARAM_ZUINTEGER", var_zuinteger },
-  { "PARAM_ZUINTEGER_UNLIMITED", var_zuinteger_unlimited },
-  { "PARAM_ENUM", var_enum },
+  { "PARAM_BOOLEAN", param_boolean }, /* ARI: param_boolean */
+  { "PARAM_AUTO_BOOLEAN", param_auto_boolean },
+  { "PARAM_UINTEGER", param_uinteger },
+  { "PARAM_INTEGER", param_integer },
+  { "PARAM_STRING", param_string },
+  { "PARAM_STRING_NOESCAPE", param_string_noescape },
+  { "PARAM_OPTIONAL_FILENAME", param_optional_filename },
+  { "PARAM_FILENAME", param_filename },
+  { "PARAM_ZINTEGER", param_zinteger },
+  { "PARAM_ZUINTEGER", param_zuinteger },
+  { "PARAM_ZUINTEGER_UNLIMITED", param_zuinteger_unlimited },
+  { "PARAM_ENUM", param_enum },
   { NULL, 0 }
 };
 
@@ -80,6 +126,9 @@ struct parmpy_object
   /* The type of the parameter.  */
   enum var_types type;
 
+  /* Extra literals, such as `unlimited', accepted in lieu of a number.  */
+  const literal_def *extra_literals;
+
   /* The value of the parameter.  */
   union parmpy_variable value;
 
@@ -96,18 +145,20 @@ struct parmpy_object
 static setting
 make_setting (parmpy_object *s)
 {
-  if (var_type_uses<bool> (s->type))
-    return setting (s->type, &s->value.boolval);
-  else if (var_type_uses<int> (s->type))
-    return setting (s->type, &s->value.intval);
-  else if (var_type_uses<auto_boolean> (s->type))
-    return setting (s->type, &s->value.autoboolval);
-  else if (var_type_uses<unsigned int> (s->type))
-    return setting (s->type, &s->value.uintval);
-  else if (var_type_uses<std::string> (s->type))
-    return setting (s->type, s->value.stringval);
-  else if (var_type_uses<const char *> (s->type))
-    return setting (s->type, &s->value.cstringval);
+  enum var_types type = s->type;
+
+  if (var_type_uses<bool> (type))
+    return setting (type, &s->value.boolval);
+  else if (var_type_uses<int> (type))
+    return setting (type, &s->value.intval, s->extra_literals);
+  else if (var_type_uses<auto_boolean> (type))
+    return setting (type, &s->value.autoboolval);
+  else if (var_type_uses<unsigned int> (type))
+    return setting (type, &s->value.uintval, s->extra_literals);
+  else if (var_type_uses<std::string> (type))
+    return setting (type, s->value.stringval);
+  else if (var_type_uses<const char *> (type))
+    return setting (type, &s->value.cstringval);
   else
     gdb_assert_not_reached ("unhandled var type");
 }
@@ -234,68 +285,98 @@ set_parameter_value (parmpy_object *self
 	}
       break;
 
-    case var_integer:
-    case var_zinteger:
     case var_uinteger:
-    case var_zuinteger:
-    case var_zuinteger_unlimited:
+    case var_integer:
+    case var_pinteger:
       {
-	long l;
-	int ok;
+	const literal_def *extra_literals = self->extra_literals;
+	enum tribool allowed = TRIBOOL_UNKNOWN;
+	enum var_types var_type = self->type;
+	std::string buffer = "";
+	size_t count = 0;
+	LONGEST val;
 
-	if (value == Py_None
-	    && (self->type == var_uinteger || self->type == var_integer))
-	  l = 0;
-	else if (value == Py_None && self->type == var_zuinteger_unlimited)
-	  l = -1;
-	else if (!PyLong_Check (value))
+	if (extra_literals != nullptr)
 	  {
-	    PyErr_SetString (PyExc_RuntimeError,
-			     _("The value must be integer."));
-	    return -1;
+	    gdb::unique_xmalloc_ptr<char>
+	      str (python_string_to_host_string (value));
+	    const char *s = str != nullptr ? str.get () : nullptr;
+	    PyErr_Clear ();
+
+	    for (const literal_def *l = extra_literals;
+		 l->literal != nullptr;
+		 l++, count++)
+	      {
+		if (count != 0)
+		  buffer += ", ";
+		buffer = buffer + "'" + l->literal + "'";
+		if (allowed == TRIBOOL_UNKNOWN
+		    && ((value == Py_None && !strcmp ("unlimited", l->literal))
+			|| (s != nullptr && !strcmp (s, l->literal))))
+		  {
+		    val = l->use;
+		    allowed = TRIBOOL_TRUE;
+		  }
+	      }
 	  }
-	else if (! gdb_py_int_as_long (value, &l))
-	  return -1;
 
-	switch (self->type)
+	if (allowed == TRIBOOL_UNKNOWN)
 	  {
-	  case var_uinteger:
-	    if (l == 0)
-	      l = UINT_MAX;
-	    /* Fall through.  */
-	  case var_zuinteger:
-	    ok = (l >= 0 && l <= UINT_MAX);
-	    break;
+	    val = PyLong_AsLongLong (value);
 
-	  case var_zuinteger_unlimited:
-	    ok = (l >= -1 && l <= INT_MAX);
-	    break;
+	    if (PyErr_Occurred ())
+	      {
+		if (extra_literals == nullptr)
+		  PyErr_SetString (PyExc_RuntimeError,
+				   _("The value must be integer."));
+		else if (count > 1)
+		  PyErr_SetString (PyExc_RuntimeError,
+				   string_printf (_("integer or one of: %s"),
+						  buffer.c_str ()).c_str ());
+		else
+		  PyErr_SetString (PyExc_RuntimeError,
+				   string_printf (_("integer or %s"),
+						  buffer.c_str ()).c_str ());
+		return -1;
+	      }
 
-	  case var_integer:
-	    ok = (l >= INT_MIN && l <= INT_MAX);
-	    if (l == 0)
-	      l = INT_MAX;
-	    break;
 
-	  case var_zinteger:
-	    ok = (l >= INT_MIN && l <= INT_MAX);
-	    break;
+	    if (extra_literals != nullptr)
+	      for (const literal_def *l = extra_literals;
+		   l->literal != nullptr;
+		   l++)
+		{
+		  if (l->val.has_value () && val == *l->val)
+		    {
+		      allowed = TRIBOOL_TRUE;
+		      val = l->use;
+		      break;
+		    }
+		  else if (val == l->use)
+		    allowed = TRIBOOL_FALSE;
+		}
+	    }
 
-	  default:
-	    gdb_assert_not_reached ("unknown var_ constant");
+	if (allowed == TRIBOOL_UNKNOWN)
+	  {
+	    if (val > UINT_MAX || val < INT_MIN
+		|| (var_type == var_uinteger && val < 0)
+		|| (var_type == var_integer && val > INT_MAX)
+		|| (var_type == var_pinteger && val < 0)
+		|| (var_type == var_pinteger && val > INT_MAX))
+	      allowed = TRIBOOL_FALSE;
 	  }
-
-	if (! ok)
+	if (allowed == TRIBOOL_FALSE)
 	  {
 	    PyErr_SetString (PyExc_RuntimeError,
 			     _("Range exceeded."));
 	    return -1;
 	  }
 
-	if (self->type == var_uinteger || self->type == var_zuinteger)
-	  self->value.uintval = (unsigned) l;
+	if (self->type == var_uinteger)
+	  self->value.uintval = (unsigned) val;
 	else
-	  self->value.intval = (int) l;
+	  self->value.intval = (int) val;
 	break;
       }
 
@@ -534,7 +615,8 @@ get_show_value (struct ui_file *file, in
 /* A helper function that dispatches to the appropriate add_setshow
    function.  */
 static void
-add_setshow_generic (int parmclass, enum command_class cmdclass,
+add_setshow_generic (enum var_types type, const literal_def *extra_literals,
+		     enum command_class cmdclass,
 		     gdb::unique_xmalloc_ptr<char> cmd_name,
 		     parmpy_object *self,
 		     const char *set_doc, const char *show_doc,
@@ -544,7 +626,7 @@ add_setshow_generic (int parmclass, enum
 {
   set_show_commands commands;
 
-  switch (parmclass)
+  switch (type)
     {
     case var_boolean:
       commands = add_setshow_boolean_cmd (cmd_name.get (), cmdclass,
@@ -564,18 +646,28 @@ add_setshow_generic (int parmclass, enum
 
     case var_uinteger:
       commands = add_setshow_uinteger_cmd (cmd_name.get (), cmdclass,
-					   &self->value.uintval, set_doc,
+					   &self->value.uintval,
+					   extra_literals, set_doc,
 					   show_doc, help_doc, get_set_value,
 					   get_show_value, set_list, show_list);
       break;
 
     case var_integer:
       commands = add_setshow_integer_cmd (cmd_name.get (), cmdclass,
-					  &self->value.intval, set_doc,
+					  &self->value.intval,
+					  extra_literals, set_doc,
 					  show_doc, help_doc, get_set_value,
 					  get_show_value, set_list, show_list);
       break;
 
+    case var_pinteger:
+      commands = add_setshow_pinteger_cmd (cmd_name.get (), cmdclass,
+					   &self->value.intval,
+					   extra_literals, set_doc,
+					   show_doc, help_doc, get_set_value,
+					   get_show_value, set_list, show_list);
+      break;
+
     case var_string:
       commands = add_setshow_string_cmd (cmd_name.get (), cmdclass,
 					 self->value.stringval, set_doc,
@@ -607,30 +699,6 @@ add_setshow_generic (int parmclass, enum
 					   get_show_value, set_list, show_list);
       break;
 
-    case var_zinteger:
-      commands = add_setshow_zinteger_cmd (cmd_name.get (), cmdclass,
-					   &self->value.intval, set_doc,
-					   show_doc, help_doc, get_set_value,
-					   get_show_value, set_list, show_list);
-      break;
-
-    case var_zuinteger:
-      commands = add_setshow_zuinteger_cmd (cmd_name.get (), cmdclass,
-					    &self->value.uintval, set_doc,
-					    show_doc, help_doc, get_set_value,
-					    get_show_value, set_list,
-					    show_list);
-      break;
-
-    case var_zuinteger_unlimited:
-      commands = add_setshow_zuinteger_unlimited_cmd (cmd_name.get (), cmdclass,
-						      &self->value.intval,
-						      set_doc, show_doc,
-						      help_doc, get_set_value,
-						      get_show_value, set_list,
-						      show_list);
-      break;
-
     case var_enum:
       /* Initialize the value, just in case.  */
       self->value.cstringval = self->enumeration[0];
@@ -740,6 +808,8 @@ parmpy_init (PyObject *self, PyObject *a
   int parmclass, cmdtype;
   PyObject *enum_values = NULL;
   struct cmd_list_element **set_list, **show_list;
+  const literal_def *extra_literals;
+  enum var_types type;
 
   if (! PyArg_ParseTuple (args, "sii|O", &name, &cmdtype, &parmclass,
 			  &enum_values))
@@ -756,33 +826,36 @@ parmpy_init (PyObject *self, PyObject *a
       return -1;
     }
 
-  if (parmclass != var_boolean /* ARI: var_boolean */
-      && parmclass != var_auto_boolean
-      && parmclass != var_uinteger && parmclass != var_integer
-      && parmclass != var_string && parmclass != var_string_noescape
-      && parmclass != var_optional_filename && parmclass != var_filename
-      && parmclass != var_zinteger && parmclass != var_zuinteger
-      && parmclass != var_zuinteger_unlimited && parmclass != var_enum)
+  if (parmclass != param_boolean /* ARI: param_boolean */
+      && parmclass != param_auto_boolean
+      && parmclass != param_uinteger && parmclass != param_integer
+      && parmclass != param_string && parmclass != param_string_noescape
+      && parmclass != param_optional_filename && parmclass != param_filename
+      && parmclass != param_zinteger && parmclass != param_zuinteger
+      && parmclass != param_zuinteger_unlimited && parmclass != param_enum)
     {
       PyErr_SetString (PyExc_RuntimeError,
 		       _("Invalid parameter class argument."));
       return -1;
     }
 
-  if (enum_values && parmclass != var_enum)
+  if (enum_values && parmclass != param_enum)
     {
       PyErr_SetString (PyExc_RuntimeError,
 		       _("Only PARAM_ENUM accepts a fourth argument."));
       return -1;
     }
-  if (parmclass == var_enum)
+  if (parmclass == param_enum)
     {
       if (! compute_enum_values (obj, enum_values))
 	return -1;
     }
   else
     obj->enumeration = NULL;
-  obj->type = (enum var_types) parmclass;
+  type = param_to_var[parmclass].type;
+  extra_literals = param_to_var[parmclass].extra_literals;
+  obj->type = type;
+  obj->extra_literals = extra_literals;
   memset (&obj->value, 0, sizeof (obj->value));
 
   if (var_type_uses<std::string> (obj->type))
@@ -805,7 +878,8 @@ parmpy_init (PyObject *self, PyObject *a
 
   try
     {
-      add_setshow_generic (parmclass, (enum command_class) cmdtype,
+      add_setshow_generic (type, extra_literals,
+			   (enum command_class) cmdtype,
 			   std::move (cmd_name), obj,
 			   set_doc.get (), show_doc.get (),
 			   doc.get (), set_list, show_list);
Index: src/gdb/python/python.c
===================================================================
--- src.orig/gdb/python/python.c
+++ src/gdb/python/python.c
@@ -504,27 +504,45 @@ gdbpy_parameter_value (const setting &va
 	  Py_RETURN_NONE;
       }
 
-    case var_integer:
-      if (var.get<int> () == INT_MAX)
-	Py_RETURN_NONE;
-      /* Fall through.  */
-    case var_zinteger:
-    case var_zuinteger_unlimited:
-      return gdb_py_object_from_longest (var.get<int> ()).release ();
-
     case var_uinteger:
+    case var_integer:
+    case var_pinteger:
       {
-	unsigned int val = var.get<unsigned int> ();
+	LONGEST value
+	  = (var.type () == var_uinteger
+	     ? static_cast<LONGEST> (var.get<unsigned int> ())
+	     : static_cast<LONGEST> (var.get<int> ()));
 
-	if (val == UINT_MAX)
-	  Py_RETURN_NONE;
-	return gdb_py_object_from_ulongest (val).release ();
-      }
+	if (var.extra_literals () != nullptr)
+	  for (const literal_def *l = var.extra_literals ();
+	       l->literal != nullptr;
+	       l++)
+	    if (value == l->use)
+	      {
+		if (strcmp (l->literal, "unlimited") == 0)
+		  {
+		    /* Compatibility hack for API brokenness.  */
+		    if (var.type () == var_pinteger
+			&& l->val.has_value ()
+			&& *l->val == -1)
+		      value = -1;
+		    else
+		      Py_RETURN_NONE;
+		  }
+		else if (l->val.has_value ())
+		  value = *l->val;
+		else
+		  return host_string_to_python_string (l->literal).release ();
+	      }
 
-    case var_zuinteger:
-      {
-	unsigned int val = var.get<unsigned int> ();
-	return gdb_py_object_from_ulongest (val).release ();
+	if (var.type () == var_uinteger)
+	  return
+	    gdb_py_object_from_ulongest
+	      (static_cast<unsigned int> (value)).release ();
+	else
+	  return
+	    gdb_py_object_from_longest
+	      (static_cast<int> (value)).release ();
       }
     }
 
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
@@ -92,4 +92,4 @@ gdb_test "set max-value-size 1" \
 gdb_test "set max-value-size 0" \
     "max-value-size set too low, increasing to \[0-9\]+ bytes"
 gdb_test "set max-value-size -5" \
-    "only -1 is allowed to set as unlimited"
+    "integer -5 out of range"
Index: src/gdb/testsuite/gdb.base/options.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/options.exp
+++ src/gdb/testsuite/gdb.base/options.exp
@@ -98,19 +98,22 @@ proc make_cmd {variant} {
 # test-options xxx", with no flag/option set.  OPERAND is the expected
 # operand.
 proc expect_none {operand} {
-    return "-flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint 0 -zuint-unl 0 -string '' -- $operand"
+    return "-flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl 0 -pint-unl 0\
+	    -string '' -- $operand"
 }
 
 # Return a string for the expected result of running "maint
 # test-options xxx", with -flag set.  OPERAND is the expected operand.
 proc expect_flag {operand} {
-    return "-flag 1 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint 0 -zuint-unl 0 -string '' -- $operand"
+    return "-flag 1 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl 0 -pint-unl 0\
+	    -string '' -- $operand"
 }
 
 # Return a string for the expected result of running "maint
 # test-options xxx", with -bool set.  OPERAND is the expected operand.
 proc expect_bool {operand} {
-    return "-flag 0 -xx1 0 -xx2 0 -bool 1 -enum xxx -uint 0 -zuint-unl 0 -string '' -- $operand"
+    return "-flag 0 -xx1 0 -xx2 0 -bool 1 -enum xxx -uint-unl 0 -pint-unl 0\
+	    -string '' -- $operand"
 }
 
 # Return a string for the expected result of running "maint
@@ -118,10 +121,12 @@ proc expect_bool {operand} {
 # OPTION determines which option to expect set.  OPERAND is the
 # expected operand.
 proc expect_integer {option val operand} {
-    if {$option == "uinteger"} {
-	return "-flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint $val -zuint-unl 0 -string '' -- $operand"
-    } elseif {$option == "zuinteger-unlimited"} {
-	return "-flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint 0 -zuint-unl $val -string '' -- $operand"
+    if {$option == "uinteger-unlimited"} {
+	return "-flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl $val\
+		-pint-unl 0 -string '' -- $operand"
+    } elseif {$option == "pinteger-unlimited"} {
+	return "-flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl 0\
+		-pint-unl $val -string '' -- $operand"
     } else {
 	error "unsupported option: $option"
     }
@@ -138,18 +143,19 @@ proc expect_string {str operand} {
 	     && [string range $str end end] == "'")} {
 	set str [string range $str 1 end-1]
     }
-    return "-flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint 0 -zuint-unl 0 -string '$str' -- $operand"
+    return "-flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl 0 -pint-unl 0\
+	    -string '$str' -- $operand"
 }
 
 set all_options {
     "-bool"
     "-enum"
     "-flag"
+    "-pinteger-unlimited"
     "-string"
-    "-uinteger"
+    "-uinteger-unlimited"
     "-xx1"
     "-xx2"
-    "-zuinteger-unlimited"
 }
 
 # Basic option-machinery + "print" command integration tests.
@@ -604,7 +610,8 @@ proc_with_prefix test-flag {variant} {
 
     # Extract twice the same flag, separated by one space.
     gdb_test "$cmd -xx1     -xx2 -xx1  -xx2 -xx1    -- non flags args" \
-	"-flag 0 -xx1 1 -xx2 1 -bool 0 -enum xxx -uint 0 -zuint-unl 0 -string '' -- non flags args"
+	"-flag 0 -xx1 1 -xx2 1 -bool 0 -enum xxx -uint-unl 0 -pint-unl 0\
+	 -string '' -- non flags args"
 
     # Extract 2 known flags in front of unknown flags.
     gdb_test "$cmd -xx1 -xx2 -a -b -c -xx1 --" \
@@ -822,13 +829,13 @@ proc_with_prefix test-boolean {variant}
 }
 
 # Uinteger option tests.  OPTION is which integer option we're
-# testing.  Can be "uinteger" or "zuinteger-unlimited".
+# testing.  Can be "uinteger-unlimited" or "pinteger-unlimited".
 proc_with_prefix test-uinteger {variant option} {
     global all_options
 
     set cmd "[make_cmd $variant] -$option"
 
-    # Test completing a uinteger option:
+    # Test completing an integer option:
     res_test_gdb_complete_multiple \
 	"1 [expect_none ""]" \
 	"$cmd " "" "" {
@@ -852,7 +859,7 @@ proc_with_prefix test-uinteger {variant
     gdb_test "$cmd 1 -- 999" [expect_integer $option "1" "999"]
     gdb_test "$cmd unlimited -- 999" \
 	[expect_integer $option "unlimited" "999"]
-    if {$option == "zuinteger-unlimited"} {
+    if {$option == "pinteger-unlimited"} {
 	gdb_test "$cmd -1 --" [expect_integer $option "unlimited" ""]
 	gdb_test "$cmd 0 --" [expect_integer $option "0" ""]
     } else {
@@ -865,7 +872,7 @@ proc_with_prefix test-uinteger {variant
 	"Expected integer at: unlimitedx --"
 
     # Don't offer completions until we're past the
-    # -uinteger/-zuinteger-unlimited argument.
+    # -uinteger-unlimited/-pinteger-unlimited argument.
     res_test_gdb_complete_none \
 	"1 [expect_none ""]" \
 	"$cmd 1"
@@ -878,15 +885,15 @@ proc_with_prefix test-uinteger {variant
     }
 
     # Try "-1".
-    if {$option == "uinteger"} {
-	# -1 is invalid uinteger.
+    if {$option == "uinteger-unlimited"} {
+	# -1 is invalid uinteger-unlimited.
 	foreach value {"-1" "-1 "} {
 	    res_test_gdb_complete_none \
 		"1 [expect_none ""]" \
 		"$cmd $value"
 	}
     } else {
-	# -1 is valid for zuinteger-unlimited.
+	# -1 is valid for pinteger-unlimited.
 	res_test_gdb_complete_none \
 	    "1 [expect_none ""]" \
 	    "$cmd -1"
@@ -914,7 +921,7 @@ proc_with_prefix test-uinteger {variant
 	res_test_gdb_complete_none "0 " "$cmd 1 "
     }
 
-    # Test completing non-option arguments after "-uinteger 1 ".
+    # Test completing non-option arguments after "-uinteger-unlimited 1 ".
     foreach operand {"x" "x " "1a" "1a " "1-" "1- "} {
 	if {$variant == "require-delimiter"} {
 	    res_test_gdb_complete_none \
@@ -1032,7 +1039,7 @@ foreach_with_prefix cmd {
     test-misc $cmd
     test-flag $cmd
     test-boolean $cmd
-    foreach subcmd {"uinteger" "zuinteger-unlimited" } {
+    foreach subcmd {"uinteger-unlimited" "pinteger-unlimited" } {
 	test-uinteger $cmd $subcmd
     }
     test-enum $cmd
Index: src/gdb/testsuite/gdb.base/settings.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/settings.exp
+++ src/gdb/testsuite/gdb.base/settings.exp
@@ -143,7 +143,7 @@ proc test-integer {variant} {
     if {$variant == "zuinteger-unlimited"} {
 	# -1 means unlimited.  Other negative values are rejected.  -1
 	# -is tested further below, along the "unlimited" tests.
-	gdb_test "$set_cmd -2" "only -1 is allowed to set as unlimited"
+	gdb_test "$set_cmd -2" "integer -2 out of range"
 	check_type "test-settings $variant" "type = int"
     } elseif {$variant == "uinteger" || $variant == "zuinteger"} {
 	# Negative values are not accepted.
Index: src/gdb/testsuite/gdb.base/with.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/with.exp
+++ src/gdb/testsuite/gdb.base/with.exp
@@ -104,7 +104,7 @@ with_test_prefix "maint" {
     test_with_error "zuinteger" "" \
 	"Argument required \\(integer to set it to\\)\\."
     test_with_error "zuinteger-unlimited" "-2" \
-	"only -1 is allowed to set as unlimited"
+	"integer -2 out of range"
     test_with_error "zuinteger-unlimited" "" \
 	"Argument required \\(integer to set it to, or \"unlimited\"\\)\\."
     test_with_error "filename" "" \
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
@@ -113,24 +113,18 @@ foreach_with_prefix param {
 	    \\(3\\) \\(3\\)\\)>"
     switch -- $param {
 	"listsize" {
-	    set param_get_one $param_type_error
-	    set param_get_zero $param_type_error
-	    set param_get_minus_one $param_type_error
-	    set param_get_unlimited $param_type_error
+	    set param_get_zero "#:unlimited"
+	    set param_get_minus_one -1
 	    set param_set_minus_one ""
 	}
 	"print elements" {
-	    set param_get_one 1
 	    set param_get_zero "#:unlimited"
 	    set param_get_minus_one "#:unlimited"
-	    set param_get_unlimited "#:unlimited"
 	    set param_set_minus_one $param_range_error
 	}
 	"max-completions" {
-	    set param_get_one 1
 	    set param_get_zero 0
 	    set param_get_minus_one "#:unlimited"
-	    set param_get_unlimited "#:unlimited"
 	    set param_set_minus_one ""
 	}
 	default {
@@ -141,7 +135,7 @@ foreach_with_prefix param {
     gdb_test_no_output "set $param 1" "test set to 1"
 
     gdb_test "guile (print (parameter-value \"$param\"))" \
-	$param_get_one "test value of 1"
+	1 "test value of 1"
 
     gdb_test_no_output "set $param 0" "test set to 0"
 
@@ -157,7 +151,7 @@ foreach_with_prefix param {
     gdb_test_no_output "set $param unlimited" "test set to 'unlimited'"
 
     gdb_test "guile (print (parameter-value \"$param\"))" \
-	$param_get_unlimited "test value of 'unlimited'"
+	"#:unlimited" "test value of 'unlimited'"
 }
 
 foreach_with_prefix kind {
@@ -189,8 +183,7 @@ foreach_with_prefix kind {
 	     #:unlimited" \
 	    "Error while executing Scheme code\\."]
     set param_minus_one_error "integer -1 out of range"
-    set param_minus_two_range "integer -2 out of range"
-    set param_minus_two_unlimited "only -1 is allowed to set as unlimited"
+    set param_minus_two_error "integer -2 out of range"
     switch -- $kind {
 	PARAM_UINTEGER {
 	    set param_get_zero "#:unlimited"
@@ -199,7 +192,7 @@ foreach_with_prefix kind {
 	    set param_str_unlimited unlimited
 	    set param_set_unlimited ""
 	    set param_set_minus_one $param_minus_one_error
-	    set param_set_minus_two $param_minus_two_range
+	    set param_set_minus_two $param_minus_two_error
 	}
 	PARAM_ZINTEGER {
 	    set param_get_zero 0
@@ -217,7 +210,7 @@ foreach_with_prefix kind {
 	    set param_str_unlimited 2
 	    set param_set_unlimited $param_integer_error
 	    set param_set_minus_one $param_minus_one_error
-	    set param_set_minus_two $param_minus_two_range
+	    set param_set_minus_two $param_minus_two_error
 	}
 	PARAM_ZUINTEGER_UNLIMITED {
 	    set param_get_zero 0
@@ -226,7 +219,7 @@ foreach_with_prefix kind {
 	    set param_str_unlimited unlimited
 	    set param_set_unlimited ""
 	    set param_set_minus_one ""
-	    set param_set_minus_two $param_minus_two_unlimited
+	    set param_set_minus_two $param_minus_two_error
 	}
 	default {
 	    error "invalid kind: $kind"
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
@@ -434,6 +434,7 @@ proc_with_prefix test_integer_parameter
 		set param_get_minus_one None
 		set param_get_minus_five 1
 		set param_get_none None
+		set param_get_unlimited None
 		set param_set_minus_one $param_range_error
 		set param_set_minus_five $param_range_error
 		set param_set_none ""
@@ -443,6 +444,7 @@ proc_with_prefix test_integer_parameter
 		set param_get_minus_one -1
 		set param_get_minus_five -5
 		set param_get_none None
+		set param_get_unlimited None
 		set param_set_minus_one -1
 		set param_set_minus_five -5
 		set param_set_none ""
@@ -452,6 +454,7 @@ proc_with_prefix test_integer_parameter
 		set param_get_minus_one -1
 		set param_get_minus_five -5
 		set param_get_none 5
+		set param_get_unlimited 0
 		set param_set_minus_one ""
 		set param_set_minus_five ""
 		set param_set_none $param_integer_error
@@ -461,6 +464,7 @@ proc_with_prefix test_integer_parameter
 		set param_get_minus_one 0
 		set param_get_minus_five 1
 		set param_get_none 5
+		set param_get_unlimited 0
 		set param_set_minus_one $param_range_error
 		set param_set_minus_five $param_range_error
 		set param_set_none $param_integer_error
@@ -470,6 +474,7 @@ proc_with_prefix test_integer_parameter
 		set param_get_minus_one -1
 		set param_get_minus_five 1
 		set param_get_none -1
+		set param_get_unlimited -1
 		set param_set_minus_one ""
 		set param_set_minus_five $param_range_error
 		set param_set_none ""
@@ -526,6 +531,16 @@ proc_with_prefix test_integer_parameter
 
 	gdb_test "python print(gdb.parameter('test-$kind'))" \
 	    $param_get_zero "test value of 0 via gdb.parameter"
+
+	py_param_test_maybe_no_output \
+	    "python test_param_$kind.value = 'unlimited'" \
+	    $param_set_none "test set to 'unlimited'"
+
+	gdb_test "python print(test_param_$kind.value)" \
+	    $param_get_unlimited "test value of 'unlimited'"
+
+	gdb_test "python print(gdb.parameter('test-$kind'))" \
+	    $param_get_unlimited "test value of 'unlimited' via gdb.parameter"
     }
 }
 
Index: src/gdb/valprint.c
===================================================================
--- src.orig/gdb/valprint.c
+++ src/gdb/valprint.c
@@ -2861,8 +2861,8 @@ using boolean_option_def
   = gdb::option::boolean_option_def<value_print_options>;
 using uinteger_option_def
   = gdb::option::uinteger_option_def<value_print_options>;
-using zuinteger_unlimited_option_def
-  = gdb::option::zuinteger_unlimited_option_def<value_print_options>;
+using pinteger_option_def
+  = gdb::option::pinteger_option_def<value_print_options>;
 
 /* Definitions of options for the "print" and "compile print"
    commands.  */
@@ -2907,15 +2907,17 @@ static const gdb::option::option_def val
   uinteger_option_def {
     "elements",
     [] (value_print_options *opt) { return &opt->print_max; },
+    uinteger_unlimited_literals,
     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_("\"unlimited\" causes there to be no limit."),
   },
 
-  zuinteger_unlimited_option_def {
+  pinteger_option_def {
     "max-depth",
     [] (value_print_options *opt) { return &opt->max_depth; },
+    pinteger_unlimited_literals,
     show_print_max_depth, /* show_cmd_cb */
     N_("Set maximum print depth for nested structures, unions and arrays."),
     N_("Show maximum print depth for nested structures, unions, and arrays."),
@@ -2975,6 +2977,7 @@ pretty-printers for that value.")
   uinteger_option_def {
     "repeats",
     [] (value_print_options *opt) { return &opt->repeat_count_threshold; },
+    uinteger_unlimited_literals,
     show_repeat_count_threshold, /* show_cmd_cb */
     N_("Set threshold for repeated print elements."),
     N_("Show threshold for repeated print elements."),
