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

login
register
mail settings
Submitter Philippe Waroquiers
Date May 11, 2019, 6:56 p.m.
Message ID <20190511185603.17231-2-philippe.waroquiers@skynet.be>
Download mbox | patch
Permalink /patch/32649/
State New
Headers show

Comments

Philippe Waroquiers - May 11, 2019, 6:56 p.m.
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(-)

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);