aboutsummaryrefslogtreecommitdiff
path: root/gdb/stack.c
diff options
context:
space:
mode:
authorAndrew Burgess <andrew.burgess@embecosm.com>2015-09-10 13:06:16 +0100
committerAndrew Burgess <andrew.burgess@embecosm.com>2018-09-28 11:59:34 +0100
commitf67ffa6a785bee26bc23550670f85c6db578641f (patch)
treebc989c15856f0c9cb628d899d0ca54f8617a4911 /gdb/stack.c
parent5f9aecea0dfd9e8b0a728c332e8ddb105bae6054 (diff)
downloadbinutils-f67ffa6a785bee26bc23550670f85c6db578641f.zip
binutils-f67ffa6a785bee26bc23550670f85c6db578641f.tar.gz
binutils-f67ffa6a785bee26bc23550670f85c6db578641f.tar.bz2
gdb: Change how frames are selected for 'frame' and 'info frame'.
The 'frame' command, and thanks to code reuse the 'info frame' and 'select-frame' commands, currently have an overloaded mechanism for selecting a frame. These commands take one or two parameters, if it's one parameter then we first try to use the parameter as an integer to select a frame by level (or depth in the stack). If that fails then we treat the parameter as an address and try to select a stack frame by stack-address. If we still have not selected a stack frame, or we initially had two parameters, then GDB allows the user to view a stack frame that is not part of the current backtrace. Internally, a new frame is created with the given stack and pc addresses, and this is shown to the user. The result of this is that a typo by the user, entering the wrong stack frame level for example, can result in a brand new frame being viewed rather than an error. The purpose of this commit is to remove this overloading, while still offering the same functionality through some new sub-commands. By making the default behaviour of 'frame' (and friends) be to select a stack frame by level index, it is hoped that enough backwards-compatibility is maintained that users will not be overly inconvenienced. The 'frame', 'select-frame', and 'info frame' commands now all take a frame specification string as an argument, this string can be any of the following: (1) An integer. This is treated as a frame level. If a frame for that level does not exist then the user gets an error. (2) A string like 'level <LEVEL>', where <LEVEL> is a frame level as in option (1) above. (3) A string like 'address <STACK-ADDRESS>', where <STACK-ADDRESS> is a stack-frame address. If there is no frame for this address then the user gets an error. (4) A string like 'function <NAME>', where <NAME> is a function name, the inner most frame for function <NAME> is selected. If there is no frame for function <NAME> then the user gets an error. (5) A string like 'view <STACK-ADDRESS>', this views a new frame with stack address <STACK-ADDRESS>. (6) A string like 'view <STACK-ADDRESS> <PC-ADDRESS>', this views a new frame with stack address <STACK-ADDRESS> and the pc <PC-ADDRESS>. This change assumes that the most common use of the commands like 'frame' is to select a frame by frame level, it is for this reason that this is the behaviour that is kept for backwards compatibility. Any of the alternative behaviours, which are assumed to be less used, now require a change in user behaviour. The MI command '-stack-select-frame' has not been changed. This ensures that we maintain backwards compatibility for existing frontends. gdb/ChangeLog: (NEWS): Mention changes to frame related commands. * cli/cli-decode.c (add_cmd_suppress_notification): New function. (add_prefix_cmd_suppress_notification): New function. (add_com_suppress_notification): Call add_cmd_suppress_notification. * command.h (add_cmd_suppress_notification): Declare. (add_prefix_cmd_suppress_notification): Declare. * mi/mi-cmd-stack.c: Add 'safe-ctype.h' include. (parse_frame_specification): Moved from stack.c, with simplification to handle a single argument. (mi_cmd_stack_select_frame): Use parse_frame_specification, the switch to the selected frame. Add a header comment. * stack.c: Remove 'safe-ctype.h' include. (find_frame_for_function): Add declaration. (find_frame_for_address): New function. (parse_frame_specification): Moved into mi/mi-cmd-stack.c. (frame_selection_by_function_completer): New function. (info_frame_command): Rename to... (info_frame_command_core): ...this, and update parameter types. (select_frame_command): Rename to... (select_frame_command_core): ...this, and update parameter types. (frame_command): Rename to... (frame_command_core): ...this, and update parameter types. (class frame_command_helper): New class to wrap implementations of frame related sub-commands. (frame_apply_cmd_list): New static global. (frame_cmd_list): Make static. (select_frame_cmd_list): New global for sub-commands. (info_frame_cmd_list): New global for sub-commands. (_initialize_stack): Register sub-commands for 'frame', 'select-frame', and 'info frame'. Update 'frame apply' commands to use frame_apply_cmd_list. Move function local static frame_apply_list to file static frame_apply_cmd_list for consistency. * stack.h (select_frame_command): Delete declarationn. (select_frame_for_mi): Declare new function. gdb/doc/ChangeLog: * gdb.texinfo (Frames): Rewrite the description of 'frame number' to highlight that the number is also the frame's level. (Selection): Rewrite documentation for 'frame' and 'select-frame' commands. (Frame Info): Rewrite documentation for 'info frame' command. gdb/testsuite/ChangeLog: * gdb.base/frame-selection.exp: New file. * gdb.base/frame-selection.c: New file.
Diffstat (limited to 'gdb/stack.c')
-rw-r--r--gdb/stack.c526
1 files changed, 353 insertions, 173 deletions
diff --git a/gdb/stack.c b/gdb/stack.c
index 40ff99b..fc1ccb3 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -48,7 +48,6 @@
#include "cli/cli-utils.h"
#include "objfiles.h"
-#include "safe-ctype.h"
#include "symfile.h"
#include "extension.h"
#include "observable.h"
@@ -102,6 +101,9 @@ static void set_last_displayed_sal (int valid,
struct symtab *symtab,
int line);
+static struct frame_info *find_frame_for_function (const char *);
+static struct frame_info *find_frame_for_address (CORE_ADDR);
+
/* Zero means do things normally; we are interacting directly with the
user. One means print the full filename and linenumber when a
frame is printed, and do so in a format emacs18/emacs19.22 can
@@ -1258,134 +1260,34 @@ print_frame (struct frame_info *frame, int print_level,
}
-/* Read a frame specification in whatever the appropriate format is from
- FRAME_EXP. Call error() if the specification is in any way invalid (so
- this function never returns NULL). When SELECTED_FRAME_P is non-NULL
- set its target to indicate that the default selected frame was used. */
+/* Completion function for "frame function", "info frame function", and
+ "select-frame function" commands. */
-static struct frame_info *
-parse_frame_specification (const char *frame_exp, int *selected_frame_p)
+void
+frame_selection_by_function_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char *word)
{
- int numargs;
- struct value *args[4];
- CORE_ADDR addrs[ARRAY_SIZE (args)];
-
- if (frame_exp == NULL)
- numargs = 0;
- else
- {
- numargs = 0;
- while (1)
- {
- const char *p;
-
- /* Skip leading white space, bail of EOL. */
- frame_exp = skip_spaces (frame_exp);
- if (!*frame_exp)
- break;
-
- /* Parse the argument, extract it, save it. */
- for (p = frame_exp;
- *p && !ISSPACE (*p);
- p++);
- std::string addr_string (frame_exp, p - frame_exp);
- frame_exp = p;
-
- /* NOTE: Parse and evaluate expression, but do not use
- functions such as parse_and_eval_long or
- parse_and_eval_address to also extract the value.
- Instead value_as_long and value_as_address are used.
- This avoids problems with expressions that contain
- side-effects. */
- if (numargs >= ARRAY_SIZE (args))
- error (_("Too many args in frame specification"));
- args[numargs++] = parse_and_eval (addr_string.c_str ());
- }
- }
-
- /* If no args, default to the selected frame. */
- if (numargs == 0)
- {
- if (selected_frame_p != NULL)
- (*selected_frame_p) = 1;
- return get_selected_frame (_("No stack."));
- }
-
- /* None of the remaining use the selected frame. */
- if (selected_frame_p != NULL)
- (*selected_frame_p) = 0;
-
- /* Assume the single arg[0] is an integer, and try using that to
- select a frame relative to current. */
- if (numargs == 1)
- {
- struct frame_info *fid;
- int level = value_as_long (args[0]);
-
- fid = find_relative_frame (get_current_frame (), &level);
- if (level == 0)
- /* find_relative_frame was successful. */
- return fid;
- }
-
- /* Convert each value into a corresponding address. */
- {
- int i;
-
- for (i = 0; i < numargs; i++)
- addrs[i] = value_as_address (args[i]);
- }
-
- /* Assume that the single arg[0] is an address, use that to identify
- a frame with a matching ID. Should this also accept stack/pc or
- stack/pc/special. */
- if (numargs == 1)
- {
- struct frame_id id = frame_id_build_wild (addrs[0]);
- struct frame_info *fid;
-
- /* 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;
- }
- }
- }
-
- /* We couldn't identify the frame as an existing frame, but
- perhaps we can create one with a single argument. */
- if (numargs == 1)
- return create_new_frame (addrs[0], 0);
- else if (numargs == 2)
- return create_new_frame (addrs[0], addrs[1]);
- else
- error (_("Too many args in frame specification"));
+ /* This is used to complete function names within a stack. It would be
+ nice if we only offered functions that were actually in the stack.
+ However, this would mean unwinding the stack to completion, which
+ could take too long, or on a corrupted stack, possibly not end.
+ Instead, we offer all symbol names as a safer choice. */
+ collect_symbol_completion_matches (tracker,
+ complete_symbol_mode::EXPRESSION,
+ symbol_name_match_type::EXPRESSION,
+ text, word);
}
-/* Print verbosely the selected frame or the frame at address
- ADDR_EXP. Absolutely all information in the frame is printed. */
+/* Core of all the "info frame" sub-commands. Print information about a
+ frame FI. If SELECTED_FRAME_P is true then the user didn't provide a
+ frame specification, they just entered 'info frame'. If the user did
+ provide a frame specification (for example 'info frame 0', 'info frame
+ level 1') then SELECTED_FRAME_P will be false. */
static void
-info_frame_command (const char *addr_exp, int from_tty)
+info_frame_command_core (struct frame_info *fi, bool selected_frame_p)
{
- struct frame_info *fi;
struct symbol *func;
struct symtab *s;
struct frame_info *calling_frame_info;
@@ -1393,7 +1295,6 @@ info_frame_command (const char *addr_exp, int from_tty)
const char *funname = 0;
enum language funlang = language_unknown;
const char *pc_regname;
- int selected_frame_p;
struct gdbarch *gdbarch;
CORE_ADDR frame_pc;
int frame_pc_p;
@@ -1401,7 +1302,6 @@ info_frame_command (const char *addr_exp, int from_tty)
CORE_ADDR caller_pc = 0;
int caller_pc_p = 0;
- fi = parse_frame_specification (addr_exp, &selected_frame_p);
gdbarch = get_frame_arch (fi);
/* Name of the value returned by get_frame_pc(). Per comments, "pc"
@@ -1742,6 +1642,157 @@ trailing_outermost_frame (int count)
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;
+
/* Print briefly all stack frames or just the innermost COUNT_EXP
frames. */
@@ -2230,39 +2281,6 @@ find_relative_frame (struct frame_info *frame, int *level_offset_ptr)
return frame;
}
-/* The "select_frame" command. With no argument this is a NOP.
- Select the frame at level LEVEL_EXP if it is a valid level.
- Otherwise, treat LEVEL_EXP as an address expression and select it.
-
- See parse_frame_specification for more info on proper frame
- expressions. */
-
-void
-select_frame_command (const char *level_exp, int from_tty)
-{
- struct frame_info *prev_frame = get_selected_frame_if_set ();
-
- select_frame (parse_frame_specification (level_exp, NULL));
- if (get_selected_frame_if_set () != prev_frame)
- gdb::observers::user_selected_context_changed.notify (USER_SELECTED_FRAME);
-}
-
-/* The "frame" command. With no argument, print the selected frame
- briefly. With an argument, behave like select_frame and then print
- the selected frame. */
-
-static void
-frame_command (const char *level_exp, int from_tty)
-{
- struct frame_info *prev_frame = get_selected_frame_if_set ();
-
- select_frame (parse_frame_specification (level_exp, NULL));
- 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);
-}
-
/* Select the frame up one or COUNT_EXP stack levels from the
previously selected frame, and print it briefly. */
@@ -2716,13 +2734,61 @@ faas_command (const char *cmd, int 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;
+}
+
+
+
+/* Commands with a prefix of `frame apply'. */
+static struct cmd_list_element *frame_apply_cmd_list = NULL;
+
/* Commands with a prefix of `frame'. */
-struct cmd_list_element *frame_cmd_list = NULL;
+static struct cmd_list_element *frame_cmd_list = NULL;
+
+/* Commands with a prefix of `select frame'. */
+static struct cmd_list_element *select_frame_cmd_list = NULL;
+
+/* Commands with a prefix of `info frame'. */
+static struct cmd_list_element *info_frame_cmd_list = NULL;
void
_initialize_stack (void)
{
- static struct cmd_list_element *frame_apply_list = NULL;
+ struct cmd_list_element *cmd;
add_com ("return", class_stack, return_command, _("\
Make selected stack frame return to its caller.\n\
@@ -2746,12 +2812,12 @@ 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_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."),
- &frame_cmd_list, "frame ", 1, &cmdlist);
+ add_prefix_cmd ("frame", class_stack,
+ &frame_cmd.base_command, _("\
+Select and print a stack frame.\n\
+With no argument, print the selected stack frame. (See also \"info frame\").\n\
+A single numerical argument specifies the frame to select."),
+ &frame_cmd_list, "frame ", 1, &cmdlist);
add_com_alias ("f", "frame", class_stack, 1);
@@ -2769,7 +2835,7 @@ or produces no output."
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);
+ &frame_apply_cmd_list, "frame apply ", 1, &frame_cmd_list);
add_cmd ("all", class_stack, frame_apply_all_command,
_("\
@@ -2777,7 +2843,7 @@ Apply a command to all frames.\n\
\n\
Usage: frame apply all [FLAG]... COMMAND\n"
FRAME_APPLY_FLAGS_HELP),
- &frame_apply_list);
+ &frame_apply_cmd_list);
add_cmd ("level", class_stack, frame_apply_level_command,
_("\
@@ -2786,19 +2852,97 @@ Apply a command to a list of frames.\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);
+ &frame_apply_cmd_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, _("\
+
+ add_prefix_cmd ("frame", class_stack,
+ &frame_cmd.base_command, _("\
+Select and print a stack frame.\n\
+With no argument, print the selected stack frame. (See also \"info frame\").\n\
+A single numerical argument specifies the frame to select."),
+ &frame_cmd_list, "frame ", 1, &cmdlist);
+ add_com_alias ("f", "frame", class_stack, 1);
+
+ add_cmd ("address", class_stack, &frame_cmd.address,
+ _("\
+Select and print a stack frame by stack address\n\
+\n\
+Usage: frame address STACK-ADDRESS"),
+ &frame_cmd_list);
+
+ add_cmd ("view", class_stack, &frame_cmd.view,
+ _("\
+View a stack frame that might be outside the current backtrace.\n\
+\n\
+Usage: frame view STACK-ADDRESS\n\
+ frame view STACK-ADDRESS PC-ADDRESS"),
+ &frame_cmd_list);
+
+ cmd = add_cmd ("function", class_stack, &frame_cmd.function,
+ _("\
+Select and print a stack frame by function name.\n\
+\n\
+Usage: frame function NAME\n\
+\n\
+The innermost frame that visited function NAME is selected."),
+ &frame_cmd_list);
+ set_cmd_completer (cmd, frame_selection_by_function_completer);
+
+
+ add_cmd ("level", class_stack, &frame_cmd.level,
+ _("\
+Select and print a stack frame by level.\n\
+\n\
+Usage: frame level LEVEL"),
+ &frame_cmd_list);
+
+ cmd = add_prefix_cmd_suppress_notification ("select-frame", class_stack,
+ &select_frame_cmd.base_command, _("\
Select a stack frame without printing anything.\n\
-An argument specifies the frame to select.\n\
-It can be a stack frame number or the address of the frame."),
+A single numerical argument specifies the frame to select."),
+ &select_frame_cmd_list, "select-frame ", 1, &cmdlist,
+ &cli_suppress_notification.user_selected_context);
+
+ add_cmd_suppress_notification ("address", class_stack,
+ &select_frame_cmd.address, _("\
+Select a stack frame by stack address.\n\
+\n\
+Usage: select-frame address STACK-ADDRESS"),
+ &select_frame_cmd_list,
+ &cli_suppress_notification.user_selected_context);
+
+
+ add_cmd_suppress_notification ("view", class_stack,
+ &select_frame_cmd.view, _("\
+Select a stack frame that might be outside the current backtrace.\n\
+\n\
+Usage: select-frame view STACK-ADDRESS\n\
+ select-frame view STACK-ADDRESS PC-ADDRESS"),
+ &select_frame_cmd_list,
&cli_suppress_notification.user_selected_context);
+ cmd = add_cmd_suppress_notification ("function", class_stack,
+ &select_frame_cmd.function, _("\
+Select a stack frame by function name.\n\
+\n\
+Usage: select-frame function NAME"),
+ &select_frame_cmd_list,
+ &cli_suppress_notification.user_selected_context);
+ set_cmd_completer (cmd, frame_selection_by_function_completer);
+
+ add_cmd_suppress_notification ("level", class_stack,
+ &select_frame_cmd.level, _("\
+Select a stack frame by level.\n\
+\n\
+Usage: select-frame level LEVEL"),
+ &select_frame_cmd_list,
+ &cli_suppress_notification.user_selected_context);
+
add_com ("backtrace", class_stack, backtrace_command, _("\
Print backtrace of all stack frames, or innermost COUNT frames.\n\
Usage: backtrace [QUALIFIERS]... [COUNT]\n\
@@ -2812,9 +2956,45 @@ on this backtrace."));
add_info ("stack", backtrace_command,
_("Backtrace of the stack, or innermost COUNT frames."));
add_info_alias ("s", "stack", 1);
- add_info ("frame", info_frame_command,
- _("All about selected stack frame, or frame at ADDR."));
+
+ add_prefix_cmd ("frame", class_info, &info_frame_cmd.base_command,
+ _("All about the selected stack frame.\n\
+With no arguments, displays information about the currently selected stack\n\
+frame. Alternatively a frame specification may be provided (See \"frame\")\n\
+the information is then printed about the specified frame."),
+ &info_frame_cmd_list, "info frame ", 1, &infolist);
add_info_alias ("f", "frame", 1);
+
+ add_cmd ("address", class_stack, &info_frame_cmd.address,
+ _("\
+Print information about a stack frame selected by stack address.\n\
+\n\
+Usage: info frame address STACK-ADDRESS"),
+ &info_frame_cmd_list);
+
+ add_cmd ("view", class_stack, &info_frame_cmd.view,
+ _("\
+Print information about a stack frame outside the current backtrace.\n\
+\n\
+Usage: info frame view STACK-ADDRESS\n\
+ info frame view STACK-ADDRESS PC-ADDRESS"),
+ &info_frame_cmd_list);
+
+ cmd = add_cmd ("function", class_stack, &info_frame_cmd.function,
+ _("\
+Print information about a stack frame selected by function name.\n\
+\n\
+Usage: info frame function NAME"),
+ &info_frame_cmd_list);
+ set_cmd_completer (cmd, frame_selection_by_function_completer);
+
+ add_cmd ("level", class_stack, &info_frame_cmd.level,
+ _("\
+Print information about a stack frame selected by level.\n\
+\n\
+Usage: info frame level LEVEL"),
+ &info_frame_cmd_list);
+
add_info ("locals", info_locals_command,
_("Local variables of current stack frame."));
add_info ("args", info_args_command,