+
+/* Completer for the "frame apply ..." commands. */
+
+static void
+frame_apply_completer (completion_tracker &tracker, const char *text)
+{
+ const auto group = make_frame_apply_options_def_group (nullptr, nullptr);
+ if (gdb::option::complete_options
+ (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group))
+ return;
+
+ complete_nested_command_line (tracker, text);
+}
+
+/* Completer for the "frame apply" commands. */
+
+static void
+frame_apply_level_cmd_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char */*word*/)
+{
+ /* Do this explicitly because there's an early return below. */
+ tracker.set_use_custom_word_point (true);
+
+ number_or_range_parser levels (text);
+
+ /* Skip the LEVEL list to find the options and command args. */
+ try
+ {
+ while (!levels.finished ())
+ {
+ /* Call for effect. */
+ levels.get_number ();
+
+ if (levels.in_range ())
+ levels.skip_range ();
+ }
+ }
+ catch (const gdb_exception_error &ex)
+ {
+ /* get_number throws if it parses a negative number, for
+ example. But a seemingly negative number may be the start of
+ an option instead. */
+ }
+
+ const char *cmd = levels.cur_tok ();
+
+ if (cmd == text)
+ {
+ /* No level list yet. */
+ return;
+ }
+
+ /* Check if we're past a valid LEVEL already. */
+ if (levels.finished ()
+ && cmd > text && !isspace (cmd[-1]))
+ return;
+
+ /* We're past LEVELs, advance word point. */
+ tracker.advance_custom_word_point_by (cmd - text);
+ text = cmd;
+
+ frame_apply_completer (tracker, text);
+}
+
+/* Completer for the "frame apply all" command. */
+
+void
+frame_apply_all_cmd_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char */*word*/)
+{
+ frame_apply_completer (tracker, text);
+}
+
+/* Completer for the "frame apply COUNT" command. */
+
+static void
+frame_apply_cmd_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char */*word*/)
+{
+ const char *cmd = text;
+
+ int count = get_number_trailer (&cmd, 0);
+ if (count == 0)
+ return;
+
+ /* Check if we're past a valid COUNT already. */
+ if (cmd > text && !isspace (cmd[-1]))
+ return;
+
+ /* We're past COUNT, advance word point. */
+ tracker.advance_custom_word_point_by (cmd - text);
+ text = cmd;
+
+ frame_apply_completer (tracker, text);
+}
+
+/* Implementation of the "frame apply level" command. */
+
+static void
+frame_apply_level_command (const char *cmd, int from_tty)
+{
+ if (!target_has_stack)
+ error (_("No stack."));
+
+ bool level_found = false;
+ const char *levels_str = cmd;
+ number_or_range_parser levels (levels_str);
+
+ /* Skip the LEVEL list to find the flags and command args. */
+ while (!levels.finished ())
+ {
+ /* Call for effect. */
+ levels.get_number ();
+
+ level_found = true;
+ if (levels.in_range ())
+ levels.skip_range ();
+ }
+
+ if (!level_found)
+ error (_("Missing or invalid LEVEL... argument"));
+
+ cmd = levels.cur_tok ();
+
+ /* Redo the LEVELS parsing, but applying COMMAND. */
+ levels.init (levels_str);
+ while (!levels.finished ())
+ {
+ const int level_beg = levels.get_number ();
+ int n_frames;
+
+ if (levels.in_range ())
+ {
+ n_frames = levels.end_value () - level_beg + 1;
+ levels.skip_range ();
+ }
+ else
+ n_frames = 1;
+
+ frame_apply_command_count ("frame apply level", cmd, from_tty,
+ leading_innermost_frame (level_beg), n_frames);
+ }
+}
+
+/* Implementation of the "frame apply all" command. */
+
+static void
+frame_apply_all_command (const char *cmd, int from_tty)
+{
+ if (!target_has_stack)
+ error (_("No stack."));
+
+ frame_apply_command_count ("frame apply all", cmd, from_tty,
+ get_current_frame (), INT_MAX);
+}
+
+/* Implementation of the "frame apply" command. */
+
+static void
+frame_apply_command (const char* cmd, int from_tty)
+{
+ int count;
+ struct frame_info *trailing;
+
+ if (!target_has_stack)
+ error (_("No stack."));
+
+ if (cmd == NULL)
+ error (_("Missing COUNT argument."));
+ count = get_number_trailer (&cmd, 0);
+ if (count == 0)
+ error (_("Invalid COUNT argument."));
+
+ if (count < 0)
+ {
+ trailing = trailing_outermost_frame (-count);
+ count = -1;
+ }
+ else
+ trailing = get_current_frame ();
+
+ frame_apply_command_count ("frame apply", cmd, from_tty,
+ trailing, count);
+}
+
+/* Implementation of the "faas" command. */
+
+static void
+faas_command (const char *cmd, int from_tty)
+{
+ if (cmd == NULL || *cmd == '\0')
+ error (_("Please specify a command to apply on all frames"));
+ std::string expanded = std::string ("frame apply all -s ") + cmd;
+ execute_command (expanded.c_str (), from_tty);
+}
+
+
+/* Find inner-mode frame with frame address ADDRESS. Return NULL if no
+ matching frame can be found. */
+
+static struct frame_info *
+find_frame_for_address (CORE_ADDR address)
+{
+ struct frame_id id;
+ struct frame_info *fid;
+
+ id = frame_id_build_wild (address);
+
+ /* If (s)he specifies the frame with an address, he deserves
+ what (s)he gets. Still, give the highest one that matches.
+ (NOTE: cagney/2004-10-29: Why highest, or outer-most, I don't
+ know). */
+ for (fid = get_current_frame ();
+ fid != NULL;
+ fid = get_prev_frame (fid))
+ {
+ if (frame_id_eq (id, get_frame_id (fid)))
+ {
+ struct frame_info *prev_frame;
+
+ while (1)
+ {
+ prev_frame = get_prev_frame (fid);
+ if (!prev_frame
+ || !frame_id_eq (id, get_frame_id (prev_frame)))
+ break;
+ fid = prev_frame;
+ }
+ return fid;
+ }
+ }
+ return NULL;
+}
+