diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c3453b0510a..08621ca805d 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,55 @@ +2019-06-13 Pedro Alves + + * frame.c: Include "cli/cli-option.h. + (user_set_backtrace_options): New. + (backtrace_past_main, backtrace_past_entry, backtrace_limit): + Delete. + (get_prev_frame): Adjust. + (boolean_option_def, uinteger_option_def) + (set_backtrace_option_defs): New. + (_initialize_frame): Adjust and use + gdb::option::add_setshow_cmds_for_options to install "set + backtrace past-main" and "set backtrace past-entry". + * frame.h: Include "cli/cli-option.h". + (struct frame_print_options): Forward declare. + (print_frame_arguments_all, print_frame_arguments_scalars) + (print_frame_arguments_none): Declare. + (print_entry_values): Delete declaration. + (struct frame_print_options, user_frame_print_options): New. + (struct set_backtrace_options): New. + (set_backtrace_option_defs, user_set_backtrace_options): Declare. + * mi/mi-cmd-stack.c (mi_cmd_stack_list_frames) + (mi_cmd_stack_list_locals, mi_cmd_stack_list_args) + (mi_cmd_stack_list_variables): Pass down USER_FRAME_PRINT_OPTIONS. + (list_args_or_locals): Add frame_print_options parameter. + (mi_cmd_stack_info_frame): Pass down USER_FRAME_PRINT_OPTIONS. + * python/py-framefilter.c (enumerate_args): Pass down + USER_FRAME_PRINT_OPTIONS. + * stack.c: Include "cli/cli-option.h". + (print_frame_arguments_all, print_frame_arguments_scalars) + (print_frame_arguments_none): Declare. + (print_raw_frame_arguments, print_entry_values): Delete. + (user_frame_print_options): New. + (boolean_option_def, enum_option_def, frame_print_option_defs): + New. + (struct backtrace_cmd_options): New. + (bt_flag_option_def): New. + (backtrace_command_option_defs): New. + (print_stack_frame): Pass down USER_FRAME_PRINT_OPTIONS. + (print_frame_arg, read_frame_arg, print_frame_args) + (print_frame_info, print_frame): Add frame_print_options parameter + and use it. + (info_frame_command_core): Pass down USER_FRAME_PRINT_OPTIONS. + (backtrace_command_1): Add frame_print_options and + backtrace_cmd_options parameters and use them. + (make_backtrace_options_def_group): New. + (backtrace_command): Process command options with + gdb::option::process_options. + (backtrace_command_completer): New. + (_initialize_stack): Extend "backtrace"'s help to mention + supported options. Install completer for "backtrace". + Install some settings commands with add_setshow_cmds_for_options. + 2019-06-13 Pedro Alves * NEWS (Changed commands): Mention set/show print raw-frame-arguments, diff --git a/gdb/frame.c b/gdb/frame.c index f4303d13cc1..84e0397db98 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -42,6 +42,7 @@ #include "tracepoint.h" #include "hashtab.h" #include "valprint.h" +#include "cli/cli-option.h" /* The sentinel frame terminates the innermost end of the frame chain. If unwound, it returns the information needed to construct an @@ -52,6 +53,9 @@ static struct frame_info *sentinel_frame; +/* The values behind the global "set backtrace ..." settings. */ +set_backtrace_options user_set_backtrace_options; + static struct frame_info *get_prev_frame_raw (struct frame_info *this_frame); static const char *frame_stop_reason_symbol_string (enum unwind_stop_reason reason); @@ -295,9 +299,8 @@ show_frame_debug (struct ui_file *file, int from_tty, fprintf_filtered (file, _("Frame debugging is %s.\n"), value); } -/* Flag to indicate whether backtraces should stop at main et.al. */ +/* Implementation of "show backtrace past-main". */ -static int backtrace_past_main; static void show_backtrace_past_main (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -308,7 +311,8 @@ show_backtrace_past_main (struct ui_file *file, int from_tty, value); } -static int backtrace_past_entry; +/* Implementation of "show backtrace past-entry". */ + static void show_backtrace_past_entry (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -318,7 +322,8 @@ show_backtrace_past_entry (struct ui_file *file, int from_tty, value); } -static unsigned int backtrace_limit = UINT_MAX; +/* Implementation of "show backtrace limit". */ + static void show_backtrace_limit (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -2276,7 +2281,7 @@ get_prev_frame (struct frame_info *this_frame) point inside the main function. */ if (this_frame->level >= 0 && get_frame_type (this_frame) == NORMAL_FRAME - && !backtrace_past_main + && !user_set_backtrace_options.backtrace_past_main && frame_pc_p && inside_main_func (this_frame)) /* Don't unwind past main(). Note, this is done _before_ the @@ -2293,7 +2298,7 @@ get_prev_frame (struct frame_info *this_frame) being 1-based and the level being 0-based, and the other accounts for the level of the new frame instead of the level of the current frame. */ - if (this_frame->level + 2 > backtrace_limit) + if (this_frame->level + 2 > user_set_backtrace_options.backtrace_limit) { frame_debug_got_null_frame (this_frame, "backtrace limit exceeded"); return NULL; @@ -2323,7 +2328,7 @@ get_prev_frame (struct frame_info *this_frame) application. */ if (this_frame->level >= 0 && get_frame_type (this_frame) == NORMAL_FRAME - && !backtrace_past_entry + && !user_set_backtrace_options.backtrace_past_entry && frame_pc_p && inside_entry_func (this_frame)) { @@ -2896,6 +2901,39 @@ show_backtrace_cmd (const char *args, int from_tty) cmd_show_list (show_backtrace_cmdlist, from_tty, ""); } +/* Definition of the "set backtrace" settings that are exposed as + "backtrace" command options. */ + +using boolean_option_def + = gdb::option::boolean_option_def; +using uinteger_option_def + = gdb::option::uinteger_option_def; + +const gdb::option::option_def set_backtrace_option_defs[] = { + + boolean_option_def { + "past-main", + [] (set_backtrace_options *opt) { return &opt->backtrace_past_main; }, + show_backtrace_past_main, /* show_cmd_cb */ + N_("Set whether backtraces should continue past \"main\"."), + N_("Show whether backtraces should continue past \"main\"."), + N_("Normally the caller of \"main\" is not of interest, so GDB will terminate\n\ +the backtrace at \"main\". Set this if you need to see the rest\n\ +of the stack trace."), + }, + + boolean_option_def { + "past-entry", + [] (set_backtrace_options *opt) { return &opt->backtrace_past_entry; }, + show_backtrace_past_entry, /* show_cmd_cb */ + N_("Set whether backtraces should continue past the entry point of a program."), + N_("Show whether backtraces should continue past the entry point of a program."), + N_("Normally there are no callers beyond the entry point of a program, so GDB\n\ +will terminate the backtrace there. Set this if you need to see\n\ +the rest of the stack trace."), + }, +}; + void _initialize_frame (void) { @@ -2916,34 +2954,8 @@ Show backtrace variables such as the backtrace limit"), &show_backtrace_cmdlist, "show backtrace ", 0/*allow-unknown*/, &showlist); - add_setshow_boolean_cmd ("past-main", class_obscure, - &backtrace_past_main, _("\ -Set whether backtraces should continue past \"main\"."), _("\ -Show whether backtraces should continue past \"main\"."), _("\ -Normally the caller of \"main\" is not of interest, so GDB will terminate\n\ -the backtrace at \"main\". Set this variable if you need to see the rest\n\ -of the stack trace."), - NULL, - show_backtrace_past_main, - &set_backtrace_cmdlist, - &show_backtrace_cmdlist); - - add_setshow_boolean_cmd ("past-entry", class_obscure, - &backtrace_past_entry, _("\ -Set whether backtraces should continue past the entry point of a program."), - _("\ -Show whether backtraces should continue past the entry point of a program."), - _("\ -Normally there are no callers beyond the entry point of a program, so GDB\n\ -will terminate the backtrace there. Set this variable if you need to see\n\ -the rest of the stack trace."), - NULL, - show_backtrace_past_entry, - &set_backtrace_cmdlist, - &show_backtrace_cmdlist); - add_setshow_uinteger_cmd ("limit", class_obscure, - &backtrace_limit, _("\ + &user_set_backtrace_options.backtrace_limit, _("\ Set an upper bound on the number of backtrace levels."), _("\ Show the upper bound on the number of backtrace levels."), _("\ No more than the specified number of frames can be displayed or examined.\n\ @@ -2953,6 +2965,10 @@ Literal \"unlimited\" or zero means no limit."), &set_backtrace_cmdlist, &show_backtrace_cmdlist); + gdb::option::add_setshow_cmds_for_options + (class_stack, &user_set_backtrace_options, + set_backtrace_option_defs, &set_backtrace_cmdlist, &show_backtrace_cmdlist); + /* Debug this files internals. */ add_setshow_zuinteger_cmd ("frame", class_maintenance, &frame_debug, _("\ Set frame debugging."), _("\ diff --git a/gdb/frame.h b/gdb/frame.h index 0a0baf46a0c..a79eeeeab16 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -70,6 +70,7 @@ */ #include "language.h" +#include "cli/cli-option.h" struct symtab_and_line; struct frame_unwind; @@ -78,6 +79,7 @@ struct block; struct gdbarch; struct ui_file; struct ui_out; +struct frame_print_options; /* Status of a given frame's stack. */ @@ -753,7 +755,8 @@ extern void print_stack_frame (struct frame_info *, int print_level, enum print_what print_what, int set_current_sal); -extern void print_frame_info (struct frame_info *, int print_level, +extern void print_frame_info (const frame_print_options &fp_opts, + struct frame_info *, int print_level, enum print_what print_what, int args, int set_current_sal); @@ -764,6 +767,12 @@ extern int deprecated_frame_register_read (struct frame_info *frame, int regnum, /* From stack.c. */ +/* The possible choices of "set print frame-arguments". */ +extern const char print_frame_arguments_all[]; +extern const char print_frame_arguments_scalars[]; +extern const char print_frame_arguments_none[]; + +/* The possible choices of "set print entry-values". */ extern const char print_entry_values_no[]; extern const char print_entry_values_only[]; extern const char print_entry_values_preferred[]; @@ -771,7 +780,22 @@ extern const char print_entry_values_if_needed[]; extern const char print_entry_values_both[]; extern const char print_entry_values_compact[]; extern const char print_entry_values_default[]; -extern const char *print_entry_values; + +/* Data for the frame-printing "set print" settings exposed as command + options. */ + +struct frame_print_options +{ + const char *print_frame_arguments = print_frame_arguments_scalars; + const char *print_entry_values = print_entry_values_default; + + /* If non-zero, don't invoke pretty-printers for frame + arguments. */ + int print_raw_frame_arguments; +}; + +/* The values behind the global "set print ..." settings. */ +extern frame_print_options user_frame_print_options; /* Inferior function parameter value read in from a frame. */ @@ -800,7 +824,8 @@ struct frame_arg const char *entry_kind; }; -extern void read_frame_arg (struct symbol *sym, struct frame_info *frame, +extern void read_frame_arg (const frame_print_options &fp_opts, + symbol *sym, frame_info *frame, struct frame_arg *argp, struct frame_arg *entryargp); extern void read_frame_local (struct symbol *sym, struct frame_info *frame, @@ -881,4 +906,28 @@ extern struct frame_info *skip_tailcall_frames (struct frame_info *frame); extern struct frame_info *skip_unwritable_frames (struct frame_info *frame); +/* Data for the "set backtrace" settings. */ + +struct set_backtrace_options +{ + /* Flag to indicate whether backtraces should continue past + main. */ + int backtrace_past_main = 0; + + /* Flag to indicate whether backtraces should continue past + entry. */ + int backtrace_past_entry = 0; + + /* Upper bound on the number of backtrace levels. Note this is not + exposed as a command option, because "backtrace" and "frame + apply" already have other means to set a frame count limit. */ + unsigned int backtrace_limit = UINT_MAX; +}; + +/* The corresponding option definitions. */ +extern const gdb::option::option_def set_backtrace_option_defs[2]; + +/* The values behind the global "set backtrace ..." settings. */ +extern set_backtrace_options user_set_backtrace_options; + #endif /* !defined (FRAME_H) */ diff --git a/gdb/mi/mi-cmd-stack.c b/gdb/mi/mi-cmd-stack.c index 0dc0b55bc91..80bc7a1968e 100644 --- a/gdb/mi/mi-cmd-stack.c +++ b/gdb/mi/mi-cmd-stack.c @@ -39,7 +39,8 @@ enum what_to_list { locals, arguments, all }; -static void list_args_or_locals (enum what_to_list what, +static void list_args_or_locals (const frame_print_options &fp_opts, + enum what_to_list what, enum print_values values, struct frame_info *fi, int skip_unavailable); @@ -175,7 +176,8 @@ mi_cmd_stack_list_frames (const char *command, char **argv, int argc) QUIT; /* Print the location and the address always, even for level 0. If args is 0, don't print the arguments. */ - print_frame_info (fi, 1, LOC_AND_ADDRESS, 0 /* args */, 0); + print_frame_info (user_frame_print_options, + fi, 1, LOC_AND_ADDRESS, 0 /* args */, 0); } } } @@ -275,7 +277,8 @@ mi_cmd_stack_list_locals (const char *command, char **argv, int argc) if "--no-frame-filters" has been specified from the command. */ if (! frame_filters || raw_arg || result == EXT_LANG_BT_NO_FILTERS) { - list_args_or_locals (locals, print_value, frame, + list_args_or_locals (user_frame_print_options, + locals, print_value, frame, skip_unavailable); } } @@ -389,7 +392,8 @@ mi_cmd_stack_list_args (const char *command, char **argv, int argc) QUIT; ui_out_emit_tuple tuple_emitter (uiout, "frame"); uiout->field_int ("level", i); - list_args_or_locals (arguments, print_values, fi, skip_unavailable); + list_args_or_locals (user_frame_print_options, + arguments, print_values, fi, skip_unavailable); } } } @@ -465,7 +469,8 @@ mi_cmd_stack_list_variables (const char *command, char **argv, int argc) if "--no-frame-filters" has been specified from the command. */ if (! frame_filters || raw_arg || result == EXT_LANG_BT_NO_FILTERS) { - list_args_or_locals (all, print_value, frame, + list_args_or_locals (user_frame_print_options, + all, print_value, frame, skip_unavailable); } } @@ -557,7 +562,8 @@ list_arg_or_local (const struct frame_arg *arg, enum what_to_list what, are available. */ static void -list_args_or_locals (enum what_to_list what, enum print_values values, +list_args_or_locals (const frame_print_options &fp_opts, + enum what_to_list what, enum print_values values, struct frame_info *fi, int skip_unavailable) { const struct block *block; @@ -652,7 +658,7 @@ list_args_or_locals (enum what_to_list what, enum print_values values, { case PRINT_ALL_VALUES: if (SYMBOL_IS_ARGUMENT (sym)) - read_frame_arg (sym2, fi, &arg, &entryarg); + read_frame_arg (fp_opts, sym2, fi, &arg, &entryarg); else read_frame_local (sym2, fi, &arg); } @@ -764,5 +770,6 @@ mi_cmd_stack_info_frame (const char *command, char **argv, int argc) if (argc > 0) error (_("-stack-info-frame: No arguments allowed")); - print_frame_info (get_selected_frame (NULL), 1, LOC_AND_ADDRESS, 0, 1); + print_frame_info (user_frame_print_options, + get_selected_frame (NULL), 1, LOC_AND_ADDRESS, 0, 1); } diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c index 017ea90f619..95ad410f23f 100644 --- a/gdb/python/py-framefilter.c +++ b/gdb/python/py-framefilter.c @@ -481,7 +481,8 @@ enumerate_args (PyObject *iter, return EXT_LANG_BT_ERROR; } - read_frame_arg (sym, frame, &arg, &entryarg); + read_frame_arg (user_frame_print_options, + sym, frame, &arg, &entryarg); gdb::unique_xmalloc_ptr arg_holder (arg.error); gdb::unique_xmalloc_ptr entry_holder (entryarg.error); diff --git a/gdb/stack.c b/gdb/stack.c index d1b195c84d6..5e878d3c887 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -52,16 +52,22 @@ #include "extension.h" #include "observable.h" #include "common/def-vector.h" +#include "cli/cli-option.h" /* The possible choices of "set print frame-arguments", and the value of this setting. */ -static const char *const print_frame_arguments_choices[] = - {"all", "scalars", "none", NULL}; -static const char *print_frame_arguments = "scalars"; +const char print_frame_arguments_all[] = "all"; +const char print_frame_arguments_scalars[] = "scalars"; +const char print_frame_arguments_none[] = "none"; -/* If non-zero, don't invoke pretty-printers for frame arguments. */ -static int print_raw_frame_arguments; +static const char *const print_frame_arguments_choices[] = +{ + print_frame_arguments_all, + print_frame_arguments_scalars, + print_frame_arguments_none, + NULL +}; /* The possible choices of "set print entry-values", and the value of this setting. */ @@ -84,7 +90,85 @@ static const char *const print_entry_values_choices[] = print_entry_values_default, NULL }; -const char *print_entry_values = print_entry_values_default; + +/* See frame.h. */ +frame_print_options user_frame_print_options; + +/* Option definitions for some frame-related "set print ..." + settings. */ + +using boolean_option_def + = gdb::option::boolean_option_def; +using enum_option_def + = gdb::option::enum_option_def; + +static const gdb::option::option_def frame_print_option_defs[] = { + + enum_option_def { + "entry-values", + print_entry_values_choices, + [] (frame_print_options *opt) { return &opt->print_entry_values; }, + NULL, /* show_cmd_cb */ + N_("Set printing of function arguments at function entry"), + N_("Show printing of function arguments at function entry"), + N_("GDB can sometimes determine the values of function arguments at entry,\n\ +in addition to their current values. This option tells GDB whether\n\ +to print the current value, the value at entry (marked as val@entry),\n\ +or both. Note that one or both of these values may be ."), + }, + + enum_option_def { + "frame-arguments", + print_frame_arguments_choices, + [] (frame_print_options *opt) { return &opt->print_frame_arguments; }, + NULL, /* show_cmd_cb */ + N_("Set printing of non-scalar frame arguments"), + N_("Show printing of non-scalar frame arguments"), + NULL /* help_doc */ + }, + + boolean_option_def { + "raw-frame-arguments", + [] (frame_print_options *opt) { return &opt->print_raw_frame_arguments; }, + NULL, /* show_cmd_cb */ + N_("Set whether to print frame arguments in raw form."), + N_("Show whether to print frame arguments in raw form."), + N_("If set, frame arguments are printed in raw form, bypassing any\n\ +pretty-printers for that value.") + }, +}; + +/* Options for the "backtrace" command. */ + +struct backtrace_cmd_options +{ + int full = 0; + int no_filters = 0; + int hide = 0; +}; + +using bt_flag_option_def + = gdb::option::flag_option_def; + +static const gdb::option::option_def backtrace_command_option_defs[] = { + bt_flag_option_def { + "full", + [] (backtrace_cmd_options *opt) { return &opt->full; }, + N_("Print values of local variables.") + }, + + bt_flag_option_def { + "no-filters", + [] (backtrace_cmd_options *opt) { return &opt->no_filters; }, + N_("Prohibit frame filters from executing on a backtrace."), + }, + + bt_flag_option_def { + "hide", + [] (backtrace_cmd_options *opt) { return &opt->hide; }, + N_("Causes Python frame filter elided frames to not be printed."), + }, +}; /* Prototypes for local functions. */ @@ -93,7 +177,8 @@ static void print_frame_local_vars (struct frame_info *frame, const char *regexp, const char *t_regexp, int num_tabs, struct ui_file *stream); -static void print_frame (struct frame_info *frame, int print_level, +static void print_frame (const frame_print_options &opts, + frame_info *frame, int print_level, enum print_what print_what, int print_args, struct symtab_and_line sal); @@ -177,7 +262,8 @@ print_stack_frame (struct frame_info *frame, int print_level, try { - print_frame_info (frame, print_level, print_what, 1 /* print_args */, + print_frame_info (user_frame_print_options, + frame, print_level, print_what, 1 /* print_args */, set_current_sal); if (set_current_sal) set_current_sal_from_frame (frame); @@ -225,7 +311,8 @@ print_frame_nameless_args (struct frame_info *frame, long start, int num, iff it should not be printed accoring to user settings. */ static void -print_frame_arg (const struct frame_arg *arg) +print_frame_arg (const frame_print_options &fp_opts, + const struct frame_arg *arg) { struct ui_out *uiout = current_uiout; @@ -269,7 +356,7 @@ print_frame_arg (const struct frame_arg *arg) try { const struct language_defn *language; - struct value_print_options opts; + struct value_print_options vp_opts; /* Avoid value_print because it will deref ref parameters. We just want to print their addresses. Print ??? for args whose @@ -286,14 +373,15 @@ print_frame_arg (const struct frame_arg *arg) else language = current_language; - get_no_prettyformat_print_options (&opts); - opts.deref_ref = 1; - opts.raw = print_raw_frame_arguments; + get_no_prettyformat_print_options (&vp_opts); + vp_opts.deref_ref = 1; + vp_opts.raw = fp_opts.print_raw_frame_arguments; /* True in "summary" mode, false otherwise. */ - opts.summary = !strcmp (print_frame_arguments, "scalars"); + vp_opts.summary + = fp_opts.print_frame_arguments == print_frame_arguments_scalars; - common_val_print (arg->val, &stb, 2, &opts, language); + common_val_print (arg->val, &stb, 2, &vp_opts, language); } catch (const gdb_exception_error &except) { @@ -333,15 +421,16 @@ read_frame_local (struct symbol *sym, struct frame_info *frame, exception. */ void -read_frame_arg (struct symbol *sym, struct frame_info *frame, +read_frame_arg (const frame_print_options &fp_opts, + symbol *sym, frame_info *frame, struct frame_arg *argp, struct frame_arg *entryargp) { struct value *val = NULL, *entryval = NULL; char *val_error = NULL, *entryval_error = NULL; int val_equal = 0; - if (print_entry_values != print_entry_values_only - && print_entry_values != print_entry_values_preferred) + if (fp_opts.print_entry_values != print_entry_values_only + && fp_opts.print_entry_values != print_entry_values_preferred) { try { @@ -356,8 +445,8 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame, if (SYMBOL_COMPUTED_OPS (sym) != NULL && SYMBOL_COMPUTED_OPS (sym)->read_variable_at_entry != NULL - && print_entry_values != print_entry_values_no - && (print_entry_values != print_entry_values_if_needed + && fp_opts.print_entry_values != print_entry_values_no + && (fp_opts.print_entry_values != print_entry_values_if_needed || !val || value_optimized_out (val))) { try @@ -379,8 +468,8 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame, if (entryval != NULL && value_optimized_out (entryval)) entryval = NULL; - if (print_entry_values == print_entry_values_compact - || print_entry_values == print_entry_values_default) + if (fp_opts.print_entry_values == print_entry_values_compact + || fp_opts.print_entry_values == print_entry_values_default) { /* For MI do not try to use print_entry_values_compact for ARGP. */ @@ -463,7 +552,7 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame, if (entryval == NULL) { - if (print_entry_values == print_entry_values_preferred) + if (fp_opts.print_entry_values == print_entry_values_preferred) { gdb_assert (val == NULL); @@ -477,18 +566,18 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame, strcpy (val_error, except.what ()); } } - if (print_entry_values == print_entry_values_only - || print_entry_values == print_entry_values_both - || (print_entry_values == print_entry_values_preferred + if (fp_opts.print_entry_values == print_entry_values_only + || fp_opts.print_entry_values == print_entry_values_both + || (fp_opts.print_entry_values == print_entry_values_preferred && (!val || value_optimized_out (val)))) { entryval = allocate_optimized_out_value (SYMBOL_TYPE (sym)); entryval_error = NULL; } } - if ((print_entry_values == print_entry_values_compact - || print_entry_values == print_entry_values_if_needed - || print_entry_values == print_entry_values_preferred) + if ((fp_opts.print_entry_values == print_entry_values_compact + || fp_opts.print_entry_values == print_entry_values_if_needed + || fp_opts.print_entry_values == print_entry_values_preferred) && (!val || value_optimized_out (val)) && entryval != NULL) { val = NULL; @@ -500,8 +589,9 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame, argp->error = val_error ? xstrdup (val_error) : NULL; if (!val && !val_error) argp->entry_kind = print_entry_values_only; - else if ((print_entry_values == print_entry_values_compact - || print_entry_values == print_entry_values_default) && val_equal) + else if ((fp_opts.print_entry_values == print_entry_values_compact + || fp_opts.print_entry_values == print_entry_values_default) + && val_equal) { argp->entry_kind = print_entry_values_compact; gdb_assert (!current_uiout->is_mi_like_p ()); @@ -528,7 +618,8 @@ read_frame_arg (struct symbol *sym, struct frame_info *frame, ints of arguments according to the stack frame". */ static void -print_frame_args (struct symbol *func, struct frame_info *frame, +print_frame_args (const frame_print_options &fp_opts, + struct symbol *func, struct frame_info *frame, int num, struct ui_file *stream) { struct ui_out *uiout = current_uiout; @@ -540,7 +631,8 @@ print_frame_args (struct symbol *func, struct frame_info *frame, /* Number of ints of arguments that we have printed so far. */ int args_printed = 0; /* True if we should print arguments, false otherwise. */ - int print_args = strcmp (print_frame_arguments, "none"); + bool print_args + = fp_opts.print_frame_arguments != print_frame_arguments_none; if (func) { @@ -674,10 +766,10 @@ print_frame_args (struct symbol *func, struct frame_info *frame, entryarg.entry_kind = print_entry_values_no; } else - read_frame_arg (sym, frame, &arg, &entryarg); + read_frame_arg (fp_opts, sym, frame, &arg, &entryarg); if (arg.entry_kind != print_entry_values_only) - print_frame_arg (&arg); + print_frame_arg (fp_opts, &arg); if (entryarg.entry_kind != print_entry_values_no) { @@ -687,7 +779,7 @@ print_frame_args (struct symbol *func, struct frame_info *frame, uiout->wrap_hint (" "); } - print_frame_arg (&entryarg); + print_frame_arg (fp_opts, &entryarg); } xfree (arg.error); @@ -778,7 +870,8 @@ do_gdb_disassembly (struct gdbarch *gdbarch, messages. */ void -print_frame_info (struct frame_info *frame, int print_level, +print_frame_info (const frame_print_options &fp_opts, + frame_info *frame, int print_level, enum print_what print_what, int print_args, int set_current_sal) { @@ -855,7 +948,7 @@ print_frame_info (struct frame_info *frame, int print_level, || print_what == SRC_AND_LOC); if (location_print || !sal.symtab) - print_frame (frame, print_level, print_what, print_args, sal); + print_frame (fp_opts, frame, print_level, print_what, print_args, sal); source_print = (print_what == SRC_LINE || print_what == SRC_AND_LOC); @@ -1128,7 +1221,8 @@ find_frame_funname (struct frame_info *frame, enum language *funlang, } static void -print_frame (struct frame_info *frame, int print_level, +print_frame (const frame_print_options &fp_opts, + frame_info *frame, int print_level, enum print_what print_what, int print_args, struct symtab_and_line sal) { @@ -1198,7 +1292,7 @@ print_frame (struct frame_info *frame, int print_level, ui_out_emit_list list_emitter (uiout, "args"); try { - print_frame_args (func, frame, numargs, gdb_stdout); + print_frame_args (fp_opts, func, frame, numargs, gdb_stdout); } catch (const gdb_exception_error &e) { @@ -1477,7 +1571,8 @@ info_frame_command_core (struct frame_info *fi, bool selected_frame_p) else printf_filtered (" %d args: ", numargs); } - print_frame_args (func, fi, numargs, gdb_stdout); + print_frame_args (user_frame_print_options, + func, fi, numargs, gdb_stdout); puts_filtered ("\n"); } } @@ -1791,8 +1886,10 @@ static frame_command_helper select_frame_cmd; frames. */ static void -backtrace_command_1 (const char *count_exp, frame_filter_flags flags, - int no_filters, int from_tty) +backtrace_command_1 (const frame_print_options &fp_opts, + const backtrace_cmd_options &bt_opts, + const char *count_exp, int from_tty) + { struct frame_info *fi; int count; @@ -1821,7 +1918,14 @@ backtrace_command_1 (const char *count_exp, frame_filter_flags flags, count = -1; } - if (! no_filters) + frame_filter_flags flags = 0; + + if (bt_opts.full) + flags |= PRINT_LOCALS; + if (bt_opts.hide) + flags |= PRINT_HIDE; + + if (!bt_opts.no_filters) { enum ext_lang_frame_args arg_type; @@ -1829,9 +1933,9 @@ backtrace_command_1 (const char *count_exp, frame_filter_flags flags, if (from_tty) flags |= PRINT_MORE_FRAMES; - if (!strcmp (print_frame_arguments, "scalars")) + if (fp_opts.print_frame_arguments == print_frame_arguments_scalars) arg_type = CLI_SCALAR_VALUES; - else if (!strcmp (print_frame_arguments, "all")) + else if (fp_opts.print_frame_arguments == print_frame_arguments_all) arg_type = CLI_ALL_VALUES; else arg_type = NO_VALUES; @@ -1842,8 +1946,8 @@ backtrace_command_1 (const char *count_exp, frame_filter_flags flags, } /* Run the inbuilt backtrace if there are no filters registered, or - "no-filters" has been specified from the command. */ - if (no_filters || result == EXT_LANG_BT_NO_FILTERS) + "-no-filters" has been specified from the command. */ + if (bt_opts.no_filters || result == EXT_LANG_BT_NO_FILTERS) { struct frame_info *trailing; @@ -1869,7 +1973,7 @@ backtrace_command_1 (const char *count_exp, frame_filter_flags flags, hand, perhaps the code does or could be fixed to make sure the frame->prev field gets set to NULL in that case). */ - print_frame_info (fi, 1, LOCATION, 1, 0); + print_frame_info (fp_opts, fi, 1, LOCATION, 1, 0); if ((flags & PRINT_LOCALS) != 0) { struct frame_id frame_id = get_frame_id (fi); @@ -1908,17 +2012,38 @@ backtrace_command_1 (const char *count_exp, frame_filter_flags flags, } } +/* Create an option_def_group array grouping all the "backtrace" + options, with FP_OPTS, BT_CMD_OPT, SET_BT_OPTS as contexts. */ + +static inline std::array +make_backtrace_options_def_group (frame_print_options *fp_opts, + backtrace_cmd_options *bt_cmd_opts, + set_backtrace_options *set_bt_opts) +{ + return {{ + { {frame_print_option_defs}, fp_opts }, + { {set_backtrace_option_defs}, set_bt_opts }, + { {backtrace_command_option_defs}, bt_cmd_opts } + }}; +} + static void backtrace_command (const char *arg, int from_tty) { - bool filters = true; - frame_filter_flags flags = 0; + frame_print_options fp_opts = user_frame_print_options; + backtrace_cmd_options bt_cmd_opts; + set_backtrace_options set_bt_opts = user_set_backtrace_options; - if (arg) + auto grp + = make_backtrace_options_def_group (&fp_opts, &bt_cmd_opts, &set_bt_opts); + gdb::option::process_options + (&arg, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp); + + /* Parse non-'-'-prefixed qualifiers, for backwards + compatibility. */ + if (arg != NULL) { - bool done = false; - - while (!done) + while (true) { const char *save_arg = arg; std::string this_arg = extract_arg (&arg); @@ -1927,16 +2052,16 @@ backtrace_command (const char *arg, int from_tty) break; if (subset_compare (this_arg.c_str (), "no-filters")) - filters = false; + bt_cmd_opts.no_filters = true; else if (subset_compare (this_arg.c_str (), "full")) - flags |= PRINT_LOCALS; + bt_cmd_opts.full = true; else if (subset_compare (this_arg.c_str (), "hide")) - flags |= PRINT_HIDE; + bt_cmd_opts.hide = true; else { /* Not a recognized argument, so stop. */ arg = save_arg; - done = true; + break; } } @@ -1944,7 +2069,29 @@ backtrace_command (const char *arg, int from_tty) arg = NULL; } - backtrace_command_1 (arg, flags, !filters /* no frame-filters */, from_tty); + /* These options are handled quite deep in the unwind machinery, so + we get to pass them down by swapping globals. */ + scoped_restore restore_set_backtrace_options + = make_scoped_restore (&user_set_backtrace_options, set_bt_opts); + + backtrace_command_1 (fp_opts, bt_cmd_opts, arg, from_tty); +} + +/* Completer for the "backtrace" command. */ + +static void +backtrace_command_completer (struct cmd_list_element *ignore, + completion_tracker &tracker, + const char *text, const char */*word*/) +{ + const auto group + = make_backtrace_options_def_group (nullptr, nullptr, nullptr); + if (gdb::option::complete_options + (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group)) + return; + + const char *word = advance_to_expression_complete_word_point (tracker, text); + expression_completer (ignore, tracker, text, word); } /* Iterate over the local variables of a block B, calling CB with @@ -3030,13 +3177,30 @@ Usage: select-frame level LEVEL"), &select_frame_cmd_list, &cli_suppress_notification.user_selected_context); - add_com ("backtrace", class_stack, backtrace_command, _("\ + const auto backtrace_opts + = make_backtrace_options_def_group (nullptr, nullptr, nullptr); + + static std::string backtrace_help + = gdb::option::build_help (N_("\ Print backtrace of all stack frames, or innermost COUNT frames.\n\ -Usage: backtrace [QUALIFIERS]... [COUNT]\n\ -With a negative argument, print outermost -COUNT frames.\n\ -Use of the 'full' qualifier also prints the values of the local variables.\n\ -Use of the 'no-filters' qualifier prohibits frame filters from executing\n\ -on this backtrace.")); +Usage: backtrace [OPTION]... [QUALIFIER]... [COUNT | -COUNT]\n\ +\n\ +Options:\n\ +%OPTIONS%\ +For backward compatibility, the following qualifiers are supported:\n\ +\n\ + full - same as -full option.\n\ + no-filters - same as -no-filters option.\n\ + hide - same as -hide.\n\ +\n\ +With a negative COUNT, print outermost -COUNT frames."), + backtrace_opts); + + cmd_list_element *c = add_com ("backtrace", class_stack, + backtrace_command, + backtrace_help.c_str ()); + set_cmd_completer_handle_brkchars (c, backtrace_command_completer); + add_com_alias ("bt", "backtrace", class_stack, 0); add_com_alias ("where", "backtrace", class_alias, 0); @@ -3100,33 +3264,20 @@ Prints the argument variables of the current stack frame.\n"), Select the stack frame that contains NAME.\n\ Usage: func NAME")); - add_setshow_enum_cmd ("frame-arguments", class_stack, - print_frame_arguments_choices, &print_frame_arguments, - _("Set printing of non-scalar frame arguments"), - _("Show printing of non-scalar frame arguments"), - NULL, NULL, NULL, &setprintlist, &showprintlist); - /* Install "set print raw frame-arguments", a deprecated spelling of "set print raw-frame-arguments". */ - cmd = add_setshow_boolean_cmd ("frame-arguments", no_class, - &print_raw_frame_arguments, _("\ + cmd = add_setshow_boolean_cmd + ("frame-arguments", no_class, + &user_frame_print_options.print_raw_frame_arguments, + _("\ Set whether to print frame arguments in raw form."), _("\ Show whether to print frame arguments in raw form."), _("\ If set, frame arguments are printed in raw form, bypassing any\n\ pretty-printers for that value."), - NULL, NULL, - &setprintrawlist, &showprintrawlist); + NULL, NULL, + &setprintrawlist, &showprintrawlist); deprecate_cmd (cmd, "set print raw-frame-arguments"); - add_setshow_boolean_cmd ("raw-frame-arguments", no_class, - &print_raw_frame_arguments, _("\ -Set whether to print frame arguments in raw form."), _("\ -Show whether to print frame arguments in raw form."), _("\ -If set, frame arguments are printed in raw form, bypassing any\n\ -pretty-printers for that value."), - NULL, NULL, - &setprintlist, &showprintlist); - add_setshow_auto_boolean_cmd ("disassemble-next-line", class_stack, &disassemble_next_line, _("\ Set whether to disassemble next source line or insn when execution stops."), @@ -3147,16 +3298,7 @@ source line."), &setlist, &showlist); disassemble_next_line = AUTO_BOOLEAN_FALSE; - add_setshow_enum_cmd ("entry-values", class_stack, - print_entry_values_choices, &print_entry_values, - _("Set printing of function arguments at function " - "entry"), - _("Show printing of function arguments at function " - "entry"), - _("\ -GDB can sometimes determine the values of function arguments at entry,\n\ -in addition to their current values. This option tells GDB whether\n\ -to print the current value, the value at entry (marked as val@entry),\n\ -or both. Note that one or both of these values may be ."), - NULL, NULL, &setprintlist, &showprintlist); + gdb::option::add_setshow_cmds_for_options + (class_stack, &user_frame_print_options, + frame_print_option_defs, &setprintlist, &showprintlist); } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 853aeb7c2d2..4485f29f1b0 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-06-13 Pedro Alves + + * gdb.base/options.exp (test-backtrace): New. + (top level): Call it. + 2019-06-13 Pedro Alves * gdb.guile/scm-frame-args.exp: Use "set print diff --git a/gdb/testsuite/gdb.base/options.exp b/gdb/testsuite/gdb.base/options.exp index 3b4e7ee189f..17573460b4d 100644 --- a/gdb/testsuite/gdb.base/options.exp +++ b/gdb/testsuite/gdb.base/options.exp @@ -20,8 +20,11 @@ # The test uses the "maintenance test-options" subcommands to exercise # TAB-completion and option processing. # -# It also tests option integration in various commands, including -# "print" and "compile print". +# It also tests option integration in various commands, including: +# +# - print +# - compile print +# - backtrace load_lib completion-support.exp @@ -231,6 +234,56 @@ proc_with_prefix test-print {{prefix ""}} { "Left operand of assignment is not an lvalue\\." } +# Basic option-machinery + "backtrace" command integration tests. +proc_with_prefix test-backtrace {} { + clean_restart + + test_gdb_complete_unique "backtrace" "backtrace" + test_gdb_complete_none "backtrace " + + gdb_test "backtrace -" "Ambiguous option at: -" + gdb_test "backtrace --" "No stack\\." + gdb_test "backtrace -- -" "No stack\\." + + test_gdb_complete_multiple "backtrace " "-" "" { + "-entry-values" + "-frame-arguments" + "-full" + "-hide" + "-no-filters" + "-past-entry" + "-past-main" + "-raw-frame-arguments" + } + + global binfile + clean_restart $binfile + + if ![runto_main] { + fail "cannot run to main" + return + } + + # COUNT in "backtrace COUNT" is parsed as an expression. Check + # that we complete expressions. + + test_gdb_complete_unique \ + "backtrace xxx" \ + "backtrace xxx1" + + test_gdb_complete_unique \ + "backtrace -xxx" \ + "backtrace -xxx1" + + test_gdb_complete_unique \ + "backtrace 1 + xxx" \ + "backtrace 1 + xxx1" + + test_gdb_complete_unique \ + "backtrace (1 + xxx" \ + "backtrace (1 + xxx1" +} + # Miscellaneous tests. proc_with_prefix test-misc {variant} { global all_options @@ -674,3 +727,6 @@ test-print "" if ![skip_compile_feature_tests] { test-print "compile " } + +# Basic "backtrace" integration tests. +test-backtrace