diff options
author | Andrew Burgess <andrew.burgess@embecosm.com> | 2015-09-10 13:06:16 +0100 |
---|---|---|
committer | Andrew Burgess <andrew.burgess@embecosm.com> | 2018-09-28 11:59:34 +0100 |
commit | f67ffa6a785bee26bc23550670f85c6db578641f (patch) | |
tree | bc989c15856f0c9cb628d899d0ca54f8617a4911 /gdb/mi/mi-cmd-stack.c | |
parent | 5f9aecea0dfd9e8b0a728c332e8ddb105bae6054 (diff) | |
download | gdb-f67ffa6a785bee26bc23550670f85c6db578641f.zip gdb-f67ffa6a785bee26bc23550670f85c6db578641f.tar.gz gdb-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/mi/mi-cmd-stack.c')
-rw-r--r-- | gdb/mi/mi-cmd-stack.c | 77 |
1 files changed, 76 insertions, 1 deletions
diff --git a/gdb/mi/mi-cmd-stack.c b/gdb/mi/mi-cmd-stack.c index 52660bd..0679c57 100644 --- a/gdb/mi/mi-cmd-stack.c +++ b/gdb/mi/mi-cmd-stack.c @@ -35,6 +35,7 @@ #include <ctype.h> #include "mi-parse.h" #include "common/gdb_optional.h" +#include "safe-ctype.h" enum what_to_list { locals, arguments, all }; @@ -678,13 +679,87 @@ list_args_or_locals (enum what_to_list what, enum print_values values, } } +/* Read a frame specification from FRAME_EXP and return the selected frame. + Call error() if the specification is in any way invalid (so this + function never returns NULL). + + The frame specification is usually an integer level number, however if + the number does not match a valid frame level then it will be treated as + a frame address. The frame address will then be used to find a matching + frame in the stack. If no matching frame is found then a new frame will + be created. + + The use of FRAME_EXP as an address is undocumented in the GDB user + manual, this feature is supported here purely for backward + compatibility. */ + +static struct frame_info * +parse_frame_specification (const char *frame_exp) +{ + gdb_assert (frame_exp != NULL); + + /* 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. */ + struct value *arg = parse_and_eval (frame_exp); + + /* Assume ARG is an integer, and try using that to select a frame. */ + struct frame_info *fid; + int level = value_as_long (arg); + + fid = find_relative_frame (get_current_frame (), &level); + if (level == 0) + /* find_relative_frame was successful. */ + return fid; + + /* Convert the value into a corresponding address. */ + CORE_ADDR addr = value_as_address (arg); + + /* Assume that ADDR is an address, use that to identify a frame with a + matching ID. */ + struct frame_id id = frame_id_build_wild (addr); + + /* 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. */ + return create_new_frame (addr, 0); +} + +/* Implement the -stack-select-frame MI command. */ + void mi_cmd_stack_select_frame (const char *command, char **argv, int argc) { if (argc == 0 || argc > 1) error (_("-stack-select-frame: Usage: FRAME_SPEC")); - select_frame_command (argv[0], 1 /* not used */ ); + select_frame_for_mi (parse_frame_specification (argv[0])); } void |