+ if (! raw_arg && frame_filters)
+ {
+ frame_filter_flags flags = PRINT_LEVEL | PRINT_ARGS;
+ int py_frame_low = frame_low;
+
+ /* We cannot pass -1 to frame_low, as that would signify a
+ relative backtrace from the tail of the stack. So, in the case
+ of frame_low == -1, assign and increment it. */
+ if (py_frame_low == -1)
+ py_frame_low++;
+
+ result = mi_apply_ext_lang_frame_filter (get_current_frame (), flags,
+ print_values, current_uiout,
+ py_frame_low, frame_high);
+ }
+
+ /* Run the inbuilt backtrace if there are no filters registered, or
+ if "--no-frame-filters" has been specified from the command. */
+ if (! frame_filters || raw_arg || result == EXT_LANG_BT_NO_FILTERS)
+ {
+ /* Now let's print the frames up to frame_high, or until there are
+ frames in the stack. */
+ for (;
+ fi && (i <= frame_high || frame_high == -1);
+ i++, fi = get_prev_frame (fi))
+ {
+ QUIT;
+ ui_out_emit_tuple tuple_emitter (uiout, "frame");
+ uiout->field_signed ("level", i);
+ list_args_or_locals (user_frame_print_options,
+ arguments, print_values, fi, skip_unavailable);
+ }
+ }
+}
+
+/* Print a list of the local variables (including arguments) for the
+ current frame. ARGC must be 1 and ARGV[0] specify if only the names,
+ or both names and values of the variables must be printed. See
+ parse_print_value for possible values. */
+
+void
+mi_cmd_stack_list_variables (const char *command, char **argv, int argc)
+{
+ struct frame_info *frame;
+ int raw_arg = 0;
+ enum ext_lang_bt_status result = EXT_LANG_BT_ERROR;
+ enum print_values print_value;
+ int oind = 0;
+ int skip_unavailable = 0;
+
+ if (argc > 1)
+ {
+ enum opt
+ {
+ NO_FRAME_FILTERS,
+ SKIP_UNAVAILABLE,
+ };
+ static const struct mi_opt opts[] =
+ {
+ {"-no-frame-filters", NO_FRAME_FILTERS, 0},
+ {"-skip-unavailable", SKIP_UNAVAILABLE, 0},
+ { 0, 0, 0 }
+ };
+
+ while (1)
+ {
+ char *oarg;
+ /* Don't parse 'print-values' as an option. */
+ int opt = mi_getopt ("-stack-list-variables", argc - 1,
+ argv, opts, &oind, &oarg);
+ if (opt < 0)
+ break;
+ switch ((enum opt) opt)
+ {
+ case NO_FRAME_FILTERS:
+ raw_arg = oind;
+ break;
+ case SKIP_UNAVAILABLE:
+ skip_unavailable = 1;
+ break;
+ }
+ }
+ }
+
+ /* After the last option is parsed, there should be only
+ 'print-values'. */
+ if (argc - oind != 1)
+ error (_("-stack-list-variables: Usage: [--no-frame-filters] " \
+ "[--skip-unavailable] PRINT_VALUES"));
+
+ frame = get_selected_frame (NULL);
+ print_value = mi_parse_print_values (argv[oind]);
+
+ if (! raw_arg && frame_filters)
+ {
+ frame_filter_flags flags = PRINT_LEVEL | PRINT_ARGS | PRINT_LOCALS;
+
+ result = mi_apply_ext_lang_frame_filter (frame, flags,
+ print_value,
+ current_uiout, 0, 0);
+ }
+
+ /* Run the inbuilt backtrace if there are no filters registered, or
+ 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 (user_frame_print_options,
+ all, print_value, frame,
+ skip_unavailable);
+ }
+}
+
+/* Print single local or argument. ARG must be already read in. For
+ WHAT and VALUES see list_args_or_locals.
+
+ Errors are printed as if they would be the parameter value. Use
+ zeroed ARG iff it should not be printed according to VALUES. If
+ SKIP_UNAVAILABLE is true, only print ARG if it is available. */
+
+static void
+list_arg_or_local (const struct frame_arg *arg, enum what_to_list what,
+ enum print_values values, int skip_unavailable)
+{
+ struct ui_out *uiout = current_uiout;
+
+ gdb_assert (!arg->val || !arg->error);
+ gdb_assert ((values == PRINT_NO_VALUES && arg->val == NULL
+ && arg->error == NULL)
+ || values == PRINT_SIMPLE_VALUES
+ || (values == PRINT_ALL_VALUES
+ && (arg->val != NULL || arg->error != NULL)));
+ gdb_assert (arg->entry_kind == print_entry_values_no
+ || (arg->entry_kind == print_entry_values_only
+ && (arg->val || arg->error)));
+
+ if (skip_unavailable && arg->val != NULL
+ && (value_entirely_unavailable (arg->val)
+ /* A scalar object that does not have all bits available is
+ also considered unavailable, because all bits contribute
+ to its representation. */
+ || (val_print_scalar_type_p (value_type (arg->val))
+ && !value_bytes_available (arg->val,
+ value_embedded_offset (arg->val),
+ TYPE_LENGTH (value_type (arg->val))))))
+ return;
+
+ gdb::optional<ui_out_emit_tuple> tuple_emitter;
+ if (values != PRINT_NO_VALUES || what == all)
+ tuple_emitter.emplace (uiout, nullptr);
+
+ string_file stb;
+
+ stb.puts (arg->sym->print_name ());
+ if (arg->entry_kind == print_entry_values_only)
+ stb.puts ("@entry");
+ uiout->field_stream ("name", stb);
+
+ if (what == all && SYMBOL_IS_ARGUMENT (arg->sym))
+ uiout->field_signed ("arg", 1);
+
+ if (values == PRINT_SIMPLE_VALUES)