diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c
index be38d9b287a..1a6bea41480 100644
--- a/gdb/cli/cli-decode.c
+++ b/gdb/cli/cli-decode.c
@@ -171,6 +171,27 @@ set_cmd_completer_handle_brkchars (struct cmd_list_element *cmd,
   cmd->completer_handle_brkchars = func;
 }
 
+
+/* Insert element C in LIST.  */
+
+static void
+insert_cmd (cmd_list_element *c, cmd_list_element **list)
+{
+  if (*list == NULL || strcmp ((*list)->name, c->name) >= 0)
+    {
+      c->next = *list;
+      *list = c;
+    }
+  else
+    {
+      cmd_list_element *p = *list;
+      while (p->next && strcmp (p->next->name, c->name) <= 0)
+	p = p->next;
+      c->next = p->next;
+      p->next = c;
+    }
+}
+
 /* Add element named NAME.
    Space for NAME and DOC must be allocated by the caller.
    CLASS is the top level category into which commands are broken down
@@ -195,13 +216,12 @@ do_add_cmd (const char *name, enum command_class theclass,
 {
   struct cmd_list_element *c = new struct cmd_list_element (name, theclass,
 							    doc);
-  struct cmd_list_element *p, *iter;
 
   /* Turn each alias of the old command into an alias of the new
      command.  */
   c->aliases = delete_cmd (name, list, &c->hook_pre, &c->hookee_pre,
 			   &c->hook_post, &c->hookee_post);
-  for (iter = c->aliases; iter; iter = iter->alias_chain)
+  for (cmd_list_element *iter = c->aliases; iter; iter = iter->alias_chain)
     iter->cmd_pointer = c;
   if (c->hook_pre)
     c->hook_pre->hookee_pre = c;
@@ -212,22 +232,7 @@ do_add_cmd (const char *name, enum command_class theclass,
   if (c->hookee_post)
     c->hookee_post->hook_post = c;
 
-  if (*list == NULL || strcmp ((*list)->name, name) >= 0)
-    {
-      c->next = *list;
-      *list = c;
-    }
-  else
-    {
-      p = *list;
-      while (p->next && strcmp (p->next->name, name) <= 0)
-	{
-	  p = p->next;
-	}
-      c->next = p->next;
-      p->next = c;
-    }
-
+  insert_cmd (c, list);
   return c;
 }
 
@@ -851,15 +856,13 @@ add_setshow_zuinteger_cmd (const char *name, enum command_class theclass,
   set_cmd_completer (show, nullptr);
 }
 
-/* Remove the command named NAME from the command list.  Return the
-   list commands which were aliased to the deleted command.  If the
-   command had no aliases, return NULL.  The various *HOOKs are set to
-   the pre- and post-hook commands for the deleted command.  If the
-   command does not have a hook, the corresponding out parameter is
-   set to NULL.  */
+/* Remove the command named NAME from the command list, and return it.
+   The various *HOOKs are set to the pre- and post-hook commands for
+   the removed command.  If the command does not have a hook, the
+   corresponding out parameter is set to NULL.  */
 
-static struct cmd_list_element *
-delete_cmd (const char *name, struct cmd_list_element **list,
+static cmd_list_element *
+unlink_cmd (const char *name, struct cmd_list_element **list,
 	    struct cmd_list_element **prehook,
 	    struct cmd_list_element **prehookee,
 	    struct cmd_list_element **posthook,
@@ -867,7 +870,6 @@ delete_cmd (const char *name, struct cmd_list_element **list,
 {
   struct cmd_list_element *iter;
   struct cmd_list_element **previous_chain_ptr;
-  struct cmd_list_element *aliases = NULL;
 
   *prehook = NULL;
   *prehookee = NULL;
@@ -893,8 +895,6 @@ delete_cmd (const char *name, struct cmd_list_element **list,
 	  /* Update the link.  */
 	  *previous_chain_ptr = iter->next;
 
-	  aliases = iter->aliases;
-
 	  /* If this command was an alias, remove it from the list of
 	     aliases.  */
 	  if (iter->cmd_pointer)
@@ -910,17 +910,57 @@ delete_cmd (const char *name, struct cmd_list_element **list,
 	      *prevp = iter->alias_chain;
 	    }
 
-	  delete iter;
-
 	  /* We won't see another command with the same name.  */
-	  break;
+	  return iter;
 	}
       else
 	previous_chain_ptr = &iter->next;
     }
 
+  return nullptr;
+}
+
+/* Remove the command named NAME from the command list and delete it.
+   Return the list commands which were aliased to the deleted command.
+   If the command had no aliases, return NULL.  The various *HOOKs are
+   set to the pre- and post-hook commands for the deleted command.  If
+   the command does not have a hook, the corresponding out parameter
+   is set to NULL.  */
+
+static cmd_list_element *
+delete_cmd (const char *name, cmd_list_element **list,
+	    cmd_list_element **prehook,
+	    cmd_list_element **prehookee,
+	    cmd_list_element **posthook,
+	    cmd_list_element **posthookee)
+{
+  cmd_list_element *cmd = unlink_cmd (name, list,
+				      prehook, prehookee,
+				      posthook, posthookee);
+  if (cmd == nullptr)
+    return nullptr;
+
+  cmd_list_element *aliases = cmd->aliases;
+  delete cmd;
   return aliases;
 }
+
+/* See command.h.  */
+
+void
+rename_cmd (const char *old_name, cmd_list_element **old_list,
+	    const char *new_name, cmd_list_element **new_list)
+{
+  cmd_list_element *prehook, *prehookee, *posthook, *posthookee;
+  cmd_list_element *c = unlink_cmd (old_name, old_list,
+				    &prehook, &prehookee,
+				    &posthook, &posthookee);
+
+  c->name = new_name;
+  insert_cmd (c, new_list);
+  set_cmd_prefix (c, new_list);
+}
+
 
 /* Shorthands to the commands above.  */
 
diff --git a/gdb/command.h b/gdb/command.h
index 35006cc339e..ed848114b85 100644
--- a/gdb/command.h
+++ b/gdb/command.h
@@ -439,6 +439,11 @@ extern void
 				       struct cmd_list_element **set_list,
 				       struct cmd_list_element **show_list);
 
+/* Move command OLD_NAME from OLD_LIST to NEW_LIST and rename it from
+   OLD_NAME to NEW_NAME.  */
+extern void rename_cmd (const char *old_name, cmd_list_element **old_list,
+			const char *new_name, cmd_list_element **new_list);
+
 /* Do a "show" command for each thing on a command list.  */
 
 extern void cmd_show_list (struct cmd_list_element *, int, const char *);
