This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH] Handle LOC_COMPUTED variables in tracepoint actions
- From: Stan Shebs <stan at codesourcery dot com>
- To: gdb-patches <gdb-patches at sourceware dot org>
- Date: Fri, 18 Dec 2009 11:46:10 -0800
- Subject: [PATCH] Handle LOC_COMPUTED variables in tracepoint actions
The last time that anybody used tracepoints much, stabs was still the
norm and Dwarf 2 the newbie, and so nobody thought much about handling
variables with computed locations. Nowadays many local variables have
computed locations, and we have to generate appropriate agent expression
bytecodes. Worse, the top-level encoding machinery for tracepoint
actions will issue instructions to collect variables directly, not using
bytecodes, so we need to detect when bytecodes are necessary. (In
theory we could always generate bytecodes for collection expressions;
that would make a good cleanup for later.)
This patch doesn't handle every possible computed location, that's a big
project of its own (basically translating arbitrary dwarf2 bytecode
sequences into equivalent agent expression bytecodes), it just handles
frame/base register combinations that are typical for local vars. Even
the simplified version is a little arcane, so I'll leave it up for
comments for a few days before committing.
Stan
2009-12-18 Stan Shebs <stan@codesourcery.com>
* ax-gdb.h (gen_trace_for_var): Declare.
* ax-gdb.c (gen_trace_for_var): New function.
* dwarf2loc.c (dwarf_expr_frame_base_1): New function, split from...
(dwarf_expr_frame_base): ...here.
(dwarf2_tracepoint_var_ref): Add computed location case.
* tracepoint.c (collect_symbol): Add scope arg and LOC_COMPUTED
case.
(add_local_symbols): Update call to collect_symbol.
(encode_actions): Ditto.
Index: ax-gdb.c
===================================================================
RCS file: /cvs/src/src/gdb/ax-gdb.c,v
retrieving revision 1.53
diff -p -r1.53 ax-gdb.c
*** ax-gdb.c 14 Jul 2009 21:40:30 -0000 1.53
--- ax-gdb.c 18 Dec 2009 19:27:46 -0000
*************** gen_expr (struct expression *exp, union
*** 1768,1773 ****
--- 1768,1797 ----
}
+ struct agent_expr *
+ gen_trace_for_var (CORE_ADDR scope, struct symbol *var)
+ {
+ struct cleanup *old_chain = 0;
+ struct agent_expr *ax = new_agent_expr (scope);
+ struct axs_value value;
+
+ old_chain = make_cleanup_free_agent_expr (ax);
+
+ trace_kludge = 1;
+ gen_var_ref (NULL, ax, &value, var);
+
+ /* Make sure we record the final object, and get rid of it. */
+ gen_traced_pop (ax, &value);
+
+ /* Oh, and terminate. */
+ ax_simple (ax, aop_end);
+
+ /* We have successfully built the agent expr, so cancel the cleanup
+ request. If we add more cleanups that we always want done, this
+ will have to get more complicated. */
+ discard_cleanups (old_chain);
+ return ax;
+ }
/* Generating bytecode from GDB expressions: driver */
Index: ax-gdb.h
===================================================================
RCS file: /cvs/src/src/gdb/ax-gdb.h,v
retrieving revision 1.12
diff -p -r1.12 ax-gdb.h
*** ax-gdb.h 14 Jul 2009 21:40:30 -0000 1.12
--- ax-gdb.h 18 Dec 2009 19:27:46 -0000
*************** struct axs_value
*** 99,104 ****
--- 99,106 ----
function to discover which registers the expression uses. */
extern struct agent_expr *gen_trace_for_expr (CORE_ADDR, struct expression *);
+ extern struct agent_expr *gen_trace_for_var (CORE_ADDR, struct symbol *);
+
extern struct agent_expr *gen_eval_for_expr (CORE_ADDR, struct expression *);
#endif /* AX_GDB_H */
Index: dwarf2loc.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2loc.c,v
retrieving revision 1.68
diff -p -r1.68 dwarf2loc.c
*** dwarf2loc.c 15 Sep 2009 16:20:53 -0000 1.68
--- dwarf2loc.c 18 Dec 2009 19:27:46 -0000
***************
*** 41,46 ****
--- 41,50 ----
#include "gdb_string.h"
#include "gdb_assert.h"
+ static void
+ dwarf_expr_frame_base_1 (struct symbol *framefunc, CORE_ADDR pc,
+ gdb_byte **start, size_t * length);
+
/* A helper function for dealing with location lists. Given a
symbol baton (BATON) and a pc value (PC), find the appropriate
location expression, set *LOCEXPR_LENGTH, and return a pointer
*************** dwarf_expr_frame_base (void *baton, gdb_
*** 166,181 ****
something has gone wrong. */
gdb_assert (framefunc != NULL);
if (SYMBOL_LOCATION_BATON (framefunc) == NULL)
*start = NULL;
else if (SYMBOL_COMPUTED_OPS (framefunc) == &dwarf2_loclist_funcs)
{
struct dwarf2_loclist_baton *symbaton;
- struct frame_info *frame = debaton->frame;
symbaton = SYMBOL_LOCATION_BATON (framefunc);
! *start = find_location_expression (symbaton, length,
! get_frame_address_in_block (frame));
}
else
{
--- 170,192 ----
something has gone wrong. */
gdb_assert (framefunc != NULL);
+ dwarf_expr_frame_base_1 (framefunc,
+ get_frame_address_in_block (debaton->frame),
+ start, length);
+ }
+
+ static void
+ dwarf_expr_frame_base_1 (struct symbol *framefunc, CORE_ADDR pc,
+ gdb_byte **start, size_t * length)
+ {
if (SYMBOL_LOCATION_BATON (framefunc) == NULL)
*start = NULL;
else if (SYMBOL_COMPUTED_OPS (framefunc) == &dwarf2_loclist_funcs)
{
struct dwarf2_loclist_baton *symbaton;
symbaton = SYMBOL_LOCATION_BATON (framefunc);
! *start = find_location_expression (symbaton, length, pc);
}
else
{
*************** dwarf2_tracepoint_var_ref (struct symbol
*** 617,637 ****
}
else if (data[0] == DW_OP_fbreg)
{
! /* And this is worse than just minimal; we should honor the frame base
! as above. */
! int frame_reg;
LONGEST frame_offset;
gdb_byte *buf_end;
buf_end = read_sleb128 (data + 1, data + size, &frame_offset);
if (buf_end != data + size)
error (_("Unexpected opcode after DW_OP_fbreg for symbol \"%s\"."),
SYMBOL_PRINT_NAME (symbol));
- gdbarch_virtual_frame_pointer (gdbarch,
- ax->scope, &frame_reg, &frame_offset);
ax_reg (ax, frame_reg);
! ax_const_l (ax, frame_offset);
ax_simple (ax, aop_add);
value->kind = axs_lvalue_memory;
--- 628,679 ----
}
else if (data[0] == DW_OP_fbreg)
{
! struct block *b;
! struct symbol *framefunc;
! int frame_reg = 0;
LONGEST frame_offset;
gdb_byte *buf_end;
+ gdb_byte *base_data;
+ size_t base_size;
+ LONGEST base_offset = 0;
+
+ b = block_for_pc (ax->scope);
+
+ if (!b)
+ error (_("No block found for address"));
+
+ framefunc = block_linkage_function (b);
+
+ if (!framefunc)
+ error (_("No function found for block"));
+
+ dwarf_expr_frame_base_1 (framefunc, ax->scope,
+ &base_data, &base_size);
+
+ if (base_data[0] >= DW_OP_breg0
+ && base_data[0] <= DW_OP_breg31)
+ {
+ frame_reg = base_data[0] - DW_OP_breg0;
+ buf_end = read_sleb128 (base_data + 1, base_data + base_size, &base_offset);
+ if (buf_end != base_data + base_size)
+ error (_("Unexpected opcode after DW_OP_breg%u for symbol \"%s\"."),
+ frame_reg, SYMBOL_PRINT_NAME (symbol));
+ }
+ else
+ {
+ /* We don't know what to do with the frame base expression,
+ so we can't trace this variable; give up. */
+ error (_("Cannot generate expression to collect symbol \"%s\"."),
+ SYMBOL_PRINT_NAME (symbol));
+ }
buf_end = read_sleb128 (data + 1, data + size, &frame_offset);
if (buf_end != data + size)
error (_("Unexpected opcode after DW_OP_fbreg for symbol \"%s\"."),
SYMBOL_PRINT_NAME (symbol));
ax_reg (ax, frame_reg);
! ax_const_l (ax, base_offset + frame_offset);
ax_simple (ax, aop_add);
value->kind = axs_lvalue_memory;
Index: tracepoint.c
===================================================================
RCS file: /cvs/src/src/gdb/tracepoint.c,v
retrieving revision 1.126
diff -p -r1.126 tracepoint.c
*** tracepoint.c 14 Jul 2009 21:40:30 -0000 1.126
--- tracepoint.c 18 Dec 2009 19:27:46 -0000
*************** static void
*** 725,731 ****
collect_symbol (struct collection_list *collect,
struct symbol *sym,
struct gdbarch *gdbarch,
! long frame_regno, long frame_offset)
{
unsigned long len;
unsigned int reg;
--- 725,732 ----
collect_symbol (struct collection_list *collect,
struct symbol *sym,
struct gdbarch *gdbarch,
! long frame_regno, long frame_offset,
! CORE_ADDR scope)
{
unsigned long len;
unsigned int reg;
*************** collect_symbol (struct collection_list *
*** 817,822 ****
--- 818,867 ----
printf_filtered ("%s has been optimized out of existence.\n",
SYMBOL_PRINT_NAME (sym));
break;
+
+ case LOC_COMPUTED:
+ {
+ struct agent_expr *aexpr;
+ struct cleanup *old_chain1 = NULL;
+ struct agent_reqs areqs;
+
+ aexpr = gen_trace_for_var (scope, sym);
+
+ old_chain1 = make_cleanup_free_agent_expr (aexpr);
+
+ ax_reqs (aexpr, &areqs);
+ if (areqs.flaw != agent_flaw_none)
+ error (_("malformed expression"));
+
+ if (areqs.min_height < 0)
+ error (_("gdb: Internal error: expression has min height < 0"));
+ if (areqs.max_height > 20)
+ error (_("expression too complicated, try simplifying"));
+
+ discard_cleanups (old_chain1);
+ add_aexpr (collect, aexpr);
+
+ /* take care of the registers */
+ if (areqs.reg_mask_len > 0)
+ {
+ int ndx1, ndx2;
+
+ for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++)
+ {
+ QUIT; /* allow user to bail out with ^C */
+ if (areqs.reg_mask[ndx1] != 0)
+ {
+ /* assume chars have 8 bits */
+ for (ndx2 = 0; ndx2 < 8; ndx2++)
+ if (areqs.reg_mask[ndx1] & (1 << ndx2))
+ /* it's used -- record it */
+ add_register (collect,
+ ndx1 * 8 + ndx2);
+ }
+ }
+ }
+ }
+ break;
}
}
*************** add_local_symbols (struct collection_lis
*** 843,849 ****
{
count++;
collect_symbol (collect, sym, gdbarch,
! frame_regno, frame_offset);
}
}
if (BLOCK_FUNCTION (block))
--- 888,894 ----
{
count++;
collect_symbol (collect, sym, gdbarch,
! frame_regno, frame_offset, pc);
}
}
if (BLOCK_FUNCTION (block))
*************** encode_actions (struct breakpoint *t, ch
*** 1122,1128 ****
exp->elts[2].symbol,
t->gdbarch,
frame_reg,
! frame_offset);
break;
default: /* full-fledged expression */
--- 1167,1174 ----
exp->elts[2].symbol,
t->gdbarch,
frame_reg,
! frame_offset,
! t->loc->address);
break;
default: /* full-fledged expression */