@@ -1687,6 +1687,38 @@ info_frame_command (const char *addr_exp, int from_tty)
}
}
+/* trailing_outermost_frame returns 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;
+}
+
/* Print briefly all stack frames or just the innermost COUNT_EXP
frames. */
@@ -1751,32 +1783,14 @@ backtrace_command_1 (const char *count_exp, frame_filter_flags flags,
variable TRAILING to the frame from which we should start
printing. Second, it must set the variable count to the number
of frames which we should print, or -1 if all of them. */
- trailing = get_current_frame ();
if (count_exp != NULL && count < 0)
{
- struct frame_info *current;
-
- count = -count;
-
- current = trailing;
- while (current && 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)
- {
- QUIT;
- trailing = get_prev_frame (trailing);
- current = get_prev_frame (current);
- }
-
+ trailing = trailing_outermost_frame (-count);
count = -1;
}
+ else
+ trailing = get_current_frame ();
for (fi = trailing; fi && count--; fi = get_prev_frame (fi))
{
@@ -2505,9 +2519,160 @@ func_command (const char *arg, int from_tty)
select_and_print_frame (frame);
}
+/* Apply a GDB command to a all stack frames, or innermost COUNT frames.
+ With a negative COUNT, apply command on outermost -COUNT frames.
+
+ frame apply 3 info frame Apply 'info frame' to frames 0, 1, 2
+ frame apply -3 info frame Apply 'info frame' to outermost 3 frames.
+ frame apply all x/i $pc Apply 'x/i $pc' cmd to all frames.
+ frame apply all -s p local_var_no_idea_in_which_frame
+ If a frame has a local variable called
+ local_var_no_idea_in_which_frame, print frame
+ and value of local_var_no_idea_in_which_frame.
+ frame apply all -sqq p local_var_no_idea_in_which_frame
+ Same as before, but only print the variable value. */
+
+/* Apply a GDB command to COUNT stack frames, starting at TRAILING.
+ COUNT -1 means all frames starting at TRAILING. WHICH_COMMAND is used
+ for error messages. */
+static void
+frame_apply_command_count (const char* which_command,
+ const char *cmd, int from_tty,
+ struct frame_info *trailing, int count)
+{
+ int print_what_v = 2; /* Corresponding to LOCATION. */
+ enum print_what print_what[5] =
+ {
+ LOC_AND_ADDRESS, /* Should never be used, this is verbosity 0. */
+ SRC_LINE,
+ LOCATION,
+ LOC_AND_ADDRESS,
+ SRC_AND_LOC
+ };
+ bool cont;
+ bool silent;
+ struct frame_info *fi;
+
+ if (cmd != NULL)
+ check_for_flags_vqcs (which_command, &cmd,
+ &print_what_v, 4,
+ &cont, &silent);
+
+ if (cmd == NULL || *cmd == '\0')
+ error (_("Please specify a command to apply on the selected frames"));
+
+ /* The below will restore the current inferior/thread/frame.
+ Usually, only the frame is effectively to be restored.
+ But in case CMD switches of inferior/thread, better restore
+ these also. */
+ scoped_restore_current_thread restore_thread;
+
+ for (fi = trailing; fi && count--; fi = get_prev_frame (fi))
+ {
+ struct frame_id frame_id = get_frame_id (fi);
+
+ QUIT;
+
+ select_frame (fi);
+ TRY
+ {
+ std::string cmd_result;
+ {
+ /* In case CMD switches of inferior/thread/frame, the below
+ restores the inferior/thread. We can then re-initialise
+ FI based on FRAME_ID. */
+ scoped_restore_current_thread restore_fi_current_frame;
+
+ cmd_result = execute_command_to_string (cmd, from_tty);
+ }
+ fi = frame_find_by_id (frame_id);
+ if (fi == NULL)
+ {
+ warning (_("Unable to restore previously selected frame."));
+ break;
+ }
+ if (!silent || cmd_result.length () > 0)
+ {
+ if (print_what_v > 0)
+ print_stack_frame (fi, 1, print_what[print_what_v], 0);
+ printf_filtered ("%s", cmd_result.c_str ());
+ }
+ }
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ fi = frame_find_by_id (frame_id);
+ if (fi == NULL)
+ {
+ warning (_("Unable to restore previously selected frame."));
+ break;
+ }
+ if (!silent)
+ {
+ if (print_what_v > 0)
+ print_stack_frame (fi, 1, print_what [print_what_v], 0);
+ if (cont)
+ printf_filtered ("%s\n", ex.message);
+ else
+ throw_exception (ex);
+ }
+ }
+ END_CATCH;
+ }
+}
+
+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."));
+
+ count = get_number_trailer (&cmd, 0);
+
+ 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)
+{
+ std::string expanded = std::string ("frame apply all -s ") + std::string (cmd);
+ execute_command (expanded.c_str (), from_tty);
+}
+
+
+/* Commands with a prefix of `frame'. */
+struct cmd_list_element *frame_cmd_list = NULL;
+
void
_initialize_stack (void)
{
+ static struct cmd_list_element *frame_apply_list = NULL;
+
add_com ("return", class_stack, return_command, _("\
Make selected stack frame return to its caller.\n\
Control remains in the debugger, but when you continue\n\
@@ -2530,14 +2695,49 @@ An argument says how many frames down to go."));
Same as the `down' command, but does not print anything.\n\
This is useful in command scripts."));
- add_com ("frame", class_stack, frame_command, _("\
+ add_prefix_cmd ("frame", class_stack, frame_command, _("\
Select and print a stack frame.\nWith no argument, \
print the selected stack frame. (See also \"info frame\").\n\
An argument specifies the frame to select.\n\
-It can be a stack frame number or the address of the frame."));
+It can be a stack frame number or the address of the frame."),
+ &frame_cmd_list, "frame ", 1, &cmdlist);
add_com_alias ("f", "frame", class_stack, 1);
+#define FRAME_APPLY_FLAGS_HELP "\
+FLAGS letters are v(increase verbosity), q(decrease verbosity)\n\
+ c(continue), s(silent).\n\
+Verbosity (default 2) controls what to print for a frame:\n\
+ 0 : no frame info is printed\n\
+ 1 : source line\n\
+ 2 : location\n\
+ 3 : location and address\n\
+ 4 : source line and location\n\
+By default, if a COMMAND raises an error, frame apply is aborted.\n\
+Flag c indicates to print the error and continue.\n\
+Flag s indicates to silently ignore a COMMAND that raises an error\n\
+or produces no output."
+
+ add_prefix_cmd ("apply", class_stack, frame_apply_command,
+ _("Apply a command to a number of frames.\n\
+Usage: frame apply COUNT [-FLAGS...] COMMAND\n\
+With a negative COUNT argument, applies the command on outermost -COUNT frames.\n"
+FRAME_APPLY_FLAGS_HELP),
+ &frame_apply_list, "frame apply ", 1, &frame_cmd_list);
+
+ add_cmd ("all", class_stack, frame_apply_all_command,
+ _("\
+Apply a command to all frames.\n\
+\n\
+Usage: frame apply all [-FLAGS...] COMMAND\n"
+FRAME_APPLY_FLAGS_HELP),
+ &frame_apply_list);
+
+ add_com ("faas", class_stack, faas_command, _("\
+Apply a command to all frames (ignoring errors and empty output).\n\
+Usage: faas COMMAND\n\
+shortcut for 'frame apply all -s COMMAND'"));
+
add_com_suppress_notification ("select-frame", class_stack, select_frame_command, _("\
Select a stack frame without printing anything.\n\
An argument specifies the frame to select.\n\