This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
fix "collect $locals" bitrot
- From: Pedro Alves <pedro at codesourcery dot com>
- To: gdb-patches at sourceware dot org
- Date: Mon, 29 Mar 2010 02:19:06 +0100
- Subject: 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;