/* Print and select stack frames for GDB, the GNU debugger.
- Copyright (C) 1986-2018 Free Software Foundation, Inc.
+ Copyright (C) 1986-2020 Free Software Foundation, Inc.
This file is part of GDB.
#include "linespec.h"
#include "cli/cli-utils.h"
#include "objfiles.h"
+#include "annotate.h"
-#include "safe-ctype.h"
#include "symfile.h"
#include "extension.h"
#include "observable.h"
-#include "common/def-vector.h"
+#include "gdbsupport/def-vector.h"
+#include "cli/cli-option.h"
+#include "cli/cli-style.h"
/* The possible choices of "set print frame-arguments", and the value
of this setting. */
+const char print_frame_arguments_all[] = "all";
+const char print_frame_arguments_scalars[] = "scalars";
+const char print_frame_arguments_none[] = "none";
+const char print_frame_arguments_presence[] = "presence";
+
static const char *const print_frame_arguments_choices[] =
- {"all", "scalars", "none", NULL};
-static const char *print_frame_arguments = "scalars";
+{
+ print_frame_arguments_all,
+ print_frame_arguments_scalars,
+ print_frame_arguments_none,
+ print_frame_arguments_presence,
+ NULL
+};
+
+/* The possible choices of "set print frame-info", and the value
+ of this setting. */
+
+const char print_frame_info_auto[] = "auto";
+const char print_frame_info_source_line[] = "source-line";
+const char print_frame_info_location[] = "location";
+const char print_frame_info_source_and_location[] = "source-and-location";
+const char print_frame_info_location_and_address[] = "location-and-address";
+const char print_frame_info_short_location[] = "short-location";
-/* If non-zero, don't invoke pretty-printers for frame arguments. */
-static int print_raw_frame_arguments;
+static const char *const print_frame_info_choices[] =
+{
+ print_frame_info_auto,
+ print_frame_info_source_line,
+ print_frame_info_location,
+ print_frame_info_source_and_location,
+ print_frame_info_location_and_address,
+ print_frame_info_short_location,
+ NULL
+};
+
+/* print_frame_info_print_what[i] maps a choice to the corresponding
+ print_what enum. */
+static const gdb::optional<enum print_what> print_frame_info_print_what[] =
+ {{}, /* Empty value for "auto". */
+ SRC_LINE, LOCATION, SRC_AND_LOC, LOC_AND_ADDRESS, SHORT_LOCATION};
/* The possible choices of "set print entry-values", and the value
of this setting. */
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<frame_print_options>;
+using enum_option_def
+ = gdb::option::enum_option_def<frame_print_options>;
+
+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 <optimized out>."),
+ },
+
+ 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.")
+ },
+
+ enum_option_def {
+ "frame-info",
+ print_frame_info_choices,
+ [] (frame_print_options *opt) { return &opt->print_frame_info; },
+ NULL, /* show_cmd_cb */
+ N_("Set printing of frame information."),
+ N_("Show printing of frame information."),
+ NULL /* help_doc */
+ }
+
+};
+
+/* Options for the "backtrace" command. */
+
+struct backtrace_cmd_options
+{
+ bool full = false;
+ bool no_filters = false;
+ bool hide = false;
+};
+
+using bt_flag_option_def
+ = gdb::option::flag_option_def<backtrace_cmd_options>;
+
+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. */
-static void print_frame_local_vars (struct frame_info *, int,
- struct ui_file *);
+static void print_frame_local_vars (struct frame_info *frame,
+ bool quiet,
+ 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);
-static void set_last_displayed_sal (int valid,
- struct program_space *pspace,
- CORE_ADDR addr,
- 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
int annotation_level = 0;
-/* These variables hold the last symtab and line we displayed to the user.
- * This is where we insert a breakpoint or a skiplist entry by default. */
-static int last_displayed_sal_valid = 0;
-static struct program_space *last_displayed_pspace = 0;
-static CORE_ADDR last_displayed_addr = 0;
-static struct symtab *last_displayed_symtab = 0;
-static int last_displayed_line = 0;
+/* Class used to manage tracking the last symtab we displayed. */
+
+class last_displayed_symtab_info_type
+{
+public:
+ /* True if the cached information is valid. */
+ bool is_valid () const
+ { return m_valid; }
+
+ /* Return the cached program_space. If the cache is invalid nullptr is
+ returned. */
+ struct program_space *pspace () const
+ { return m_pspace; }
+
+ /* Return the cached CORE_ADDR address. If the cache is invalid 0 is
+ returned. */
+ CORE_ADDR address () const
+ { return m_address; }
+
+ /* Return the cached symtab. If the cache is invalid nullptr is
+ returned. */
+ struct symtab *symtab () const
+ { return m_symtab; }
+
+ /* Return the cached line number. If the cache is invalid 0 is
+ returned. */
+ int line () const
+ { return m_line; }
+
+ /* Invalidate the cache, reset all the members to their default value. */
+ void invalidate ()
+ {
+ m_valid = false;
+ m_pspace = nullptr;
+ m_address = 0;
+ m_symtab = nullptr;
+ m_line = 0;
+ }
+
+ /* Store a new set of values in the cache. */
+ void set (struct program_space *pspace, CORE_ADDR address,
+ struct symtab *symtab, int line)
+ {
+ gdb_assert (pspace != nullptr);
+
+ m_valid = true;
+ m_pspace = pspace;
+ m_address = address;
+ m_symtab = symtab;
+ m_line = line;
+ }
+
+private:
+ /* True when the cache is valid. */
+ bool m_valid = false;
+
+ /* The last program space displayed. */
+ struct program_space *m_pspace = nullptr;
+
+ /* The last address displayed. */
+ CORE_ADDR m_address = 0;
+
+ /* The last symtab displayed. */
+ struct symtab *m_symtab = nullptr;
+
+ /* The last line number displayed. */
+ int m_line = 0;
+};
+
+/* An actual instance of the cache, holds information about the last symtab
+ displayed. */
+static last_displayed_symtab_info_type last_displayed_symtab_info;
+
\f
-/* Return 1 if we should display the address in addition to the location,
- because we are in the middle of a statement. */
+/* See stack.h. */
-static int
+bool
frame_show_address (struct frame_info *frame,
struct symtab_and_line sal)
{
if (sal.line != 0 && sal.pc == 0 && sal.end == 0)
{
if (get_next_frame (frame) == NULL)
- gdb_assert (inline_skipped_frames (inferior_ptid) > 0);
+ gdb_assert (inline_skipped_frames (inferior_thread ()) > 0);
else
gdb_assert (get_frame_type (get_next_frame (frame)) == INLINE_FRAME);
- return 0;
+ return false;
}
return get_frame_pc (frame) != sal.pc;
int set_current_sal)
{
- /* For mi, alway print location and address. */
+ /* For mi, always print location and address. */
if (current_uiout->is_mi_like_p ())
print_what = LOC_AND_ADDRESS;
- TRY
+ 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);
}
- CATCH (e, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &e)
{
}
- END_CATCH
}
/* Print nameless arguments of frame FRAME on STREAM, where START is
read in.
Errors are printed as if they would be the parameter value. Use zeroed ARG
- iff it should not be printed accoring to user settings. */
+ iff it should not be printed according 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;
- const char *error_message = NULL;
string_file stb;
annotate_arg_emitter arg_emitter;
ui_out_emit_tuple tuple_emitter (uiout, NULL);
- fprintf_symbol_filtered (&stb, SYMBOL_PRINT_NAME (arg->sym),
- SYMBOL_LANGUAGE (arg->sym), DMGL_PARAMS | DMGL_ANSI);
+ fprintf_symbol_filtered (&stb, arg->sym->print_name (),
+ arg->sym->language (), DMGL_PARAMS | DMGL_ANSI);
if (arg->entry_kind == print_entry_values_compact)
{
/* It is OK to provide invalid MI-like stream as with
PRINT_ENTRY_VALUE_COMPACT we never use MI. */
stb.puts ("=");
- fprintf_symbol_filtered (&stb, SYMBOL_PRINT_NAME (arg->sym),
- SYMBOL_LANGUAGE (arg->sym),
+ fprintf_symbol_filtered (&stb, arg->sym->print_name (),
+ arg->sym->language (),
DMGL_PARAMS | DMGL_ANSI);
}
if (arg->entry_kind == print_entry_values_only
|| arg->entry_kind == print_entry_values_compact)
stb.puts ("@entry");
- uiout->field_stream ("name", stb);
+ uiout->field_stream ("name", stb, variable_name_style.style ());
annotate_arg_name_end ();
uiout->text ("=");
+ ui_file_style style;
if (!arg->val && !arg->error)
uiout->text ("...");
else
{
if (arg->error)
- error_message = arg->error;
+ {
+ stb.printf (_("<error reading variable: %s>"), arg->error.get ());
+ style = metadata_style.style ();
+ }
else
{
- TRY
+ 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
/* Use the appropriate language to display our symbol, unless the
user forced the language to a specific language. */
if (language_mode == language_mode_auto)
- language = language_def (SYMBOL_LANGUAGE (arg->sym));
+ language = language_def (arg->sym->language ());
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 (except, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &except)
{
- error_message = except.message;
+ stb.printf (_("<error reading variable: %s>"),
+ except.what ());
+ style = metadata_style.style ();
}
- END_CATCH
}
- if (error_message != NULL)
- stb.printf (_("<error reading variable: %s>"), error_message);
}
- uiout->field_stream ("value", stb);
+ uiout->field_stream ("value", stb, style);
}
/* Read in inferior function local SYM at FRAME into ARGP. Caller is
argp->val = NULL;
argp->error = NULL;
- TRY
+ try
{
argp->val = read_var_value (sym, NULL, frame);
}
- CATCH (except, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &except)
{
- argp->error = xstrdup (except.message);
+ argp->error.reset (xstrdup (except.what ()));
}
- END_CATCH
}
-/* Read in inferior function parameter SYM at FRAME into ARGP. Caller is
- responsible for xfree of ARGP->ERROR. This function never throws an
- exception. */
+/* Read in inferior function parameter SYM at FRAME into ARGP. This
+ function never throws an 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
+ try
{
val = read_var_value (sym, NULL, frame);
}
- CATCH (except, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &except)
{
- val_error = (char *) alloca (strlen (except.message) + 1);
- strcpy (val_error, except.message);
+ val_error = (char *) alloca (except.message->size () + 1);
+ strcpy (val_error, except.what ());
}
- END_CATCH
}
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
+ try
{
const struct symbol_computed_ops *ops;
ops = SYMBOL_COMPUTED_OPS (sym);
entryval = ops->read_variable_at_entry (sym, frame);
}
- CATCH (except, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &except)
{
if (except.error != NO_ENTRY_VALUE_ERROR)
{
- entryval_error = (char *) alloca (strlen (except.message) + 1);
- strcpy (entryval_error, except.message);
+ entryval_error = (char *) alloca (except.message->size () + 1);
+ strcpy (entryval_error, except.what ());
}
}
- END_CATCH
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. */
value. If it is a reference still try to verify if
dereferenced DW_AT_call_data_value does not differ. */
- TRY
+ try
{
struct type *type_deref;
TYPE_LENGTH (type_deref)))
val_equal = 1;
}
- CATCH (except, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &except)
{
/* If the dereferenced content could not be
fetched do not display anything. */
val_equal = 1;
else if (except.message != NULL)
{
- entryval_error = (char *) alloca (strlen (except.message) + 1);
- strcpy (entryval_error, except.message);
+ entryval_error
+ = (char *) alloca (except.message->size () + 1);
+ strcpy (entryval_error, except.what ());
}
}
- END_CATCH
/* Value was not a reference; and its content matches. */
if (val == val_deref)
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);
- TRY
+ try
{
val = read_var_value (sym, NULL, frame);
}
- CATCH (except, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &except)
{
- val_error = (char *) alloca (strlen (except.message) + 1);
- strcpy (val_error, except.message);
+ val_error = (char *) alloca (except.message->size () + 1);
+ strcpy (val_error, except.what ());
}
- END_CATCH
}
- 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;
argp->sym = sym;
argp->val = val;
- argp->error = val_error ? xstrdup (val_error) : NULL;
+ argp->error.reset (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 ());
entryargp->sym = sym;
entryargp->val = entryval;
- entryargp->error = entryval_error ? xstrdup (entryval_error) : NULL;
+ entryargp->error.reset (entryval_error ? xstrdup (entryval_error) : NULL);
if (!entryval && !entryval_error)
entryargp->entry_kind = print_entry_values_no;
else
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;
long highest_offset = -1;
/* Number of ints of arguments that we have printed so far. */
int args_printed = 0;
+ /* True if we should print arg names. If false, we only indicate
+ the presence of arguments by printing ellipsis. */
+ bool print_names
+ = fp_opts.print_frame_arguments != print_frame_arguments_presence;
/* True if we should print arguments, false otherwise. */
- int print_args = strcmp (print_frame_arguments, "none");
+ bool print_args
+ = (print_names
+ && fp_opts.print_frame_arguments != print_frame_arguments_none);
if (func)
{
if (!SYMBOL_IS_ARGUMENT (sym))
continue;
+ if (!print_names)
+ {
+ uiout->text ("...");
+ first = 0;
+ break;
+ }
+
switch (SYMBOL_CLASS (sym))
{
case LOC_ARG:
parameter names occur on the RS/6000, for traceback
tables. FIXME, should we even print them? */
- if (*SYMBOL_LINKAGE_NAME (sym))
+ if (*sym->linkage_name ())
{
struct symbol *nsym;
- nsym = lookup_symbol_search_name (SYMBOL_SEARCH_NAME (sym),
+ nsym = lookup_symbol_search_name (sym->search_name (),
b, VAR_DOMAIN).symbol;
gdb_assert (nsym != NULL);
if (SYMBOL_CLASS (nsym) == LOC_REGISTER
if (!print_args)
{
- memset (&arg, 0, sizeof (arg));
arg.sym = sym;
arg.entry_kind = print_entry_values_no;
- memset (&entryarg, 0, sizeof (entryarg));
entryarg.sym = sym;
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)
{
uiout->wrap_hint (" ");
}
- print_frame_arg (&entryarg);
+ print_frame_arg (fp_opts, &entryarg);
}
- xfree (arg.error);
- xfree (entryarg.error);
-
first = 0;
}
}
else
start = highest_offset;
- print_frame_nameless_args (frame, start, num - args_printed,
- first, stream);
+ if (!print_names && !first && num > 0)
+ uiout->text ("...");
+ else
+ print_frame_nameless_args (frame, start, num - args_printed,
+ first, stream);
}
}
int how_many, CORE_ADDR low, CORE_ADDR high)
{
- TRY
+ try
{
gdb_disassembly (gdbarch, current_uiout,
DISASSEMBLY_RAW_INSN, how_many,
low, high);
}
- CATCH (exception, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &exception)
{
/* If an exception was thrown while doing the disassembly, print
the error message, to give the user a clue of what happened. */
exception_print (gdb_stderr, exception);
}
- END_CATCH
+}
+
+/* Converts the PRINT_FRAME_INFO choice to an optional enum print_what.
+ Value not present indicates to the caller to use default values
+ specific to the command being executed. */
+
+static gdb::optional<enum print_what>
+print_frame_info_to_print_what (const char *print_frame_info)
+{
+ for (int i = 0; print_frame_info_choices[i] != NULL; i++)
+ if (print_frame_info == print_frame_info_choices[i])
+ return print_frame_info_print_what[i];
+
+ internal_error (__FILE__, __LINE__,
+ "Unexpected print frame-info value `%s'.",
+ print_frame_info);
+}
+
+/* Print the PC from FRAME, plus any flags, to UIOUT. */
+
+static void
+print_pc (struct ui_out *uiout, struct gdbarch *gdbarch, frame_info *frame,
+ CORE_ADDR pc)
+{
+ uiout->field_core_addr ("addr", gdbarch, pc);
+
+ std::string flags = gdbarch_get_pc_address_flags (gdbarch, frame, pc);
+ if (!flags.empty ())
+ {
+ uiout->text (" [");
+ uiout->field_string ("addr_flags", flags);
+ uiout->text ("]");
+ }
+}
+
+/* See stack.h. */
+
+void
+get_user_print_what_frame_info (gdb::optional<enum print_what> *what)
+{
+ *what
+ = print_frame_info_to_print_what
+ (user_frame_print_options.print_frame_info);
}
/* Print information about frame FRAME. The output is format according
- to PRINT_LEVEL and PRINT_WHAT and PRINT_ARGS. The meaning of
- PRINT_WHAT is:
-
- SRC_LINE: Print only source line.
- LOCATION: Print only location.
- SRC_AND_LOC: Print location and source line.
+ to PRINT_LEVEL and PRINT_WHAT and PRINT_ARGS. For the meaning of
+ PRINT_WHAT, see enum print_what comments in frame.h.
+ Note that PRINT_WHAT is overridden if FP_OPTS.print_frame_info
+ != print_frame_info_auto.
Used in "where" output, and to emit breakpoint or step
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)
{
int location_print;
struct ui_out *uiout = current_uiout;
+ if (!current_uiout->is_mi_like_p ()
+ && fp_opts.print_frame_info != print_frame_info_auto)
+ {
+ /* Use the specific frame information desired by the user. */
+ print_what = *print_frame_info_to_print_what (fp_opts.print_frame_info);
+ }
+
if (get_frame_type (frame) == DUMMY_FRAME
|| get_frame_type (frame) == SIGTRAMP_FRAME
|| get_frame_type (frame) == ARCH_FRAME)
if (print_level)
{
uiout->text ("#");
- uiout->field_fmt_int (2, ui_left, "level",
- frame_relative_level (frame));
+ uiout->field_fmt_signed (2, ui_left, "level",
+ frame_relative_level (frame));
}
if (uiout->is_mi_like_p ())
{
annotate_frame_address ();
- uiout->field_core_addr ("addr",
- gdbarch, get_frame_pc (frame));
+ print_pc (uiout, gdbarch, frame, get_frame_pc (frame));
annotate_frame_address_end ();
}
if (get_frame_type (frame) == DUMMY_FRAME)
{
annotate_function_call ();
- uiout->field_string ("func", "<function called from gdb>");
+ uiout->field_string ("func", "<function called from gdb>",
+ metadata_style.style ());
}
else if (get_frame_type (frame) == SIGTRAMP_FRAME)
{
annotate_signal_handler_caller ();
- uiout->field_string ("func", "<signal handler called>");
+ uiout->field_string ("func", "<signal handler called>",
+ metadata_style.style ());
}
else if (get_frame_type (frame) == ARCH_FRAME)
{
- uiout->field_string ("func", "<cross-architecture call>");
+ uiout->field_string ("func", "<cross-architecture call>",
+ metadata_style.style ());
}
uiout->text ("\n");
annotate_frame_end ();
to get the line containing FRAME->pc. */
symtab_and_line sal = find_frame_sal (frame);
- location_print = (print_what == LOCATION
+ location_print = (print_what == LOCATION
+ || print_what == SRC_AND_LOC
|| print_what == LOC_AND_ADDRESS
- || print_what == SRC_AND_LOC);
-
+ || print_what == SHORT_LOCATION);
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);
if (source_print && sal.symtab)
{
- int done = 0;
int mid_statement = ((print_what == SRC_LINE)
&& frame_show_address (frame, sal));
+ annotate_source_line (sal.symtab, sal.line, mid_statement,
+ get_frame_pc (frame));
- if (annotation_level)
- done = identify_source_line (sal.symtab, sal.line, mid_statement,
- get_frame_pc (frame));
- if (!done)
+ if (deprecated_print_frame_info_listing_hook)
+ deprecated_print_frame_info_listing_hook (sal.symtab, sal.line,
+ sal.line + 1, 0);
+ else
{
- if (deprecated_print_frame_info_listing_hook)
- deprecated_print_frame_info_listing_hook (sal.symtab,
- sal.line,
- sal.line + 1, 0);
- else
- {
- struct value_print_options opts;
-
- get_user_print_options (&opts);
- /* We used to do this earlier, but that is clearly
- wrong. This function is used by many different
- parts of gdb, including normal_stop in infrun.c,
- which uses this to print out the current PC
- when we stepi/nexti into the middle of a source
- line. Only the command line really wants this
- behavior. Other UIs probably would like the
- ability to decide for themselves if it is desired. */
- if (opts.addressprint && mid_statement)
- {
- uiout->field_core_addr ("addr",
- gdbarch, get_frame_pc (frame));
- uiout->text ("\t");
- }
+ struct value_print_options opts;
- print_source_lines (sal.symtab, sal.line, sal.line + 1, 0);
+ get_user_print_options (&opts);
+ /* We used to do this earlier, but that is clearly
+ wrong. This function is used by many different
+ parts of gdb, including normal_stop in infrun.c,
+ which uses this to print out the current PC
+ when we stepi/nexti into the middle of a source
+ line. Only the command line really wants this
+ behavior. Other UIs probably would like the
+ ability to decide for themselves if it is desired. */
+ if (opts.addressprint && mid_statement)
+ {
+ print_pc (uiout, gdbarch, frame, get_frame_pc (frame));
+ uiout->text ("\t");
}
+
+ print_source_lines (sal.symtab, sal.line, sal.line + 1, 0);
}
/* If disassemble-next-line is set to on and there is line debug
- messages, output assembly codes for next line. */
+ messages, output assembly codes for next line. */
if (disassemble_next_line == AUTO_BOOLEAN_TRUE)
do_gdb_disassembly (get_frame_arch (frame), -1, sal.pc, sal.end);
}
CORE_ADDR pc;
if (get_frame_pc_if_available (frame, &pc))
- set_last_displayed_sal (1, sal.pspace, pc, sal.symtab, sal.line);
+ last_displayed_symtab_info.set (sal.pspace, pc, sal.symtab, sal.line);
else
- set_last_displayed_sal (0, 0, 0, 0, 0);
+ last_displayed_symtab_info.invalidate ();
}
annotate_frame_end ();
gdb_flush (gdb_stdout);
}
-/* Remember the last symtab and line we displayed, which we use e.g.
- * as the place to put a breakpoint when the `break' command is
- * invoked with no arguments. */
-
-static void
-set_last_displayed_sal (int valid, struct program_space *pspace,
- CORE_ADDR addr, struct symtab *symtab,
- int line)
-{
- last_displayed_sal_valid = valid;
- last_displayed_pspace = pspace;
- last_displayed_addr = addr;
- last_displayed_symtab = symtab;
- last_displayed_line = line;
- if (valid && pspace == NULL)
- {
- clear_last_displayed_sal ();
- internal_error (__FILE__, __LINE__,
- _("Trying to set NULL pspace."));
- }
-}
-
-/* Forget the last sal we displayed. */
+/* See stack.h. */
void
clear_last_displayed_sal (void)
{
- last_displayed_sal_valid = 0;
- last_displayed_pspace = 0;
- last_displayed_addr = 0;
- last_displayed_symtab = 0;
- last_displayed_line = 0;
+ last_displayed_symtab_info.invalidate ();
}
-/* Is our record of the last sal we displayed valid? If not,
- * the get_last_displayed_* functions will return NULL or 0, as
- * appropriate. */
+/* See stack.h. */
-int
+bool
last_displayed_sal_is_valid (void)
{
- return last_displayed_sal_valid;
+ return last_displayed_symtab_info.is_valid ();
}
-/* Get the pspace of the last sal we displayed, if it's valid. */
+/* See stack.h. */
struct program_space *
get_last_displayed_pspace (void)
{
- if (last_displayed_sal_valid)
- return last_displayed_pspace;
- return 0;
+ return last_displayed_symtab_info.pspace ();
}
-/* Get the address of the last sal we displayed, if it's valid. */
+/* See stack.h. */
CORE_ADDR
get_last_displayed_addr (void)
{
- if (last_displayed_sal_valid)
- return last_displayed_addr;
- return 0;
+ return last_displayed_symtab_info.address ();
}
-/* Get the symtab of the last sal we displayed, if it's valid. */
+/* See stack.h. */
struct symtab*
get_last_displayed_symtab (void)
{
- if (last_displayed_sal_valid)
- return last_displayed_symtab;
- return 0;
+ return last_displayed_symtab_info.symtab ();
}
-/* Get the line of the last sal we displayed, if it's valid. */
+/* See stack.h. */
int
get_last_displayed_line (void)
{
- if (last_displayed_sal_valid)
- return last_displayed_line;
- return 0;
+ return last_displayed_symtab_info.line ();
}
-/* Get the last sal we displayed, if it's valid. */
+/* See stack.h. */
symtab_and_line
get_last_displayed_sal ()
{
symtab_and_line sal;
- if (last_displayed_sal_valid)
+ if (last_displayed_symtab_info.is_valid ())
{
- sal.pspace = last_displayed_pspace;
- sal.pc = last_displayed_addr;
- sal.symtab = last_displayed_symtab;
- sal.line = last_displayed_line;
+ sal.pspace = last_displayed_symtab_info.pspace ();
+ sal.pc = last_displayed_symtab_info.address ();
+ sal.symtab = last_displayed_symtab_info.symtab ();
+ sal.line = last_displayed_symtab_info.line ();
}
return sal;
func = get_frame_function (frame);
if (func)
{
- /* In certain pathological cases, the symtabs give the wrong
- function (when we are in the first function in a file which
- is compiled without debugging symbols, the previous function
- is compiled with debugging symbols, and the "foo.o" symbol
- that is supposed to tell us where the file with debugging
- symbols ends has been truncated by ar because it is longer
- than 15 characters). This also occurs if the user uses asm()
- to create a function but not stabs for it (in a file compiled
- with -g).
-
- So look in the minimal symbol tables as well, and if it comes
- up with a larger address for the function use that instead.
- I don't think this can ever cause any problems; there
- shouldn't be any minimal symbols in the middle of a function;
- if this is ever changed many parts of GDB will need to be
- changed (and we'll create a find_pc_minimal_function or some
- such). */
-
- struct bound_minimal_symbol msymbol;
-
- /* Don't attempt to do this for inlined functions, which do not
- have a corresponding minimal symbol. */
- if (!block_inlined_p (SYMBOL_BLOCK_VALUE (func)))
- msymbol
- = lookup_minimal_symbol_by_pc (get_frame_address_in_block (frame));
- else
- memset (&msymbol, 0, sizeof (msymbol));
+ const char *print_name = func->print_name ();
- if (msymbol.minsym != NULL
- && (BMSYMBOL_VALUE_ADDRESS (msymbol)
- > BLOCK_START (SYMBOL_BLOCK_VALUE (func))))
+ *funlang = func->language ();
+ if (funcp)
+ *funcp = func;
+ if (*funlang == language_cplus)
{
- /* We also don't know anything about the function besides
- its address and name. */
- func = 0;
- funname.reset (xstrdup (MSYMBOL_PRINT_NAME (msymbol.minsym)));
- *funlang = MSYMBOL_LANGUAGE (msymbol.minsym);
+ /* It seems appropriate to use print_name() here,
+ to display the demangled name that we already have
+ stored in the symbol table, but we stored a version
+ with DMGL_PARAMS turned on, and here we don't want to
+ display parameters. So remove the parameters. */
+ funname = cp_remove_params (print_name);
}
- else
- {
- const char *print_name = SYMBOL_PRINT_NAME (func);
-
- *funlang = SYMBOL_LANGUAGE (func);
- if (funcp)
- *funcp = func;
- if (*funlang == language_cplus)
- {
- /* It seems appropriate to use SYMBOL_PRINT_NAME() here,
- to display the demangled name that we already have
- stored in the symbol table, but we stored a version
- with DMGL_PARAMS turned on, and here we don't want to
- display parameters. So remove the parameters. */
- funname = cp_remove_params (print_name);
- }
- /* If we didn't hit the C++ case above, set *funname
- here. */
- if (funname == NULL)
- funname.reset (xstrdup (print_name));
- }
+ /* If we didn't hit the C++ case above, set *funname
+ here. */
+ if (funname == NULL)
+ funname.reset (xstrdup (print_name));
}
else
{
msymbol = lookup_minimal_symbol_by_pc (pc);
if (msymbol.minsym != NULL)
{
- funname.reset (xstrdup (MSYMBOL_PRINT_NAME (msymbol.minsym)));
- *funlang = MSYMBOL_LANGUAGE (msymbol.minsym);
+ funname.reset (xstrdup (msymbol.minsym->print_name ()));
+ *funlang = msymbol.minsym->language ();
}
}
}
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)
{
if (print_level)
{
uiout->text ("#");
- uiout->field_fmt_int (2, ui_left, "level",
- frame_relative_level (frame));
+ uiout->field_fmt_signed (2, ui_left, "level",
+ frame_relative_level (frame));
}
get_user_print_options (&opts);
if (opts.addressprint)
{
annotate_frame_address ();
if (pc_p)
- uiout->field_core_addr ("addr", gdbarch, pc);
+ print_pc (uiout, gdbarch, frame, pc);
else
- uiout->field_string ("addr", "<unavailable>");
+ uiout->field_string ("addr", "<unavailable>",
+ metadata_style.style ());
annotate_frame_address_end ();
uiout->text (" in ");
}
string_file stb;
fprintf_symbol_filtered (&stb, funname ? funname.get () : "??",
funlang, DMGL_ANSI);
- uiout->field_stream ("func", stb);
+ uiout->field_stream ("func", stb, function_name_style.style ());
uiout->wrap_hint (" ");
annotate_frame_args ();
-
+
uiout->text (" (");
if (print_args)
{
- struct gdbarch *gdbarch = get_frame_arch (frame);
int numargs;
if (gdbarch_frame_num_args_p (gdbarch))
{
ui_out_emit_list list_emitter (uiout, "args");
- TRY
+ try
{
- print_frame_args (func, frame, numargs, gdb_stdout);
+ print_frame_args (fp_opts, func, frame, numargs, gdb_stdout);
}
- CATCH (e, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &e)
{
}
- END_CATCH
/* FIXME: ARGS must be a list. If one argument is a string it
will have " that will not be properly escaped. */
QUIT;
}
uiout->text (")");
- if (sal.symtab)
+ if (print_what != SHORT_LOCATION && sal.symtab)
{
const char *filename_display;
uiout->wrap_hint (" ");
uiout->text (" at ");
annotate_frame_source_file ();
- uiout->field_string ("file", filename_display);
+ uiout->field_string ("file", filename_display,
+ file_name_style.style ());
if (uiout->is_mi_like_p ())
{
const char *fullname = symtab_to_fullname (sal.symtab);
annotate_frame_source_file_end ();
uiout->text (":");
annotate_frame_source_line ();
- uiout->field_int ("line", sal.line);
+ uiout->field_signed ("line", sal.line);
annotate_frame_source_end ();
}
- if (pc_p && (funname == NULL || sal.symtab == NULL))
+ if (print_what != SHORT_LOCATION
+ && pc_p && (funname == NULL || sal.symtab == NULL))
{
char *lib = solib_name_from_address (get_frame_program_space (frame),
get_frame_pc (frame));
annotate_frame_where ();
uiout->wrap_hint (" ");
uiout->text (" from ");
- uiout->field_string ("from", lib);
+ uiout->field_string ("from", lib, file_name_style.style ());
}
}
+ if (uiout->is_mi_like_p ())
+ uiout->field_string ("arch",
+ (gdbarch_bfd_arch_info (gdbarch))->printable_name);
}
uiout->text ("\n");
}
\f
-/* 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)
+static 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;
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;
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"
gdb::unique_xmalloc_ptr<char> func_only;
if (func)
{
- funname = SYMBOL_PRINT_NAME (func);
- funlang = SYMBOL_LANGUAGE (func);
+ funname = func->print_name ();
+ funlang = func->language ();
if (funlang == language_cplus)
{
- /* It seems appropriate to use SYMBOL_PRINT_NAME() here,
+ /* It seems appropriate to use print_name() here,
to display the demangled name that we already have
stored in the symbol table, but we stored a version
with DMGL_PARAMS turned on, and here we don't want to
msymbol = lookup_minimal_symbol_by_pc (frame_pc);
if (msymbol.minsym != NULL)
{
- funname = MSYMBOL_PRINT_NAME (msymbol.minsym);
- funlang = MSYMBOL_LANGUAGE (msymbol.minsym);
+ funname = msymbol.minsym->print_name ();
+ funlang = msymbol.minsym->language ();
}
}
calling_frame_info = get_prev_frame (fi);
if (frame_pc_p)
fputs_filtered (paddress (gdbarch, get_frame_pc (fi)), gdb_stdout);
else
- fputs_filtered ("<unavailable>", gdb_stdout);
+ fputs_styled ("<unavailable>", metadata_style.style (), gdb_stdout);
wrap_here (" ");
if (funname)
}
wrap_here (" ");
if (sal.symtab)
- printf_filtered (" (%s:%d)", symtab_to_filename_for_display (sal.symtab),
- sal.line);
+ printf_filtered
+ (" (%ps:%d)",
+ styled_string (file_name_style.style (),
+ symtab_to_filename_for_display (sal.symtab)),
+ sal.line);
puts_filtered ("; ");
wrap_here (" ");
printf_filtered ("saved %s = ", pc_regname);
val_print_not_saved (gdb_stdout);
else
{
- TRY
+ try
{
caller_pc = frame_unwind_caller_pc (fi);
caller_pc_p = 1;
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
switch (ex.error)
{
val_print_not_saved (gdb_stdout);
break;
default:
- fprintf_filtered (gdb_stdout, _("<error: %s>"), ex.message);
+ fprintf_styled (gdb_stdout, metadata_style.style (),
+ _("<error: %s>"),
+ ex.what ());
break;
}
}
- END_CATCH
}
if (caller_pc_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");
}
}
}
count = 0;
- numregs = gdbarch_num_regs (gdbarch)
- + gdbarch_num_pseudo_regs (gdbarch);
+ numregs = gdbarch_num_cooked_regs (gdbarch);
for (i = 0; i < numregs; i++)
if (i != sp_regnum
&& gdbarch_register_reggroup_p (gdbarch, i, all_reggroup))
}
}
+/* 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;
+}
+
+/* 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. */
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;
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;
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
+ else if (fp_opts.print_frame_arguments == print_frame_arguments_presence)
+ arg_type = CLI_PRESENCE;
+ else if (fp_opts.print_frame_arguments == print_frame_arguments_none)
arg_type = NO_VALUES;
+ else
+ gdb_assert (0);
result = apply_ext_lang_frame_filter (get_current_frame (), flags,
arg_type, current_uiout,
}
/* 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;
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))
{
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);
- print_frame_local_vars (fi, 1, gdb_stdout);
+ print_frame_local_vars (fi, false, NULL, NULL, 1, gdb_stdout);
/* print_frame_local_vars invalidates FI. */
fi = frame_find_by_id (frame_id);
}
}
-static void
-backtrace_command (const char *arg, int from_tty)
+/* 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<gdb::option::option_def_group, 3>
+make_backtrace_options_def_group (frame_print_options *fp_opts,
+ backtrace_cmd_options *bt_cmd_opts,
+ set_backtrace_options *set_bt_opts)
{
- bool filters = true;
- frame_filter_flags flags = 0;
+ return {{
+ { {frame_print_option_defs}, fp_opts },
+ { {set_backtrace_option_defs}, set_bt_opts },
+ { {backtrace_command_option_defs}, bt_cmd_opts }
+ }};
+}
- if (arg)
- {
- bool done = false;
+/* Parse the backtrace command's qualifiers. Returns ARG advanced
+ past the qualifiers, if any. BT_CMD_OPTS, if not null, is used to
+ store the parsed qualifiers. */
- while (!done)
- {
- const char *save_arg = arg;
- std::string this_arg = extract_arg (&arg);
+static const char *
+parse_backtrace_qualifiers (const char *arg,
+ backtrace_cmd_options *bt_cmd_opts = nullptr)
+{
+ while (true)
+ {
+ const char *save_arg = arg;
+ std::string this_arg = extract_arg (&arg);
- if (this_arg.empty ())
- break;
+ if (this_arg.empty ())
+ return arg;
- if (subset_compare (this_arg.c_str (), "no-filters"))
- filters = false;
- else if (subset_compare (this_arg.c_str (), "full"))
- flags |= PRINT_LOCALS;
- else if (subset_compare (this_arg.c_str (), "hide"))
- flags |= PRINT_HIDE;
- else
- {
- /* Not a recognized argument, so stop. */
- arg = save_arg;
- done = true;
- }
+ if (subset_compare (this_arg.c_str (), "no-filters"))
+ {
+ if (bt_cmd_opts != nullptr)
+ bt_cmd_opts->no_filters = true;
}
+ else if (subset_compare (this_arg.c_str (), "full"))
+ {
+ if (bt_cmd_opts != nullptr)
+ bt_cmd_opts->full = true;
+ }
+ else if (subset_compare (this_arg.c_str (), "hide"))
+ {
+ if (bt_cmd_opts != nullptr)
+ bt_cmd_opts->hide = true;
+ }
+ else
+ {
+ /* Not a recognized qualifier, so stop. */
+ return save_arg;
+ }
+ }
+}
+static void
+backtrace_command (const char *arg, int from_tty)
+{
+ 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;
+
+ 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)
+ {
+ arg = parse_backtrace_qualifiers (arg, &bt_cmd_opts);
if (*arg == '\0')
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;
+
+ if (*text != '\0')
+ {
+ const char *p = skip_to_space (text);
+ if (*p == '\0')
+ {
+ static const char *const backtrace_cmd_qualifier_choices[] = {
+ "full", "no-filters", "hide", nullptr,
+ };
+ complete_on_enum (tracker, backtrace_cmd_qualifier_choices,
+ text, text);
+
+ if (tracker.have_completions ())
+ return;
+ }
+ else
+ {
+ const char *cmd = parse_backtrace_qualifiers (text);
+ tracker.advance_custom_word_point_by (cmd - text);
+ text = cmd;
+ }
+ }
+
+ 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
break;
if (SYMBOL_DOMAIN (sym) == COMMON_BLOCK_DOMAIN)
break;
- (*cb) (SYMBOL_PRINT_NAME (sym), sym, cb_data);
+ (*cb) (sym->print_name (), sym, cb_data);
break;
default:
ALL_BLOCK_SYMBOLS (b, iter, sym)
{
- if (strcmp (SYMBOL_LINKAGE_NAME (sym), "default") == 0)
+ if (strcmp (sym->linkage_name (), "default") == 0)
{
if (*have_default)
continue;
sal = find_pc_line (SYMBOL_VALUE_ADDRESS (sym), 0);
values_printed = 1;
- fputs_filtered (SYMBOL_PRINT_NAME (sym), stream);
+ fputs_filtered (sym->print_name (), stream);
get_user_print_options (&opts);
if (opts.addressprint)
{
struct print_variable_and_value_data
{
+ gdb::optional<compiled_regex> preg;
+ gdb::optional<compiled_regex> treg;
struct frame_id frame_id;
int num_tabs;
struct ui_file *stream;
= (struct print_variable_and_value_data *) cb_data;
struct frame_info *frame;
+ if (p->preg.has_value ()
+ && p->preg->exec (sym->natural_name (), 0, NULL, 0) != 0)
+ return;
+ if (p->treg.has_value ()
+ && !treg_matches_sym_type_name (*p->treg, sym))
+ return;
+
frame = frame_find_by_id (p->frame_id);
if (frame == NULL)
{
p->values_printed = 1;
}
+/* Prepares the regular expression REG from REGEXP.
+ If REGEXP is NULL, it results in an empty regular expression. */
+
+static void
+prepare_reg (const char *regexp, gdb::optional<compiled_regex> *reg)
+{
+ if (regexp != NULL)
+ {
+ int cflags = REG_NOSUB | (case_sensitivity == case_sensitive_off
+ ? REG_ICASE : 0);
+ reg->emplace (regexp, cflags, _("Invalid regexp"));
+ }
+ else
+ reg->reset ();
+}
+
/* Print all variables from the innermost up to the function block of FRAME.
Print them with values to STREAM indented by NUM_TABS.
+ If REGEXP is not NULL, only print local variables whose name
+ matches REGEXP.
+ If T_REGEXP is not NULL, only print local variables whose type
+ matches T_REGEXP.
+ If no local variables have been printed and !QUIET, prints a message
+ explaining why no local variables could be printed.
This function will invalidate FRAME. */
static void
-print_frame_local_vars (struct frame_info *frame, int num_tabs,
- struct ui_file *stream)
+print_frame_local_vars (struct frame_info *frame,
+ bool quiet,
+ const char *regexp, const char *t_regexp,
+ int num_tabs, struct ui_file *stream)
{
struct print_variable_and_value_data cb_data;
const struct block *block;
if (!get_frame_pc_if_available (frame, &pc))
{
- fprintf_filtered (stream,
- _("PC unavailable, cannot determine locals.\n"));
+ if (!quiet)
+ fprintf_filtered (stream,
+ _("PC unavailable, cannot determine locals.\n"));
return;
}
block = get_frame_block (frame, 0);
if (block == 0)
{
- fprintf_filtered (stream, "No symbol table info available.\n");
+ if (!quiet)
+ fprintf_filtered (stream, "No symbol table info available.\n");
return;
}
+ prepare_reg (regexp, &cb_data.preg);
+ prepare_reg (t_regexp, &cb_data.treg);
cb_data.frame_id = get_frame_id (frame);
cb_data.num_tabs = 4 * num_tabs;
cb_data.stream = stream;
do_print_variable_and_value,
&cb_data);
- if (!cb_data.values_printed)
- fprintf_filtered (stream, _("No locals.\n"));
+ if (!cb_data.values_printed && !quiet)
+ {
+ if (regexp == NULL && t_regexp == NULL)
+ fprintf_filtered (stream, _("No locals.\n"));
+ else
+ fprintf_filtered (stream, _("No matching locals.\n"));
+ }
+}
+
+/* Structure to hold the values of the options used by the 'info
+ variables' command and other similar commands. These correspond to the
+ -q and -t options. */
+
+struct info_print_options
+{
+ bool quiet = false;
+ char *type_regexp = nullptr;
+
+ ~info_print_options ()
+ {
+ xfree (type_regexp);
+ }
+};
+
+/* The options used by the 'info locals' and 'info args' commands. */
+
+static const gdb::option::option_def info_print_options_defs[] = {
+ gdb::option::boolean_option_def<info_print_options> {
+ "q",
+ [] (info_print_options *opt) { return &opt->quiet; },
+ nullptr, /* show_cmd_cb */
+ nullptr /* set_doc */
+ },
+
+ gdb::option::string_option_def<info_print_options> {
+ "t",
+ [] (info_print_options *opt) { return &opt->type_regexp; },
+ nullptr, /* show_cmd_cb */
+ nullptr /* set_doc */
+ }
+};
+
+/* Returns the option group used by 'info locals' and 'info args'
+ commands. */
+
+static gdb::option::option_def_group
+make_info_print_options_def_group (info_print_options *opts)
+{
+ return {{info_print_options_defs}, opts};
+}
+
+/* Command completer for 'info locals' and 'info args'. */
+
+static void
+info_print_command_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char * /* word */)
+{
+ const auto group
+ = make_info_print_options_def_group (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);
+ symbol_completer (ignore, tracker, text, word);
}
+/* Implement the 'info locals' command. */
+
void
info_locals_command (const char *args, int from_tty)
{
+ info_print_options opts;
+ auto grp = make_info_print_options_def_group (&opts);
+ gdb::option::process_options
+ (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp);
+ if (args != nullptr && *args == '\0')
+ args = nullptr;
+
print_frame_local_vars (get_selected_frame (_("No frame selected.")),
+ opts.quiet, args, opts.type_regexp,
0, gdb_stdout);
}
float). There are also LOC_ARG/LOC_REGISTER pairs which
are not combined in symbol-reading. */
- sym2 = lookup_symbol_search_name (SYMBOL_SEARCH_NAME (sym),
+ sym2 = lookup_symbol_search_name (sym->search_name (),
b, VAR_DOMAIN).symbol;
- (*cb) (SYMBOL_PRINT_NAME (sym), sym2, cb_data);
+ (*cb) (sym->print_name (), sym2, cb_data);
}
}
}
/* Print all argument variables of the function of FRAME.
Print them with values to STREAM.
+ If REGEXP is not NULL, only print argument variables whose name
+ matches REGEXP.
+ If T_REGEXP is not NULL, only print argument variables whose type
+ matches T_REGEXP.
+ If no argument variables have been printed and !QUIET, prints a message
+ explaining why no argument variables could be printed.
This function will invalidate FRAME. */
static void
-print_frame_arg_vars (struct frame_info *frame, struct ui_file *stream)
+print_frame_arg_vars (struct frame_info *frame,
+ bool quiet,
+ const char *regexp, const char *t_regexp,
+ struct ui_file *stream)
{
struct print_variable_and_value_data cb_data;
struct symbol *func;
CORE_ADDR pc;
+ gdb::optional<compiled_regex> preg;
+ gdb::optional<compiled_regex> treg;
if (!get_frame_pc_if_available (frame, &pc))
{
- fprintf_filtered (stream, _("PC unavailable, cannot determine args.\n"));
+ if (!quiet)
+ fprintf_filtered (stream,
+ _("PC unavailable, cannot determine args.\n"));
return;
}
func = get_frame_function (frame);
if (func == NULL)
{
- fprintf_filtered (stream, _("No symbol table info available.\n"));
+ if (!quiet)
+ fprintf_filtered (stream, _("No symbol table info available.\n"));
return;
}
+ prepare_reg (regexp, &cb_data.preg);
+ prepare_reg (t_regexp, &cb_data.treg);
cb_data.frame_id = get_frame_id (frame);
cb_data.num_tabs = 0;
cb_data.stream = stream;
/* do_print_variable_and_value invalidates FRAME. */
frame = NULL;
- if (!cb_data.values_printed)
- fprintf_filtered (stream, _("No arguments.\n"));
+ if (!cb_data.values_printed && !quiet)
+ {
+ if (regexp == NULL && t_regexp == NULL)
+ fprintf_filtered (stream, _("No arguments.\n"));
+ else
+ fprintf_filtered (stream, _("No matching arguments.\n"));
+ }
}
+/* Implement the 'info args' command. */
+
void
-info_args_command (const char *ignore, int from_tty)
+info_args_command (const char *args, int from_tty)
{
+ info_print_options opts;
+ auto grp = make_info_print_options_def_group (&opts);
+ gdb::option::process_options
+ (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp);
+ if (args != nullptr && *args == '\0')
+ args = nullptr;
+
print_frame_arg_vars (get_selected_frame (_("No frame selected.")),
- gdb_stdout);
+ opts.quiet, args, opts.type_regexp, gdb_stdout);
}
\f
/* Return the symbol-block in which the selected frame is executing.
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. */
if (TYPE_NO_RETURN (thisfun->type))
warning (_("Function does not return normally to caller."));
confirmed = query (_("%sMake %s return now? "), query_prefix,
- SYMBOL_PRINT_NAME (thisfun));
+ thisfun->print_name ());
}
if (!confirmed)
error (_("Not confirmed"));
if (return_value != NULL)
{
struct type *return_type = value_type (return_value);
- struct gdbarch *gdbarch = get_current_regcache ()->arch ();
+ struct gdbarch *cache_arch = get_current_regcache ()->arch ();
gdb_assert (rv_conv != RETURN_VALUE_STRUCT_CONVENTION
&& rv_conv != RETURN_VALUE_ABI_RETURNS_ADDRESS);
- gdbarch_return_value (gdbarch, function, return_type,
+ gdbarch_return_value (cache_arch, function, return_type,
get_current_regcache (), NULL /*read*/,
value_contents (return_value) /*write*/);
}
struct frame_info *frame = find_frame_for_function (arg);
if (frame == NULL)
- error (_("'%s' not within current stack frame.\n"), arg);
+ error (_("'%s' not within current stack frame."), arg);
if (frame != get_selected_frame (NULL))
{
select_frame (frame);
}
}
+/* The qcs command line flags for the "frame apply" commands. Keep
+ this in sync with the "thread apply" commands. */
+
+using qcs_flag_option_def
+ = gdb::option::flag_option_def<qcs_flags>;
+
+static const gdb::option::option_def fr_qcs_flags_option_defs[] = {
+ qcs_flag_option_def {
+ "q", [] (qcs_flags *opt) { return &opt->quiet; },
+ N_("Disables printing the frame location information."),
+ },
+
+ qcs_flag_option_def {
+ "c", [] (qcs_flags *opt) { return &opt->cont; },
+ N_("Print any error raised by COMMAND and continue."),
+ },
+
+ qcs_flag_option_def {
+ "s", [] (qcs_flags *opt) { return &opt->silent; },
+ N_("Silently ignore any errors or empty output produced by COMMAND."),
+ },
+};
+
+/* Create an option_def_group array for all the "frame apply" options,
+ with FLAGS and SET_BT_OPTS as context. */
+
+static inline std::array<gdb::option::option_def_group, 2>
+make_frame_apply_options_def_group (qcs_flags *flags,
+ set_backtrace_options *set_bt_opts)
+{
+ return {{
+ { {fr_qcs_flags_option_defs}, flags },
+ { {set_backtrace_option_defs}, set_bt_opts },
+ }};
+}
+
+/* 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;
+ set_backtrace_options set_bt_opts = user_set_backtrace_options;
+
+ auto group = make_frame_apply_options_def_group (&flags, &set_bt_opts);
+ gdb::option::process_options
+ (&cmd, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group);
+
+ validate_flags_qcs (which_command, &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;
+
+ /* 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);
+
+ for (frame_info *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, gdb_stdout->term_out ());
+ }
+ 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 (const gdb_exception_error &ex)
+ {
+ 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.what ());
+ else
+ throw;
+ }
+ }
+ }
+}
+
+/* Completer for the "frame apply ..." commands. */
+
+static void
+frame_apply_completer (completion_tracker &tracker, const char *text)
+{
+ const auto group = make_frame_apply_options_def_group (nullptr, nullptr);
+ if (gdb::option::complete_options
+ (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group))
+ return;
+
+ complete_nested_command_line (tracker, text);
+}
+
+/* Completer for the "frame apply" commands. */
+
+static void
+frame_apply_level_cmd_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char */*word*/)
+{
+ /* Do this explicitly because there's an early return below. */
+ tracker.set_use_custom_word_point (true);
+
+ number_or_range_parser levels (text);
+
+ /* Skip the LEVEL list to find the options and command args. */
+ try
+ {
+ while (!levels.finished ())
+ {
+ /* Call for effect. */
+ levels.get_number ();
+
+ if (levels.in_range ())
+ levels.skip_range ();
+ }
+ }
+ catch (const gdb_exception_error &ex)
+ {
+ /* get_number throws if it parses a negative number, for
+ example. But a seemingly negative number may be the start of
+ an option instead. */
+ }
+
+ const char *cmd = levels.cur_tok ();
+
+ if (cmd == text)
+ {
+ /* No level list yet. */
+ return;
+ }
+
+ /* Check if we're past a valid LEVEL already. */
+ if (levels.finished ()
+ && cmd > text && !isspace (cmd[-1]))
+ return;
+
+ /* We're past LEVELs, advance word point. */
+ tracker.advance_custom_word_point_by (cmd - text);
+ text = cmd;
+
+ frame_apply_completer (tracker, text);
+}
+
+/* Completer for the "frame apply all" command. */
+
+void
+frame_apply_all_cmd_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char */*word*/)
+{
+ frame_apply_completer (tracker, text);
+}
+
+/* Completer for the "frame apply COUNT" command. */
+
+static void
+frame_apply_cmd_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char */*word*/)
+{
+ const char *cmd = text;
+
+ int count = get_number_trailer (&cmd, 0);
+ if (count == 0)
+ return;
+
+ /* Check if we're past a valid COUNT already. */
+ if (cmd > text && !isspace (cmd[-1]))
+ return;
+
+ /* We're past COUNT, advance word point. */
+ tracker.advance_custom_word_point_by (cmd - text);
+ text = cmd;
+
+ frame_apply_completer (tracker, text);
+}
+
+/* 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 ())
+ {
+ /* Call for effect. */
+ 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)
+{
+ if (cmd == NULL || *cmd == '\0')
+ error (_("Please specify a command to apply on all frames"));
+ std::string expanded = std::string ("frame apply all -s ") + cmd;
+ execute_command (expanded.c_str (), 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;
+}
+
+\f
+
+/* Commands with a prefix of `frame apply'. */
+static struct cmd_list_element *frame_apply_cmd_list = NULL;
+
+/* Commands with a prefix of `frame'. */
+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)
{
+ struct cmd_list_element *cmd;
+
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\
Same as the `down' command, but does not print anything.\n\
This is useful in command scripts."));
- add_com ("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."));
+ 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);
+#define FRAME_APPLY_OPTION_HELP "\
+Prints the frame location information followed by COMMAND output.\n\
+\n\
+By default, an error raised during the execution of COMMAND\n\
+aborts \"frame apply\".\n\
+\n\
+Options:\n\
+%OPTIONS%"
+
+ const auto frame_apply_opts
+ = make_frame_apply_options_def_group (nullptr, nullptr);
+
+ static std::string frame_apply_cmd_help = gdb::option::build_help (_("\
+Apply a command to a number of frames.\n\
+Usage: frame apply COUNT [OPTION]... COMMAND\n\
+With a negative COUNT argument, applies the command on outermost -COUNT frames.\n"
+ FRAME_APPLY_OPTION_HELP),
+ frame_apply_opts);
+
+ cmd = add_prefix_cmd ("apply", class_stack, frame_apply_command,
+ frame_apply_cmd_help.c_str (),
+ &frame_apply_cmd_list, "frame apply ", 1,
+ &frame_cmd_list);
+ set_cmd_completer_handle_brkchars (cmd, frame_apply_cmd_completer);
+
+ static std::string frame_apply_all_cmd_help = gdb::option::build_help (_("\
+Apply a command to all frames.\n\
+\n\
+Usage: frame apply all [OPTION]... COMMAND\n"
+ FRAME_APPLY_OPTION_HELP),
+ frame_apply_opts);
+
+ cmd = add_cmd ("all", class_stack, frame_apply_all_command,
+ frame_apply_all_cmd_help.c_str (),
+ &frame_apply_cmd_list);
+ set_cmd_completer_handle_brkchars (cmd, frame_apply_all_cmd_completer);
+
+ static std::string frame_apply_level_cmd_help = gdb::option::build_help (_("\
+Apply a command to a list of frames.\n\
+\n\
+Usage: frame apply level LEVEL... [OPTION]... COMMAND\n\
+LEVEL is a space-separated list of levels of frames to apply COMMAND on.\n"
+ FRAME_APPLY_OPTION_HELP),
+ frame_apply_opts);
+
+ cmd = add_cmd ("level", class_stack, frame_apply_level_command,
+ frame_apply_level_cmd_help.c_str (),
+ &frame_apply_cmd_list);
+ set_cmd_completer_handle_brkchars (cmd, frame_apply_level_cmd_completer);
+
+ cmd = add_com ("faas", class_stack, faas_command, _("\
+Apply a command to all frames (ignoring errors and empty output).\n\
+Usage: faas [OPTION]... COMMAND\n\
+shortcut for 'frame apply all -s [OPTION]... COMMAND'\n\
+See \"help frame apply all\" for available options."));
+ set_cmd_completer_handle_brkchars (cmd, frame_apply_all_cmd_completer);
+
+ 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_com_suppress_notification ("select-frame", class_stack, select_frame_command, _("\
+ 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);
- add_com ("backtrace", class_stack, backtrace_command, _("\
+ 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);
+
+ const auto backtrace_opts
+ = make_backtrace_options_def_group (nullptr, nullptr, nullptr);
+
+ static std::string backtrace_help
+ = gdb::option::build_help (_("\
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%\n\
+\n\
+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);
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_info ("locals", info_locals_command,
- _("Local variables of current stack frame."));
- add_info ("args", info_args_command,
- _("Argument variables of current stack frame."));
+
+ 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);
+
+ cmd = add_info ("locals", info_locals_command,
+ info_print_args_help (_("\
+All local variables of current stack frame or those matching REGEXPs.\n\
+Usage: info locals [-q] [-t TYPEREGEXP] [NAMEREGEXP]\n\
+Prints the local variables of the current stack frame.\n"),
+ _("local variables"),
+ false));
+ set_cmd_completer_handle_brkchars (cmd, info_print_command_completer);
+ cmd = add_info ("args", info_args_command,
+ info_print_args_help (_("\
+All argument variables of current stack frame or those matching REGEXPs.\n\
+Usage: info args [-q] [-t TYPEREGEXP] [NAMEREGEXP]\n\
+Prints the argument variables of the current stack frame.\n"),
+ _("argument variables"),
+ false));
+ set_cmd_completer_handle_brkchars (cmd, info_print_command_completer);
if (dbx_commands)
add_com ("func", class_stack, func_command, _("\
-Select the stack frame that contains <func>.\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);
-
- add_setshow_boolean_cmd ("frame-arguments", no_class,
- &print_raw_frame_arguments, _("\
+Select the stack frame that contains NAME.\n\
+Usage: func NAME"));
+
+ /* Install "set print raw frame-arguments", a deprecated spelling of
+ "set 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_auto_boolean_cmd ("disassemble-next-line", class_stack,
&disassemble_next_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 <optimized out>."),
- NULL, NULL, &setprintlist, &showprintlist);
+ gdb::option::add_setshow_cmds_for_options
+ (class_stack, &user_frame_print_options,
+ frame_print_option_defs, &setprintlist, &showprintlist);
}