This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

fix "collect $locals" bitrot


Collecting locals of a function with "collect $locals"
prints something weird at "tstart" time.  For example,
with code like this:

 void function ()
 {
   struct foo {};
   struct foo bar;      
 }

You'd see:

 (gdb) trace function
 (gdb) commands
 >collect $locals
 >end
 (gdb) tstart
 foo: don't know symbol class 8
 (gdb) 

The issue is just the bytecode generator not knowing
what to do with the `foo' symbol.

When addressing the issue in ax-gdb.c, I noticed that 
there are several corner cases and workarounds for
some compilers in the code that implements "info args" and
"info locals" in gdb/stack.c.  So instead of fixing this
locally in gdb/ax-gdb.c, I thought of factoring out the
stack.c that iterates over local args and locals, behind a
callback interface, so it's useable for both printing and
bytecode generation.  The main idea being prevent
future bitrot.

Here's the patch below.  No regressions on x86_64 against
a gdbserver that supports tracepoints.

I've added a local struct to the gdb.trace/collection.exp
test that collects locals; that is enough to trigger the
bug and cause a failure with an unpatched GDB.

I wouldn't mind an extra pair of eyes looking at the patch.

-- 
Pedro Alves

2010-03-29  Pedro Alves  <pedro@codesourcery.com>

	gdb/
	* tracepoint.c: Include stack.h.
	(struct add_local_symbols_data): New.
	(do_collect_symbol): New.
	(add_local_symbols): Rewrite using iterate_over_block_arg_vars and
	iterate_over_block_local_vars.
	* stack.c (print_block_frame_locals): Rewrite as ...
	(iterate_over_block_locals): ... this.  Take a callback function
	pointer and generic data pointer, and call that instead of
	print_variable_and_value.
	(struct print_variable_and_value_data): New.
	(do_print_variable_and_value): New.
	(iterate_over_block_local_vars): New, abstracted out from
	print_frame_local_vars.
	(print_frame_local_vars): Rewrite using
	iterate_over_block_local_vars.
	(iterate_over_block_arg_vars): New, abstracted out from
	print_frame_arg_vars.
	(print_frame_arg_vars): Rewrite using iterate_over_block_arg_vars.
	* stack.h (iterate_over_block_arg_local_vars_cb): New typedef.
	(iterate_over_block_arg_vars, iterate_over_block_local_vars): Declare.

2010-03-29  Pedro Alves  <pedro@codesourcery.com>

	gdb/testsuite/
	* gdb.trace/collection.c (local_test_func): Define a local struct,
	and instanciate it.

---
 gdb/stack.c                          |  136 ++++++++++++++++++++++-------------
 gdb/stack.h                          |   12 +++
 gdb/testsuite/gdb.trace/collection.c |    1 
 gdb/tracepoint.c                     |   77 ++++++++++++++-----
 4 files changed, 157 insertions(+), 69 deletions(-)

Index: src/gdb/tracepoint.c
===================================================================
--- src.orig/gdb/tracepoint.c	2010-03-29 01:58:22.000000000 +0100
+++ src/gdb/tracepoint.c	2010-03-29 01:58:55.000000000 +0100
@@ -44,6 +44,7 @@
 #include "objfiles.h"
 #include "filenames.h"
 #include "gdbthread.h"
+#include "stack.h"
 
 #include "ax.h"
 #include "ax-gdb.h"
@@ -990,40 +991,72 @@ collect_symbol (struct collection_list *
     }
 }
 
+struct add_local_symbols_data
+{
+  struct collection_list *collect;
+  struct gdbarch *gdbarch;
+  CORE_ADDR pc;
+  long frame_regno;
+  long frame_offset;
+  int count;
+};
+
+static void
+do_collect_symbol (const char *print_name,
+		   struct symbol *sym,
+		   void *cb_data)
+{
+  struct add_local_symbols_data *p = cb_data;
+
+  collect_symbol (p->collect, sym, p->gdbarch, p->frame_regno,
+		  p->frame_offset, p->pc);
+  p->count++;
+}
+
 /* Add all locals (or args) symbols to collection list */
 static void
 add_local_symbols (struct collection_list *collect,
 		   struct gdbarch *gdbarch, CORE_ADDR pc,
 		   long frame_regno, long frame_offset, int type)
 {
-  struct symbol *sym;
   struct block *block;
-  struct dict_iterator iter;
-  int count = 0;
+  struct add_local_symbols_data cb_data;
 
-  block = block_for_pc (pc);
-  while (block != 0)
+  cb_data.collect = collect;
+  cb_data.gdbarch = gdbarch;
+  cb_data.pc = pc;
+  cb_data.frame_regno = frame_regno;
+  cb_data.frame_offset = frame_offset;
+  cb_data.count = 0;
+
+  if (type == 'L')
     {
-      QUIT;			/* allow user to bail out with ^C */
-      ALL_BLOCK_SYMBOLS (block, iter, sym)
+      block = block_for_pc (pc);
+      if (block == NULL)
 	{
-	  if (SYMBOL_IS_ARGUMENT (sym)
-	      ? type == 'A'	/* collecting Arguments */
-	      : type == 'L')	/* collecting Locals */
-	    {
-	      count++;
-	      collect_symbol (collect, sym, gdbarch,
-			      frame_regno, frame_offset, pc);
-	    }
+	  warning (_("Can't collect locals; "
+		     "no symbol table info available.\n"));
+	  return;
 	}
-      if (BLOCK_FUNCTION (block))
-	break;
-      else
-	block = BLOCK_SUPERBLOCK (block);
+
+      iterate_over_block_local_vars (block, do_collect_symbol, &cb_data);
+      if (cb_data.count == 0)
+	warning (_("No locals found in scope."));
+    }
+  else
+    {
+      pc = get_pc_function_start (pc);
+      block = block_for_pc (pc);
+      if (block == NULL)
+	{
+	  warning (_("Can't collect args; no symbol table info available.\n"));
+	  return;
+	}
+
+      iterate_over_block_arg_vars (block, do_collect_symbol, &cb_data);
+      if (cb_data.count == 0)
+	warning (_("No args found in scope."));
     }
-  if (count == 0)
-    warning (_("No %s found in scope."), 
-	     type == 'L' ? "locals" : "args");
 }
 
 /* worker function */
Index: src/gdb/stack.c
===================================================================
--- src.orig/gdb/stack.c	2010-03-29 01:58:22.000000000 +0100
+++ src/gdb/stack.c	2010-03-29 01:58:55.000000000 +0100
@@ -1455,17 +1455,16 @@ backtrace_full_command (char *arg, int f
 }
 
 
-/* Print the local variables of a block B active in FRAME on STREAM.
-   Return 1 if any variables were printed; 0 otherwise.  */
+/* Iterate over the local variables of a block B, calling CB with
+   CB_DATA.  */
 
-static int
-print_block_frame_locals (struct block *b, struct frame_info *frame,
-			  int num_tabs, struct ui_file *stream)
+static void
+iterate_over_block_locals (struct block *b,
+			   iterate_over_block_arg_local_vars_cb cb,
+			   void *cb_data)
 {
   struct dict_iterator iter;
   struct symbol *sym;
-  int values_printed = 0;
-  int j;
 
   ALL_BLOCK_SYMBOLS (b, iter, sym)
     {
@@ -1477,8 +1476,7 @@ print_block_frame_locals (struct block *
 	case LOC_COMPUTED:
 	  if (SYMBOL_IS_ARGUMENT (sym))
 	    break;
-	  values_printed = 1;
-	  print_variable_and_value (NULL, sym, frame, stream, 4 * num_tabs);
+	  (*cb) (SYMBOL_PRINT_NAME (sym), sym, cb_data);
 	  break;
 
 	default:
@@ -1486,8 +1484,6 @@ print_block_frame_locals (struct block *
 	  break;
 	}
     }
-
-  return values_printed;
 }
 
 
@@ -1539,39 +1535,70 @@ print_block_frame_labels (struct gdbarch
 }
 #endif
 
-/* Print on STREAM all the local variables in frame FRAME, including
-   all the blocks active in that frame at its current PC.
+/* Iterate over all the local variables in block B, including all its
+   superblocks, stopping when the top-level block is reached.  */
+
+void
+iterate_over_block_local_vars (struct block *block,
+			       iterate_over_block_arg_local_vars_cb cb,
+			       void *cb_data)
+{
+  while (block)
+    {
+      iterate_over_block_locals (block, cb, cb_data);
+      /* After handling the function's top-level block, stop.  Don't
+	 continue to its superblock, the block of per-file
+	 symbols.  */
+      if (BLOCK_FUNCTION (block))
+	break;
+      block = BLOCK_SUPERBLOCK (block);
+    }
+}
+
+struct print_variable_and_value_data
+{
+  struct frame_info *frame;
+  int num_tabs;
+  struct ui_file *stream;
+  int values_printed;
+};
 
-   Returns 1 if the job was done, or 0 if nothing was printed because
-   we have no info on the function running in FRAME.  */
+static void
+do_print_variable_and_value (const char *print_name,
+			     struct symbol *sym,
+			     void *cb_data)
+{
+  struct print_variable_and_value_data *p = cb_data;
+
+  print_variable_and_value (print_name, sym,
+			    p->frame, p->stream, p->num_tabs);
+  p->values_printed = 1;
+}
 
 static void
 print_frame_local_vars (struct frame_info *frame, int num_tabs,
 			struct ui_file *stream)
 {
-  struct block *block = get_frame_block (frame, 0);
-  int values_printed = 0;
+  struct print_variable_and_value_data cb_data;
+  struct block *block;
 
+  block = get_frame_block (frame, 0);
   if (block == 0)
     {
       fprintf_filtered (stream, "No symbol table info available.\n");
       return;
     }
 
-  while (block)
-    {
-      if (print_block_frame_locals (block, frame, num_tabs, stream))
-	values_printed = 1;
-      /* After handling the function's top-level block, stop.  Don't
-         continue to its superblock, the block of per-file symbols.
-         Also do not continue to the containing function of an inlined
-         function.  */
-      if (BLOCK_FUNCTION (block))
-	break;
-      block = BLOCK_SUPERBLOCK (block);
-    }
+  cb_data.frame = frame;
+  cb_data.num_tabs = 4 * num_tabs;
+  cb_data.stream = stream;
+  cb_data.values_printed = 0;
+
+  iterate_over_block_local_vars (block,
+				 do_print_variable_and_value,
+				 &cb_data);
 
-  if (!values_printed)
+  if (!cb_data.values_printed)
     fprintf_filtered (stream, _("No locals.\n"));
 }
 
@@ -1668,29 +1695,23 @@ catch_info (char *ignore, int from_tty)
                           0, gdb_stdout);
 }
 
-static void
-print_frame_arg_vars (struct frame_info *frame, struct ui_file *stream)
+/* Iterate over all the argument variables in block B.
+
+   Returns 1 if any argument was walked; 0 otherwise.  */
+
+void
+iterate_over_block_arg_vars (struct block *b,
+			     iterate_over_block_arg_local_vars_cb cb,
+			     void *cb_data)
 {
-  struct symbol *func = get_frame_function (frame);
-  struct block *b;
   struct dict_iterator iter;
   struct symbol *sym, *sym2;
-  int values_printed = 0;
-
-  if (func == 0)
-    {
-      fprintf_filtered (stream, _("No symbol table info available.\n"));
-      return;
-    }
 
-  b = SYMBOL_BLOCK_VALUE (func);
   ALL_BLOCK_SYMBOLS (b, iter, sym)
     {
       /* Don't worry about things which aren't arguments.  */
       if (SYMBOL_IS_ARGUMENT (sym))
 	{
-	  values_printed = 1;
-
 	  /* We have to look up the symbol because arguments can have
 	     two entries (one a parameter, one a local) and the one we
 	     want is the local, which lookup_symbol will find for us.
@@ -1704,12 +1725,33 @@ print_frame_arg_vars (struct frame_info 
 
 	  sym2 = lookup_symbol (SYMBOL_LINKAGE_NAME (sym),
 				b, VAR_DOMAIN, NULL);
-	  print_variable_and_value (SYMBOL_PRINT_NAME (sym), sym2,
-				    frame, stream, 0);
+	  (*cb) (SYMBOL_PRINT_NAME (sym), sym2, cb_data);
 	}
     }
+}
+
+static void
+print_frame_arg_vars (struct frame_info *frame, struct ui_file *stream)
+{
+  struct print_variable_and_value_data cb_data;
+  struct symbol *func;
+
+  func = get_frame_function (frame);
+  if (func == NULL)
+    {
+      fprintf_filtered (stream, _("No symbol table info available.\n"));
+      return;
+    }
+
+  cb_data.frame = frame;
+  cb_data.num_tabs = 0;
+  cb_data.stream = gdb_stdout;
+  cb_data.values_printed = 0;
+
+  iterate_over_block_arg_vars (SYMBOL_BLOCK_VALUE (func),
+			       do_print_variable_and_value, &cb_data);
 
-  if (!values_printed)
+  if (!cb_data.values_printed)
     fprintf_filtered (stream, _("No arguments.\n"));
 }
 
Index: src/gdb/stack.h
===================================================================
--- src.orig/gdb/stack.h	2010-03-29 01:58:22.000000000 +0100
+++ src/gdb/stack.h	2010-03-29 01:58:55.000000000 +0100
@@ -27,4 +27,16 @@ void select_frame_command (char *level_e
 void find_frame_funname (struct frame_info *frame, char **funname,
 			 enum language *funlang);
 
+typedef void (*iterate_over_block_arg_local_vars_cb) (const char *symbol_print_name,
+						      struct symbol *sym,
+						      void *cb_data);
+
+void iterate_over_block_arg_vars (struct block *block,
+				  iterate_over_block_arg_local_vars_cb cb,
+				  void *cb_data);
+
+void iterate_over_block_local_vars (struct block *block,
+				    iterate_over_block_arg_local_vars_cb cb,
+				    void *cb_data);
+
 #endif /* #ifndef STACK_H */
Index: src/gdb/testsuite/gdb.trace/collection.c
===================================================================
--- src.orig/gdb/testsuite/gdb.trace/collection.c	2010-03-29 01:58:22.000000000 +0100
+++ src/gdb/testsuite/gdb.trace/collection.c	2010-03-29 02:00:11.000000000 +0100
@@ -93,6 +93,7 @@ int local_test_func ()			/* test collect
   test_struct locst;
   int         locar[4];
   int         i;
+  struct localstruct {} locdefst;
 
   locst.memberc  = 15;
   locst.memberi  = 16;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]