mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-26 01:07:52 +00:00
Implement frame apply [all | COUNT | -COUNT | level LEVEL... ] [FLAG]... COMMAND.
Implement frame apply [all | COUNT | -COUNT | level LEVEL... ] [FLAG]... COMMAND.
Also implement the command 'faas COMMAND', a shortcut for
'frame apply all -s COMMAND'.
The syntax of 'frame apply' to specify some innermost or outermost
frames is similar to 'backtrace' command, using COUNT or -COUNT.
To apply a COMMAND to a more specific set of frames, the following
new command and syntax can be used:
frame apply level LEVEL... [FLAG]... COMMAND
where LEVEL is one or more frame levels or range of frame levels.
The new command 'frame apply' allows to apply a COMMAND to a number of frames,
or to all frames, or to a set of frames.
The optional [FLAG]... arguments allow to control what output to produce
and how to handle errors raised when applying COMMAND to a frame.
Some example usages for this new command:
frame apply all info frame
Produce info frame for all frames.
frame apply all p $sp
For each frame, print the location, followed by the frame sp.
frame apply all -q p $sp
Same as before, but -q flag (q = quiet) indicates to only print
the frames sp.
frame apply all p some_local_var_somewhere
Print some_local_var_somewhere in all frames. 'frame apply'
will abort as soon as the print command fails.
frame apply all -c p some_local_var_somewhere
Same as before, but -c flag (c = continue) means to
print the error and continue applying command in case the
print command fails.
frame apply all -s p some_local_var_somewhere
Same as before, but -s flag (s = silent) means to
be silent for frames where the print command fails.
In other words, this allows to 'search' the frame in which
some_local_var_somewhere can be printed.
frame apply all -s -q p some_local_var_somewhere
Same as before, but does not print the frame info in which
the variable is found.
frame apply level 2-4 5 8-10 -s p i = i + 1
Increments i in the identified frames.
gdb/ChangeLog
2018-07-12 Philippe Waroquiers <philippe.waroquiers@skynet.be>
* stack.c: (trailing_outermost_frame): New function, mostly
extracted from backtrace_command_1.
(leading_innermost_frame): New function.
(backtrace_command_1): Update to call trailing_outermost_frame.
(frame_apply_command_count): New function.
(frame_apply_level_command): New function.
(frame_apply_all_command): New function.
(frame_apply_command): New function.
(faas_command): New function.
(frame_cmd_list): New variable.
(_initialize_stack): Update to setup the new commands 'frame apply'
and 'faas'.
This commit is contained in:
@@ -1,3 +1,18 @@
|
||||
2018-07-12 Philippe Waroquiers <philippe.waroquiers@skynet.be>
|
||||
|
||||
* stack.c: (trailing_outermost_frame): New function, mostly
|
||||
extracted from backtrace_command_1.
|
||||
(leading_innermost_frame): New function.
|
||||
(backtrace_command_1): Update to call trailing_outermost_frame.
|
||||
(frame_apply_command_count): New function.
|
||||
(frame_apply_level_command): New function.
|
||||
(frame_apply_all_command): New function.
|
||||
(frame_apply_command): New function.
|
||||
(faas_command): New function.
|
||||
(frame_cmd_list): New variable.
|
||||
(_initialize_stack): Update to setup the new commands 'frame apply'
|
||||
and 'faas'.
|
||||
|
||||
2018-07-12 Philippe Waroquiers <philippe.waroquiers@skynet.be>
|
||||
|
||||
* cli-utils.c (number_or_range_parser::get_number): Only handle
|
||||
|
||||
308
gdb/stack.c
308
gdb/stack.c
@@ -1687,6 +1687,58 @@ info_frame_command (const char *addr_exp, int from_tty)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the innermost frame at level LEVEL. */
|
||||
|
||||
static struct frame_info *
|
||||
leading_innermost_frame (int level)
|
||||
{
|
||||
struct frame_info *leading;
|
||||
|
||||
leading = get_current_frame ();
|
||||
|
||||
gdb_assert (level >= 0);
|
||||
|
||||
while (leading != nullptr && level)
|
||||
{
|
||||
QUIT;
|
||||
leading = get_prev_frame (leading);
|
||||
level--;
|
||||
}
|
||||
|
||||
return leading;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Print briefly all stack frames or just the innermost COUNT_EXP
|
||||
frames. */
|
||||
|
||||
@@ -1751,32 +1803,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))
|
||||
{
|
||||
@@ -2494,9 +2528,198 @@ func_command (const char *arg, int from_tty)
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply a GDB command to all stack frames, or a set of identified 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 -s -q p local_var_no_idea_in_which_frame
|
||||
Same as before, but only print the variable value.
|
||||
frame apply level 2-5 0 4-7 -s p i = i + 1
|
||||
Adds 1 to the variable i in the specified frames.
|
||||
Note that i will be incremented twice in
|
||||
frames 4 and 5. */
|
||||
|
||||
/* Apply a GDB command to COUNT stack frames, starting at TRAILING.
|
||||
CMD starts with 0 or more qcs flags followed by the GDB command to apply.
|
||||
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)
|
||||
{
|
||||
qcs_flags flags;
|
||||
struct frame_info *fi;
|
||||
|
||||
while (cmd != NULL && parse_flags_qcs (which_command, &cmd, &flags))
|
||||
;
|
||||
|
||||
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))
|
||||
{
|
||||
QUIT;
|
||||
|
||||
select_frame (fi);
|
||||
TRY
|
||||
{
|
||||
std::string cmd_result;
|
||||
{
|
||||
/* In case CMD switches of inferior/thread/frame, the below
|
||||
restores the inferior/thread/frame. FI can then be
|
||||
set to the selected frame. */
|
||||
scoped_restore_current_thread restore_fi_current_frame;
|
||||
|
||||
cmd_result = execute_command_to_string (cmd, from_tty);
|
||||
}
|
||||
fi = get_selected_frame (_("frame apply "
|
||||
"unable to get selected frame."));
|
||||
if (!flags.silent || cmd_result.length () > 0)
|
||||
{
|
||||
if (!flags.quiet)
|
||||
print_stack_frame (fi, 1, LOCATION, 0);
|
||||
printf_filtered ("%s", cmd_result.c_str ());
|
||||
}
|
||||
}
|
||||
CATCH (ex, RETURN_MASK_ERROR)
|
||||
{
|
||||
fi = get_selected_frame (_("frame apply "
|
||||
"unable to get selected frame."));
|
||||
if (!flags.silent)
|
||||
{
|
||||
if (!flags.quiet)
|
||||
print_stack_frame (fi, 1, LOCATION, 0);
|
||||
if (flags.cont)
|
||||
printf_filtered ("%s\n", ex.message);
|
||||
else
|
||||
throw_exception (ex);
|
||||
}
|
||||
}
|
||||
END_CATCH;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 ())
|
||||
{
|
||||
const int level_beg = 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)
|
||||
{
|
||||
std::string expanded = std::string ("frame apply all -s ") + 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\
|
||||
@@ -2519,14 +2742,53 @@ 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 "\
|
||||
Prints the frame location information followed by COMMAND output.\n\
|
||||
FLAG arguments are -q (quiet), -c (continue), -s (silent).\n\
|
||||
Flag -q disables printing the frame location information.\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 [FLAG]... 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 [FLAG]... COMMAND\n"
|
||||
FRAME_APPLY_FLAGS_HELP),
|
||||
&frame_apply_list);
|
||||
|
||||
add_cmd ("level", class_stack, frame_apply_level_command,
|
||||
_("\
|
||||
Apply a command to a list of frames.\n\
|
||||
\n\
|
||||
Usage: frame apply level LEVEL... [FLAG]... COMMAND\n\
|
||||
ID is a space-separated list of LEVELs of frames to apply COMMAND on.\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\
|
||||
|
||||
Reference in New Issue
Block a user