[RFAv2,1/3] Implement 'set print frame-info|frame-arguments presence'.

Message ID 20190511185603.17231-2-philippe.waroquiers@skynet.be
State New, archived
Headers

Commit Message

Philippe Waroquiers May 11, 2019, 6:56 p.m. UTC
  New settings allow to better control what frame information is printed.

'set print frame-info' allows to override the default frame information
printed when a GDB command prints a frame.

It is now possible to have very short frame information by using the
new 'set print frame-arguments presence' and 'set print frame-info short_loc'.

Combined with 'set print address off', a backtrace will only show
the essential information to see the function call chain, e.g.:
  (gdb) set print address off
  (gdb) set print frame-arguments presence
  (gdb) set print frame-info short_loc
  (gdb) bt
  #0  break_me ()
  #1  call_me (...)
  #2  main ()
  (gdb)

This is handy in particular for big backtraces with functions having
many arguments.

Python frame filter printing logic has been updated to respect the new
setting in non MI mode.
---
 gdb/ChangeLog               |  21 +++++++
 gdb/extension.h             |   5 +-
 gdb/frame.h                 |  28 +++++++---
 gdb/python/py-framefilter.c |  84 ++++++++++++++++++++++++----
 gdb/stack.c                 | 106 +++++++++++++++++++++++++++++-------
 gdb/stack.h                 |  12 ++++
 6 files changed, 215 insertions(+), 41 deletions(-)
  

Comments

Tom Tromey June 4, 2019, 5:11 p.m. UTC | #1
>>>>> "Philippe" == Philippe Waroquiers <philippe.waroquiers@skynet.be> writes:

Philippe> New settings allow to better control what frame information is printed.
Philippe> 'set print frame-info' allows to override the default frame information
Philippe> printed when a GDB command prints a frame.

Thanks for the patch.

I wanted to mention - in the last series, I noticed that the ChangeLog
entries didn't wind up in the commit messages.  I think it is a gdb
standard to do that, so please make sure it happens for future pushes.

I realize this is a bit of a pain, but various people have scripts for
automating it, I believe, and so you can pretty much pick one approach
that appeals to you.

Philippe> +  if (args_type == CLI_PRESENCE)
Philippe> +    {
Philippe> +      if (args_iter != Py_None)
Philippe> +	{
Philippe> +	  if (PyIter_Next (args_iter.get ()) != NULL)

This causes a memory leak, because PyIter_Next returns a new reference.
You can wrap it in a gdbpy_ref<> to avoid this problem.

Sometimes I think we just use wrapper functions for the Python API that
let us spell out this stuff in the type system.

Philippe> +  /* Note that this print_what default implies that 'bt' and 'bt no-filters'
Philippe> +     shows different information, as the default for 'bt no-filters
Philippe> +     is LOCATION.  */
Philippe> +  enum print_what print_what = LOC_AND_ADDRESS;

Is this a pre-existing bug?  It seems like something we should change,
since my believe is that "no filters" should produce the same output as
the situation where there are actually no filters installed.

Tom
  
Philippe Waroquiers June 10, 2019, 12:48 p.m. UTC | #2
On Tue, 2019-06-04 at 11:11 -0600, Tom Tromey wrote:
> > > > > > "Philippe" == Philippe Waroquiers <philippe.waroquiers@skynet.be> writes:
> 
> Philippe> New settings allow to better control what frame information is printed.
> Philippe> 'set print frame-info' allows to override the default frame information
> Philippe> printed when a GDB command prints a frame.
> 
> Thanks for the patch.
> 
> I wanted to mention - in the last series, I noticed that the ChangeLog
> entries didn't wind up in the commit messages.  I think it is a gdb
> standard to do that, so please make sure it happens for future pushes.
Sorry, I thought that having the ChangeLog file was sufficient.
I will ensure that it is done in the future.

> 
> I realize this is a bit of a pain, but various people have scripts for
> automating it, I believe, and so you can pretty much pick one approach
> that appeals to you.
> 
> Philippe> +  if (args_type == CLI_PRESENCE)
> Philippe> +    {
> Philippe> +      if (args_iter != Py_None)
> Philippe> +	{
> Philippe> +	  if (PyIter_Next (args_iter.get ()) != NULL)
> 
> This causes a memory leak, because PyIter_Next returns a new reference.
> You can wrap it in a gdbpy_ref<> to avoid this problem.
Fixed.
(Note that also for this patch series, I will wait for Pedro to push cli-option
to avoid pushing merge conflicts to him).

> 
> Sometimes I think we just use wrapper functions for the Python API that
> let us spell out this stuff in the type system.
> 
> Philippe> +  /* Note that this print_what default implies that 'bt' and 'bt no-filters'
> Philippe> +     shows different information, as the default for 'bt no-filters
> Philippe> +     is LOCATION.  */
> Philippe> +  enum print_what print_what = LOC_AND_ADDRESS;
> 
> Is this a pre-existing bug?  It seems like something we should change,
> since my believe is that "no filters" should produce the same output as
> the situation where there are actually no filters installed.
Yes, it is a pre-existing "bug", but the difference of behaviour is
between 'bt' and 'bt no-filters' *when there are some filters*.

here is a log with the HEAD:

(gdb) bt
#0  0x000055555555548e in niam (argc=1, argv=0x7fffffffe0d8) at sleepers.c:194
(gdb) bt no-filters
#0  main (argc=1, argv=0x7fffffffe0d8) at sleepers.c:194
(gdb) p $pc
$1 = (void (*)()) 0x55555555548e <main+823>
(gdb) frame
#0  main (argc=1, argv=0x7fffffffe0d8) at sleepers.c:194
194	  sleeper_or_burner(&m);
(gdb) info line
Line 194 of "sleepers.c" starts at address 0x55555555548e <main+823> and ends at
0x55555555549d <main+838>.
(gdb) 

As you can see, the first 'bt' is applying a filter (the 'Reverse' filter
of gdb/testsuite/gdb.python/py-framefilter.py), and shows the address,
while the 'bt no-filters' does not show the address.

This difference of behaviour will be visible as long as there is
one filter active, even if the filter is a 'no effect' filter.

This is because backtrace_command_1 calls apply_ext_lang_frame_filter.
If this finds at least one active filter, it will print the frame itself
by calling py_print_frame.
If there are no active filter or with 'bt no-filters', backtrace_command_1
calls 'print_frame_info (..., LOCATION, ...).

So, the GDB HEAD has a different default way to print a frame
when it is printed by py_print_frame or by stack.c print_frame_info.

The 'set print frame-info auto' setting aims at keeping a backward
compatible behaviour : in GDB HEAD, different commands have different
behaviours, and 'auto' means to let each command decide by itself
what to do.

If the user chooses a specific value (e.g. 'set print frame-info location'),
then with this patch, the python frame filtering will do what the user wants.

So, the question is: do we want to change the default output behaviour
of python frame filters to be LOCATION ?
That is of course a user visible change.

Philippe
  
Tom Tromey June 10, 2019, 8:10 p.m. UTC | #3
>>>>> "Philippe" == Philippe Waroquiers <philippe.waroquiers@skynet.be> writes:

>> Is this a pre-existing bug?  It seems like something we should change,
>> since my believe is that "no filters" should produce the same output as
>> the situation where there are actually no filters installed.

Philippe> Yes, it is a pre-existing "bug", but the difference of behaviour is
Philippe> between 'bt' and 'bt no-filters' *when there are some filters*.
[...]
Philippe> This difference of behaviour will be visible as long as there is
Philippe> one filter active, even if the filter is a 'no effect' filter.

Philippe> So, the question is: do we want to change the default output behaviour
Philippe> of python frame filters to be LOCATION ?
Philippe> That is of course a user visible change.

Yes, I think this ought to change.  Installing a "no effect" filter
should not have any effect on the output.

Tom
  

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 9492412efb..9ba008a35c 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -6765,3 +6765,24 @@  version-control: never
 coding: utf-8
 End:
 
+2019-05-04  Philippe Waroquiers  <philippe.waroquiers@skynet.be>
+
+	* NEWS: Mention 'set|show print frame-info'.  Mention new
+	'presence' value for 'frame-arguments'.
+	* frame.h (enum print_what): New value 'SHORT_LOCATION', update
+	comments.
+	* extension.h (enum ext_lang_frame_args): New value CLI_PRESENCE.
+	* stack.h (get_user_print_what_frame_info): New declaration.
+	(frame_show_address): New declaration.
+	* stack.c (print_frame_arguments_choices): New value 'presence'.
+	(print_frame_args): Only print dots for args if print frame-arguments
+	is 'presence'.
+	(get_user_print_what_frame_info): New function.
+	(frame_show_address): Make non static.  Move comment to stack.h.
+	(print_what_frame_info_string, print_what_frame_info)
+	(set_print_frame_info_command): New variables and function.
+	(print_frame_info): Update comment.  Use print_what_frame_info
+	to decide what to print.
+	(_initialize_stack): Call add_setshow_enum_cmd for frame-info.
+	* py-framefilter.c (py_print_args): Handle CLI_PRESENCE.
+	(py_print_frame): Handle frame-info user option in non MI mode.
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 0a0baf46a0..4c0ee4d53e 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -675,18 +675,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.
diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c
index 017ea90f61..1e20f6f4ce 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"
@@ -712,9 +714,19 @@  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)
+	{
+	  if (PyIter_Next (args_iter.get ()) != 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 (")");
@@ -747,7 +759,12 @@  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 this print_what default implies that 'bt' and 'bt no-filters'
+     shows different information, as the default for 'bt no-filters
+     is LOCATION.  */
+  enum print_what print_what = LOC_AND_ADDRESS;
   gdb::unique_xmalloc_ptr<char> function_to_free;
 
   /* Extract print settings from FLAGS.  */
@@ -757,6 +774,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
@@ -770,6 +798,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.  */
@@ -814,9 +844,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;
@@ -843,16 +883,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.  */
@@ -904,14 +949,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 ();
 
@@ -963,12 +1011,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 408c795e38..2c19e961c2 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -57,7 +57,7 @@ 
    of this setting.  */
 
 static const char *const print_frame_arguments_choices[] =
-  {"all", "scalars", "none", NULL};
+  {"all", "scalars", "none", "presence", NULL};
 static const char *print_frame_arguments = "scalars";
 
 /* If non-zero, don't invoke pretty-printers for frame arguments.  */
@@ -123,10 +123,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)
 {
@@ -539,8 +538,11 @@  print_frame_args (struct symbol *func, struct frame_info *frame,
   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.  */
+  int print_names = strcmp (print_frame_arguments, "presence");
   /* True if we should print arguments, false otherwise.  */
-  int print_args = strcmp (print_frame_arguments, "none");
+  int print_args = print_names && strcmp (print_frame_arguments, "none");
 
   if (func)
     {
@@ -560,6 +562,13 @@  print_frame_args (struct symbol *func, struct frame_info *frame,
 	  if (!SYMBOL_IS_ARGUMENT (sym))
 	    continue;
 
+	  if (!print_names)
+	    {
+	      uiout->text ("...");
+	      first = 0;
+	      break;
+	    }
+
 	  switch (SYMBOL_CLASS (sym))
 	    {
 	    case LOC_ARG:
@@ -708,8 +717,11 @@  print_frame_args (struct symbol *func, struct frame_info *frame,
       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);
     }
 }
 
@@ -766,13 +778,51 @@  do_gdb_disassembly (struct gdbarch *gdbarch,
     }
 }
 
+/* The possible choices of "set print frame-info", and the value
+   of this setting.  */
+
+static const char *const print_frame_info_choices[] =
+  {"auto", "source-line", "location", "source-and-location",
+   "location-and-address", "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};
+static const char *print_what_frame_info_string = "auto";
+static gdb::optional<enum print_what> print_what_frame_info;
+
+/* Set command.  Change the current frame info to print.  */
+
+static void
+set_print_frame_info_command (const char *ignore,
+			      int from_tty, struct cmd_list_element *c)
+{
+
+  for (int i = 0; print_frame_info_choices[i] != NULL; i++)
+    {
+      if (strcmp (print_what_frame_info_string,
+		  print_frame_info_choices[i]) == 0)
+	{
+	  print_what_frame_info = print_frame_info_print_what[i];
+	  return;
+	}
+    }
+
+  internal_error (__FILE__, __LINE__,
+		  "Unexpected set print frame-info `%s'.",
+		  print_what_frame_info_string);
+}
+
+void
+get_user_print_what_frame_info (gdb::optional<enum print_what> *what)
+{
+  *what = print_what_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.
 
    Used in "where" output, and to emit breakpoint or step
    messages.  */
@@ -787,6 +837,12 @@  print_frame_info (struct frame_info *frame, int print_level,
   int location_print;
   struct ui_out *uiout = current_uiout;
 
+  if (!current_uiout->is_mi_like_p () && print_what_frame_info.has_value ())
+    {
+      /* Use the specific frame information desired by the user.  */
+      print_what = *print_what_frame_info;
+    }
+
   if (get_frame_type (frame) == DUMMY_FRAME
       || get_frame_type (frame) == SIGTRAMP_FRAME
       || get_frame_type (frame) == ARCH_FRAME)
@@ -850,10 +906,10 @@  print_frame_info (struct frame_info *frame, int print_level,
      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);
 
@@ -1210,7 +1266,7 @@  print_frame (struct frame_info *frame, int print_level,
 	QUIT;
       }
     uiout->text (")");
-    if (sal.symtab)
+    if (print_what != SHORT_LOCATION && sal.symtab)
       {
 	const char *filename_display;
       
@@ -1233,7 +1289,8 @@  print_frame (struct frame_info *frame, int print_level,
 	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));
@@ -1833,8 +1890,12 @@  backtrace_command_1 (const char *count_exp, frame_filter_flags flags,
 	arg_type = CLI_SCALAR_VALUES;
       else if (!strcmp (print_frame_arguments, "all"))
 	arg_type = CLI_ALL_VALUES;
-      else
+      else if (!strcmp (print_frame_arguments, "presence"))
+	arg_type = CLI_PRESENCE;
+      else if (!strcmp (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,
@@ -3106,6 +3167,13 @@  Usage: func NAME"));
 			_("Show printing of non-scalar frame arguments"),
 			NULL, NULL, NULL, &setprintlist, &showprintlist);
 
+  add_setshow_enum_cmd ("frame-info", class_stack,
+			print_frame_info_choices, &print_what_frame_info_string,
+			_("Set printing of frame information"),
+			_("Show printing of frame information"),
+			NULL, set_print_frame_info_command, NULL,
+			&setprintlist, &showprintlist);
+
   add_setshow_boolean_cmd ("frame-arguments", no_class,
 			   &print_raw_frame_arguments, _("\
 Set whether to print frame arguments in raw form."), _("\
diff --git a/gdb/stack.h b/gdb/stack.h
index 6c6caa913e..32fb196eed 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);