+/* Return the starting frame needed to handle COUNT outermost frames. */
+
+static struct frame_info *
+trailing_outermost_frame (int count)
+{
+ struct frame_info *current;
+ struct frame_info *trailing;
+
+ trailing = get_current_frame ();
+
+ gdb_assert (count > 0);
+
+ current = trailing;
+ while (current != nullptr && count--)
+ {
+ QUIT;
+ current = get_prev_frame (current);
+ }
+
+ /* Will stop when CURRENT reaches the top of the stack.
+ TRAILING will be COUNT below it. */
+ while (current != nullptr)
+ {
+ QUIT;
+ trailing = get_prev_frame (trailing);
+ current = get_prev_frame (current);
+ }
+
+ return trailing;
+}
+
+/* The core of all the "select-frame" sub-commands. Just wraps a call to
+ SELECT_FRAME. */
+
+static void
+select_frame_command_core (struct frame_info *fi, bool ignored)
+{
+ struct frame_info *prev_frame = get_selected_frame_if_set ();
+ select_frame (fi);
+ if (get_selected_frame_if_set () != prev_frame)
+ gdb::observers::user_selected_context_changed.notify (USER_SELECTED_FRAME);
+}
+
+/* See stack.h. */
+
+void
+select_frame_for_mi (struct frame_info *fi)
+{
+ select_frame_command_core (fi, false /* Ignored. */);
+}
+
+/* The core of all the "frame" sub-commands. Select frame FI, and if this
+ means we change frame send out a change notification (otherwise, just
+ reprint the current frame summary). */
+
+static void
+frame_command_core (struct frame_info *fi, bool ignored)
+{
+ struct frame_info *prev_frame = get_selected_frame_if_set ();
+
+ select_frame (fi);
+ if (get_selected_frame_if_set () != prev_frame)
+ gdb::observers::user_selected_context_changed.notify (USER_SELECTED_FRAME);
+ else
+ print_selected_thread_frame (current_uiout, USER_SELECTED_FRAME);
+}
+
+/* The three commands 'frame', 'select-frame', and 'info frame' all have a
+ common set of sub-commands that allow a specific frame to be selected.
+ All of the sub-command functions are static methods within this class
+ template which is then instantiated below. The template parameter is a
+ callback used to implement the functionality of the base command
+ ('frame', 'select-frame', or 'info frame').
+
+ In the template parameter FI is the frame being selected. The
+ SELECTED_FRAME_P flag is true if the frame being selected was done by
+ default, which happens when the user uses the base command with no
+ arguments. For example the commands 'info frame', 'select-frame',
+ 'frame' will all cause SELECTED_FRAME_P to be true. In all other cases
+ SELECTED_FRAME_P is false. */
+
+template <void (*FPTR) (struct frame_info *fi, bool selected_frame_p)>
+class frame_command_helper
+{
+public:
+
+ /* The "frame level" family of commands. The ARG is an integer that is
+ the frame's level in the stack. */
+ static void
+ level (const char *arg, int from_tty)
+ {
+ int level = value_as_long (parse_and_eval (arg));
+ struct frame_info *fid
+ = find_relative_frame (get_current_frame (), &level);
+ if (level != 0)
+ error (_("No frame at level %s."), arg);
+ FPTR (fid, false);
+ }
+
+ /* The "frame address" family of commands. ARG is a stack-pointer
+ address for an existing frame. This command does not allow new
+ frames to be created. */
+
+ static void
+ address (const char *arg, int from_tty)
+ {
+ CORE_ADDR addr = value_as_address (parse_and_eval (arg));
+ struct frame_info *fid = find_frame_for_address (addr);
+ if (fid == NULL)
+ error (_("No frame at address %s."), arg);
+ FPTR (fid, false);
+ }
+
+ /* The "frame view" family of commands. ARG is one or two addresses and
+ is used to view a frame that might be outside the current backtrace.
+ The addresses are stack-pointer address, and (optional) pc-address. */
+
+ static void
+ view (const char *args, int from_tty)
+ {
+ struct frame_info *fid;
+
+ if (args == NULL)
+ error (_("Missing address argument to view a frame"));
+
+ gdb_argv argv (args);
+
+ if (argv.count () == 2)
+ {
+ CORE_ADDR addr[2];
+
+ addr [0] = value_as_address (parse_and_eval (argv[0]));
+ addr [1] = value_as_address (parse_and_eval (argv[1]));
+ fid = create_new_frame (addr[0], addr[1]);
+ }
+ else
+ {
+ CORE_ADDR addr = value_as_address (parse_and_eval (argv[0]));
+ fid = create_new_frame (addr, false);
+ }
+ FPTR (fid, false);
+ }
+
+ /* The "frame function" family of commands. ARG is the name of a
+ function within the stack, the first function (searching from frame
+ 0) with that name will be selected. */
+
+ static void
+ function (const char *arg, int from_tty)
+ {
+ if (arg == NULL)
+ error (_("Missing function name argument"));
+ struct frame_info *fid = find_frame_for_function (arg);
+ if (fid == NULL)
+ error (_("No frame for function \"%s\"."), arg);
+ FPTR (fid, false);
+ }
+
+ /* The "frame" base command, that is, when no sub-command is specified.
+ If one argument is provided then we assume that this is a frame's
+ level as historically, this was the supported command syntax that was
+ used most often.
+
+ If no argument is provided, then the current frame is selected. */
+
+ static void
+ base_command (const char *arg, int from_tty)
+ {
+ if (arg == NULL)
+ FPTR (get_selected_frame (_("No stack.")), true);
+ else
+ level (arg, from_tty);
+ }
+};
+
+/* Instantiate three FRAME_COMMAND_HELPER instances to implement the
+ sub-commands for 'info frame', 'frame', and 'select-frame' commands. */
+
+static frame_command_helper <info_frame_command_core> info_frame_cmd;
+static frame_command_helper <frame_command_core> frame_cmd;
+static frame_command_helper <select_frame_command_core> select_frame_cmd;
+