diff --git a/gdb/extension.h b/gdb/extension.h
index 2f1b71851c..405346ff6a 100644
--- a/gdb/extension.h
+++ b/gdb/extension.h
@@ -125,7 +125,10 @@ enum ext_lang_frame_args
     CLI_SCALAR_VALUES,
 
     /* Print all values for arguments when invoked from the CLI. */
-    CLI_ALL_VALUES
+    CLI_ALL_VALUES,
+
+    /* Only indicate the presence of arguments when invoked from the CLI.  */
+    CLI_PRESENCE
   };
 
 /* The possible results of
diff --git a/gdb/frame.h b/gdb/frame.h
index a79eeeeab1..ccc285005a 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -677,18 +677,28 @@ extern struct gdbarch *frame_unwind_arch (frame_info *next_frame);
 extern struct gdbarch *frame_unwind_caller_arch (struct frame_info *frame);
 
 
-/* Values for the source flag to be used in print_frame_info_base().  */
+/* Values for the source flag to be used in print_frame_info ().
+   For all the cases below, the address is never printed if
+   'set print address' is off.  When 'set print address' is on,
+   the address is printed if the program counter is not at the
+   beginning of the source line of the frame
+   and PRINT_WHAT is != LOC_AND_ADDRESS.  */
 enum print_what
-  { 
-    /* Print only the source line, like in stepi.  */
-    SRC_LINE = -1, 
-    /* Print only the location, i.e. level, address (sometimes)
-       function, args, file, line, line num.  */
+  {
+    /* Print only the address, source line, like in stepi.  */
+    SRC_LINE = -1,
+    /* Print only the location, i.e. level, address,
+       function, args (as controlled by 'set print frame-arguments'),
+       file, line, line num.  */
     LOCATION,
     /* Print both of the above.  */
-    SRC_AND_LOC, 
-    /* Print location only, but always include the address.  */
-    LOC_AND_ADDRESS 
+    SRC_AND_LOC,
+    /* Print location only, print the address even if the program counter
+       is at the beginning of the source line.  */
+    LOC_AND_ADDRESS,
+    /* Print only level and function,
+       i.e. location only, without address, file, line, line num.  */
+    SHORT_LOCATION
   };
 
 /* Allocate zero initialized memory from the frame cache obstack.
@@ -772,6 +782,14 @@ extern const char print_frame_arguments_all[];
 extern const char print_frame_arguments_scalars[];
 extern const char print_frame_arguments_none[];
 
+/* The possible choices of "set print frame-info".  */
+extern const char print_frame_info_auto[];
+extern const char print_frame_info_source_line[];
+extern const char print_frame_info_location[];
+extern const char print_frame_info_source_and_location[];
+extern const char print_frame_info_location_and_address[];
+extern const char print_frame_info_short_location[];
+
 /* The possible choices of "set print entry-values".  */
 extern const char print_entry_values_no[];
 extern const char print_entry_values_only[];
@@ -787,6 +805,7 @@ extern const char print_entry_values_default[];
 struct frame_print_options
 {
   const char *print_frame_arguments = print_frame_arguments_scalars;
+  const char *print_frame_info = print_frame_info_auto;
   const char *print_entry_values = print_entry_values_default;
 
   /* If non-zero, don't invoke pretty-printers for frame
diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c
index 95ad410f23..f1282597a5 100644
--- a/gdb/python/py-framefilter.c
+++ b/gdb/python/py-framefilter.c
@@ -25,6 +25,8 @@
 #include "python.h"
 #include "ui-out.h"
 #include "valprint.h"
+#include "stack.h"
+#include "source.h"
 #include "annotate.h"
 #include "hashtab.h"
 #include "demangle.h"
@@ -713,9 +715,21 @@ py_print_args (PyObject *filter,
   annotate_frame_args ();
   out->text (" (");
 
-  if (args_iter != Py_None
-      && (enumerate_args (args_iter.get (), out, args_type, 0, frame)
-	  == EXT_LANG_BT_ERROR))
+  if (args_type == CLI_PRESENCE)
+    {
+      if (args_iter != Py_None)
+	{
+	  gdbpy_ref<> item (PyIter_Next (args_iter.get ()));
+
+	  if (item != NULL)
+	    out->text ("...");
+	  else if (PyErr_Occurred ())
+	    return EXT_LANG_BT_ERROR;
+	}
+    }
+  else if (args_iter != Py_None
+	   && (enumerate_args (args_iter.get (), out, args_type, 0, frame)
+	       == EXT_LANG_BT_ERROR))
     return EXT_LANG_BT_ERROR;
 
   out->text (")");
@@ -748,7 +762,16 @@ py_print_frame (PyObject *filter, frame_filter_flags flags,
   struct gdbarch *gdbarch = NULL;
   struct frame_info *frame = NULL;
   struct value_print_options opts;
+
   int print_level, print_frame_info, print_args, print_locals;
+  /* Note that the below default in non-mi mode is the same as the
+     default value for the backtrace command (see the call to print_frame_info
+     in backtrace_command_1).
+     Having the same default ensures that 'bt' and 'bt no-filters'
+     have the same behaviour when some filters exist but do not apply
+     to a frame.  */
+  enum print_what print_what
+    = out->is_mi_like_p () ? LOC_AND_ADDRESS : LOCATION;
   gdb::unique_xmalloc_ptr<char> function_to_free;
 
   /* Extract print settings from FLAGS.  */
@@ -758,6 +781,17 @@ py_print_frame (PyObject *filter, frame_filter_flags flags,
   print_locals = (flags & PRINT_LOCALS) ? 1 : 0;
 
   get_user_print_options (&opts);
+  if (print_frame_info)
+  {
+    gdb::optional<enum print_what> user_frame_info_print_what;
+
+    get_user_print_what_frame_info (&user_frame_info_print_what);
+    if (!out->is_mi_like_p () && user_frame_info_print_what.has_value ())
+      {
+	/* Use the specific frame information desired by the user.  */
+	print_what = *user_frame_info_print_what;
+      }
+  }
 
   /* Get the underlying frame.  This is needed to determine GDB
   architecture, and also, in the cases of frame variables/arguments to
@@ -771,6 +805,8 @@ py_print_frame (PyObject *filter, frame_filter_flags flags,
   if (frame == NULL)
     return EXT_LANG_BT_ERROR;
 
+  symtab_and_line sal = find_frame_sal (frame);
+
   gdbarch = get_frame_arch (frame);
 
   /* stack-list-variables.  */
@@ -815,9 +851,19 @@ py_print_frame (PyObject *filter, frame_filter_flags flags,
 	}
     }
 
+  /* For MI, each piece is controlled individually.  */
+  bool location_print = (print_frame_info
+			 && !out->is_mi_like_p ()
+			 && (print_what == LOCATION
+			     || print_what == SRC_AND_LOC
+			     || print_what == LOC_AND_ADDRESS
+			     || print_what == SHORT_LOCATION));
+
   /* Print frame level.  MI does not require the level if
      locals/variables only are being printed.  */
-  if ((print_frame_info || print_args) && print_level)
+  if (print_level
+      && (location_print
+	  || (out->is_mi_like_p () && (print_frame_info || print_args))))
     {
       struct frame_info **slot;
       int level;
@@ -844,16 +890,21 @@ py_print_frame (PyObject *filter, frame_filter_flags flags,
 	}
     }
 
-  if (print_frame_info)
+  if (location_print || (out->is_mi_like_p () && print_frame_info))
     {
       /* Print address to the address field.  If an address is not provided,
 	 print nothing.  */
       if (opts.addressprint && has_addr)
 	{
-	  annotate_frame_address ();
-	  out->field_core_addr ("addr", gdbarch, address);
-	  annotate_frame_address_end ();
-	  out->text (" in ");
+	  if (!sal.symtab
+	      || frame_show_address (frame, sal)
+	      || print_what == LOC_AND_ADDRESS)
+	    {
+	      annotate_frame_address ();
+	      out->field_core_addr ("addr", gdbarch, address);
+	      annotate_frame_address_end ();
+	      out->text (" in ");
+	    }
 	}
 
       /* Print frame function name.  */
@@ -905,14 +956,17 @@ py_print_frame (PyObject *filter, frame_filter_flags flags,
 
   /* Frame arguments.  Check the result, and error if something went
      wrong.  */
-  if (print_args)
+  if (print_args && (location_print || out->is_mi_like_p ()))
     {
       if (py_print_args (filter, out, args_type, frame) == EXT_LANG_BT_ERROR)
 	return EXT_LANG_BT_ERROR;
     }
 
   /* File name/source/line number information.  */
-  if (print_frame_info)
+  bool print_location_source
+    = ((location_print && print_what != SHORT_LOCATION)
+       || (out->is_mi_like_p () && print_frame_info));
+  if (print_location_source)
     {
       annotate_frame_source_begin ();
 
@@ -964,12 +1018,24 @@ py_print_frame (PyObject *filter, frame_filter_flags flags,
                            (gdbarch_bfd_arch_info (gdbarch))->printable_name);
     }
 
+  bool source_print
+    = (! out->is_mi_like_p ()
+       && (print_what == SRC_LINE || print_what == SRC_AND_LOC));
+  if (source_print)
+    {
+      if (print_location_source)
+	out->text ("\n"); /* Newline after the location source.  */
+      print_source_lines (sal.symtab, sal.line, sal.line + 1, 0);
+    }
+
   /* For MI we need to deal with the "children" list population of
      elided frames, so if MI output detected do not send newline.  */
   if (! out->is_mi_like_p ())
     {
       annotate_frame_end ();
-      out->text ("\n");
+      /* print_source_lines has already printed a newline.  */
+      if (!source_print)
+	out->text ("\n");
     }
 
   if (print_locals)
diff --git a/gdb/stack.c b/gdb/stack.c
index b3d113d3b4..de3eb27d0c 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -61,15 +61,42 @@
 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[] =
 {
   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";
+
+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.  */
 
@@ -137,6 +164,17 @@ or both.  Note that one or both of these values may be <optimized out>."),
     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.  */
@@ -209,10 +247,9 @@ static struct symtab *last_displayed_symtab = 0;
 static int last_displayed_line = 0;
 
 
-/* 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
+int
 frame_show_address (struct frame_info *frame,
 		    struct symtab_and_line sal)
 {
@@ -631,9 +668,13 @@ print_frame_args (const frame_print_options &fp_opts,
   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.  */
-  bool print_args
-    = fp_opts.print_frame_arguments != print_frame_arguments_none;
+  bool print_args = print_names
+    && fp_opts.print_frame_arguments != print_frame_arguments_none;
 
   if (func)
     {
@@ -653,6 +694,13 @@ print_frame_args (const frame_print_options &fp_opts,
 	  if (!SYMBOL_IS_ARGUMENT (sym))
 	    continue;
 
+	  if (!print_names)
+	    {
+	      uiout->text ("...");
+	      first = 0;
+	      break;
+	    }
+
 	  switch (SYMBOL_CLASS (sym))
 	    {
 	    case LOC_ARG:
@@ -801,8 +849,11 @@ print_frame_args (const frame_print_options &fp_opts,
       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);
     }
 }
 
@@ -859,13 +910,35 @@ do_gdb_disassembly (struct gdbarch *gdbarch,
     }
 }
 
+/* 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);
+}
+
+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 overriden if FP_OPTS.print_frame_info
+   != print_frame_info_auto.
 
    Used in "where" output, and to emit breakpoint or step
    messages.  */
@@ -881,6 +954,13 @@ print_frame_info (const frame_print_options &fp_opts,
   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)
@@ -944,10 +1024,10 @@ print_frame_info (const frame_print_options &fp_opts,
      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 (fp_opts, frame, print_level, print_what, print_args, sal);
 
@@ -1299,7 +1379,7 @@ print_frame (const frame_print_options &fp_opts,
 	QUIT;
       }
     uiout->text (")");
-    if (sal.symtab)
+    if (print_what != SHORT_LOCATION && sal.symtab)
       {
 	const char *filename_display;
       
@@ -1322,7 +1402,8 @@ print_frame (const frame_print_options &fp_opts,
 	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));
@@ -1932,8 +2013,12 @@ backtrace_command_1 (const frame_print_options &fp_opts,
 	arg_type = CLI_SCALAR_VALUES;
       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,
diff --git a/gdb/stack.h b/gdb/stack.h
index 9ac77c0617..dda4fc9f66 100644
--- a/gdb/stack.h
+++ b/gdb/stack.h
@@ -42,6 +42,18 @@ void iterate_over_block_local_vars (const struct block *block,
 				    iterate_over_block_arg_local_vars_cb cb,
 				    void *cb_data);
 
+/* Initialize *WHAT to be a copy of the user desired print what frame info.
+   If !WHAT.has_value (), the printing function chooses a default set of
+   information to print, otherwise the printing function should print
+   the relevant information.  */
+
+void get_user_print_what_frame_info (gdb::optional<enum print_what> *what);
+
+/* Return 1 if we should display the address in addition to the location,
+   because we are in the middle of a statement.  */
+
+int frame_show_address (struct frame_info *frame, struct symtab_and_line sal);
+
 /* Get or set the last displayed symtab and line, which is, e.g. where we set a
  * breakpoint when `break' is supplied with no arguments.  */
 void clear_last_displayed_sal (void);
