This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
patch suggestion: conditional collect command
- To: <gdb-patches at sourceware dot cygnus dot com>
- Subject: patch suggestion: conditional collect command
- From: "Josef Ezra" <jezra at emc dot com>
- Date: Wed, 1 Nov 2000 16:35:24 -0500
- Cc: <shagam at emc dot com>, <sgordon at emc dot com>
(had some mail problems, hoping it won't be sent more then once)
This patch should allow conditional collect
expressions in tracepoints. The format is:
> collect expr2 if expr3
or
> collect expr1, expr2 if expr3, expr4 ....
in both cases, the expression expr2 will be collected
only if expr3 turned out to be true.
NOTE 1: if this patch will be accepted, the collect
command's legend should be updated.
NOTE 2: targets should protect themselves from infinite
loops.
NOTE 3: in gen_binop, I thought that pointer/integer
operations are too powerful to be disallowed,
fixme if I'm wrong.
Thanks -
Josef Ezra
*ax.h: (ax_append_const) new function
*ax-general.c: ditto
*ax-gdb.h: (gen_trace_for_expr) additional 'if' parameter
*ax-gdb.c: (require_rvalue) minor bug fixed
*ax-gdb.c: (gen_binop) allow ptr/int operation
*ax-gdb.c: (gen_expr) added compare operations (EQUAL, GTR etc.)
*ax-gdb.c: (gen_trace_for_expr) additional 'if' parameter, create
conditional trace
*ax-gdb.c: (agent_command) manipulate 'expr if expr' expresstions
*tracepoint.c: (validate_actionline) allow 'collect expr if expr' commands
*tracepoint.c: (encode_actions) ditto
*tracepoint.c: (trace_dump_command) outputing conditional traces
Index: ax-gdb.h
===================================================================
RCS file: /emc/ucode/cvsroot_0/sgdb6/gdb/ax-gdb.h,v
retrieving revision 1.1
diff -c -5 -p -r1.1 ax-gdb.h
*** ax-gdb.h 2000/09/07 16:34:30 1.1
--- ax-gdb.h 2000/10/26 21:07:55
*************** extern struct agent_expr *expr_to_addres
*** 107,114 ****
The result will use the `trace' and `trace_quick' bytecodes to
record the value of all memory touched by the expression, and leave
no values on the stack. The caller can then use the ax_reqs
function to discover which registers the expression uses. */
extern struct agent_expr *gen_trace_for_expr PARAMS ((CORE_ADDR,
! struct expression *));
#endif /* AX_GDB_H */
--- 107,123 ----
The result will use the `trace' and `trace_quick' bytecodes to
record the value of all memory touched by the expression, and leave
no values on the stack. The caller can then use the ax_reqs
function to discover which registers the expression uses. */
extern struct agent_expr *gen_trace_for_expr PARAMS ((CORE_ADDR,
! struct expression *,
! struct expression
*));
!
#endif /* AX_GDB_H */
Index: ax.h
===================================================================
RCS file: /emc/ucode/cvsroot_0/sgdb6/gdb/ax.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -c -5 -p -r1.1 -r1.2
*** ax.h 2000/09/07 16:34:30 1.1
--- ax.h 2000/10/19 13:33:25 1.2
*************** extern int ax_goto PARAMS ((struct agent
*** 174,183 ****
--- 180,193 ----
extern void ax_label PARAMS ((struct agent_expr * EXPR, int patch, int
target));
/* Assemble code to push a constant on the stack. */
extern void ax_const_l PARAMS ((struct agent_expr * EXPR, LONGEST l));
extern void ax_const_d PARAMS ((struct agent_expr * EXPR, LONGEST d));
+
+
+ /* just add n low bytes of val to expression chain - jezra EMC */
+ extern void ax_append_const PARAMS ((struct agent_expr * x, unsigned long
val, int n));
/* Assemble code to push the value of register number REG on the
stack. */
extern void ax_reg PARAMS ((struct agent_expr * EXPR, int REG));
Index: ax-gdb.c
===================================================================
RCS file: /emc/ucode/cvsroot_0/sgdb6/gdb/ax-gdb.c,v
retrieving revision 1.1
diff -c -5 -p -r1.1 ax-gdb.c
*** ax-gdb.c 2000/09/07 16:34:30 1.1
--- ax-gdb.c 2000/11/01 15:27:06
*************** require_rvalue (ax, value)
*** 697,707 ****
/* It's already an rvalue. */
break;
case axs_lvalue_memory:
/* The top of stack is the address of the object. Dereference. */
! gen_fetch (ax, value->type);
break;
case axs_lvalue_register:
/* There's nothing on the stack, but value->u.reg is the
register number containing the value.
--- 697,707 ----
/* It's already an rvalue. */
break;
case axs_lvalue_memory:
/* The top of stack is the address of the object. Dereference. */
! gen_fetch (ax, CHECK_TYPEDEF( value->type ));
break;
case axs_lvalue_register:
/* There's nothing on the stack, but value->u.reg is the
register number containing the value.
*************** gen_binop (ax, value, value1, value2, op
*** 1106,1117 ****
enum agent_op op, op_unsigned;
int may_carry;
char *name;
{
/* We only handle INT op INT. */
! if ((value1->type->code != TYPE_CODE_INT)
! || (value2->type->code != TYPE_CODE_INT))
error ("Illegal combination of types in %s.", name);
ax_simple (ax,
TYPE_UNSIGNED (value1->type) ? op_unsigned : op);
if (may_carry)
--- 1106,1120 ----
enum agent_op op, op_unsigned;
int may_carry;
char *name;
{
/* We only handle INT op INT. */
! /* FIXME: mmm.., ptr/int operations are too powerful to be disabled */
! if (((value1->type->code != TYPE_CODE_INT) &&
! (value1->type->code != TYPE_CODE_PTR)) ||
! ((value2->type->code != TYPE_CODE_INT) &&
! (value2->type->code != TYPE_CODE_PTR)))
error ("Illegal combination of types in %s.", name);
ax_simple (ax,
TYPE_UNSIGNED (value1->type) ? op_unsigned : op);
if (may_carry)
*************** gen_expr (pc, ax, value)
*** 1565,1574 ****
--- 1569,1586 ----
}
/* Otherwise, go ahead and generate code for it. */
switch (op)
{
+ /* Binary Comparation operators */
+ case BINOP_EQUAL: /* == */
+ case BINOP_NOTEQUAL: /* != */
+ case BINOP_LESS: /* < */
+ case BINOP_GTR: /* > */
+ case BINOP_LEQ: /* <= */
+ case BINOP_GEQ: /* >= */
+
/* Binary arithmetic operators. */
case BINOP_ADD:
case BINOP_SUB:
case BINOP_MUL:
case BINOP_DIV:
*************** gen_expr (pc, ax, value)
*** 1583,1592 ****
--- 1595,1627 ----
gen_expr (pc, ax, &value2);
gen_usual_unary (ax, &value2);
gen_usual_arithmetic (ax, &value1, &value2);
switch (op)
{
+ case BINOP_EQUAL: /* == */
+ gen_binop (ax, value, &value1, &value2,
+ aop_equal, aop_equal, 0, "isequal");
+ break;
+ case BINOP_NOTEQUAL: /* != */
+ gen_binop (ax, value, &value1, &value2,
+ aop_equal, aop_equal, 0, "isequal");
+ ax_simple (ax, aop_log_not);
+ break;
+ case BINOP_GTR: /* > */
+ ax_simple (ax, aop_swap);
+ case BINOP_LESS: /* < */
+ gen_binop (ax, value, &value1, &value2,
+ aop_less_signed, aop_less_unsigned, 1, "isless");
+ break;
+ case BINOP_LEQ: /* <= */
+ ax_simple (ax, aop_swap);
+ case BINOP_GEQ: /* >= */
+ gen_binop (ax, value, &value1, &value2,
+ aop_less_signed, aop_less_unsigned, 1, "isless");
+ ax_simple (ax, aop_log_not);
+ break;
+
case BINOP_ADD:
gen_add (ax, value, &value1, &value2, "addition");
break;
case BINOP_SUB:
gen_sub (ax, value, &value1, &value2);
*************** expr_to_address_and_size (expr)
*** 1843,1865 ****
The result will use the `trace' and `trace_quick' bytecodes to
record the value of all memory touched by the expression. The
caller can then use the ax_reqs function to discover which
registers it relies upon. */
struct agent_expr *
! gen_trace_for_expr (scope, expr)
CORE_ADDR scope;
struct expression *expr;
{
struct cleanup *old_chain = 0;
struct agent_expr *ax = new_agent_expr (scope);
union exp_element *pc;
struct axs_value value;
old_chain = make_cleanup ((make_cleanup_func) free_agent_expr, ax);
- pc = expr->elts;
trace_kludge = 1;
gen_expr (&pc, ax, &value);
/* Make sure we record the final object, and get rid of it. */
gen_traced_pop (ax, &value);
--- 1878,1912 ----
The result will use the `trace' and `trace_quick' bytecodes to
record the value of all memory touched by the expression. The
caller can then use the ax_reqs function to discover which
registers it relies upon. */
struct agent_expr *
! gen_trace_for_expr (scope, expr, ifexpr)
CORE_ADDR scope;
struct expression *expr;
+ struct expression *ifexpr;
{
struct cleanup *old_chain = 0;
struct agent_expr *ax = new_agent_expr (scope);
union exp_element *pc;
struct axs_value value;
old_chain = make_cleanup ((make_cleanup_func) free_agent_expr, ax);
trace_kludge = 1;
+ if (ifexpr != NULL)
+ {
+ pc = ifexpr->elts;
+ gen_expr (&pc, ax, &value) ;
+ require_rvalue (ax, &value) ;
+ ax_simple (ax, aop_if_goto) ;
+ ax_append_const (ax, (ax->len + 3), 2);
+ ax_simple (ax, aop_end) ;
+ /* >>==========>>
+ condition_expr, if_goto, end, collection_expr */
+ }
+ pc = expr->elts;
gen_expr (&pc, ax, &value);
/* Make sure we record the final object, and get rid of it. */
gen_traced_pop (ax, &value);
*************** agent_command (exp, from_tty)
*** 1909,1918 ****
--- 2019,2030 ----
{
struct cleanup *old_chain = 0;
struct expression *expr;
struct agent_expr *agent;
struct frame_info *fi = get_current_frame (); /* need current scope */
+ struct expression *ifexpr = NULL;
+ char *ifexp ;
/* We don't deal with overlay debugging at the moment. We need to
think more carefully about this. If you copy this code into
another command, change the error message; the user shouldn't
have to know anything about agent expressions. */
*************** agent_command (exp, from_tty)
*** 1920,1932 ****
error ("GDB can't do agent expression translation with overlays.");
if (exp == 0)
error_no_arg ("expression to translate");
expr = parse_expression (exp);
old_chain = make_cleanup ((make_cleanup_func) free_current_contents,
&expr);
! agent = gen_trace_for_expr (fi->pc, expr);
make_cleanup ((make_cleanup_func) free_agent_expr, agent);
ax_print (gdb_stdout, agent);
/* It would be nice to call ax_reqs here to gather some general info
about the expression, and then print out the result. */
--- 2032,2052 ----
error ("GDB can't do agent expression translation with overlays.");
if (exp == 0)
error_no_arg ("expression to translate");
+ if ((ifexp = strstr (exp, " if ")) != NULL) /* is it an if command?
*/
+ {
+ ifexpr = parse_expression (ifexp + 4);
+ *ifexp = '\0';
+ }
expr = parse_expression (exp);
old_chain = make_cleanup ((make_cleanup_func) free_current_contents,
&expr);
! if (ifexpr)
! old_chain = make_cleanup ((make_cleanup_func) free_current_contents,
&ifexpr);
!
! agent = gen_trace_for_expr (fi->pc, expr, ifexpr);
make_cleanup ((make_cleanup_func) free_agent_expr, agent);
ax_print (gdb_stdout, agent);
/* It would be nice to call ax_reqs here to gather some general info
about the expression, and then print out the result. */
Index: ax-general.c
===================================================================
RCS file: /emc/ucode/cvsroot_0/sgdb6/gdb/ax-general.c,v
retrieving revision 1.1
diff -c -5 -p -r1.1 ax-general.c
*** ax-general.c 2000/09/07 16:34:30 1.1
--- ax-general.c 2000/11/01 14:28:05
*************** grow_expr (x, n)
*** 78,87 ****
--- 78,96 ----
x->buf = xrealloc (x->buf, x->size);
}
}
+ void
+ ax_append_const (x, val, n)
+ struct agent_expr *x;
+ unsigned long val;
+ int n;
+ {
+ append_const (x, (LONGEST) val, n);
+ }
+
/* Append the low N bytes of VAL as an N-byte integer to the
expression X, in big-endian order. */
static void
append_const (x, val, n)
struct agent_expr *x;
Index: tracepoint.c
===================================================================
RCS file: /emc/ucode/cvsroot_0/sgdb6/gdb/tracepoint.c,v
retrieving revision 1.1
diff -c -5 -p -r1.1 tracepoint.c
*** tracepoint.c 2000/09/07 16:35:13 1.1
--- tracepoint.c 2000/11/01 16:59:41
*************** validate_actionline (line, t)
*** 932,942 ****
--- 995,1007 ----
char **line;
struct tracepoint *t;
{
struct cmd_list_element *c;
struct expression *exp = NULL;
+ struct expression *ifexp = NULL;
struct cleanup *old_chain = NULL;
+
char *p;
for (p = *line; isspace ((int) *p);)
p++;
*************** validate_actionline (line, t)
*** 967,986 ****
if (*p == '$') /* look for special pseudo-symbols */
{
if ((0 == strncasecmp ("reg", p + 1, 3)) ||
(0 == strncasecmp ("arg", p + 1, 3)) ||
! (0 == strncasecmp ("loc", p + 1, 3)))
{
p = strchr (p, ',');
continue;
}
/* else fall thru, treat p as an expression and parse it! */
}
exp = parse_exp_1 (&p, block_for_pc (t->address), 1);
old_chain = make_cleanup ((make_cleanup_func) free_current_contents,
&exp);
if (exp->elts[0].opcode == OP_VAR_VALUE)
{
if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_CONST)
{
--- 1032,1100 ----
if (*p == '$') /* look for special pseudo-symbols */
{
if ((0 == strncasecmp ("reg", p + 1, 3)) ||
(0 == strncasecmp ("arg", p + 1, 3)) ||
! (0 == strncasecmp ("loc", p + 1, 3)))
{
p = strchr (p, ',');
continue;
}
/* else fall thru, treat p as an expression and parse it! */
}
exp = parse_exp_1 (&p, block_for_pc (t->address), 1);
+ if (*p)
+ {
+ while (isspace ((int) *p)) p ++;
+ if ( p[0] == 'i' &&
+ p[1] == 'f' &&
+ p[2] == ' ')
+ { /* this is an if
command */
+ p += 3;
+ ifexp = parse_exp_1 (&p, block_for_pc (t->address), 1);
+ }
+ }
+
old_chain = make_cleanup ((make_cleanup_func) free_current_contents,
&exp);
+ if (ifexp)
+ old_chain = make_cleanup ((make_cleanup_func)
free_current_contents,
+ &ifexp);
if (exp->elts[0].opcode == OP_VAR_VALUE)
{
if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_CONST)
{
*************** validate_actionline (line, t)
*** 997,1007 ****
}
}
/* we have something to collect, make sure that the expr to
bytecode translator can handle it and that it's not too long */
! aexpr = gen_trace_for_expr (t->address, exp);
(void) make_cleanup ((make_cleanup_func) free_agent_expr, aexpr);
if (aexpr->len > MAX_AGENT_EXPR_LEN)
error ("expression too complicated, try simplifying");
--- 1111,1121 ----
}
}
/* we have something to collect, make sure that the expr to
bytecode translator can handle it and that it's not too long */
! aexpr = gen_trace_for_expr (t->address, exp, ifexp);
(void) make_cleanup ((make_cleanup_func) free_agent_expr, aexpr);
if (aexpr->len > MAX_AGENT_EXPR_LEN)
error ("expression too complicated, try simplifying");
*************** encode_actions (t, tdp_actions, stepping
*** 1514,1532 ****
char ***stepping_actions;
{
static char tdp_buff[2048], step_buff[2048];
char *action_exp;
struct expression *exp = NULL;
struct action_line *action;
int i;
value_ptr tempval;
struct collection_list *collect;
struct cmd_list_element *cmd;
struct agent_expr *aexpr;
long frame_reg, frame_offset;
-
clear_collection_list (&tracepoint_list);
clear_collection_list (&stepping_list);
collect = &tracepoint_list;
*tdp_actions = NULL;
--- 1629,1647 ----
char ***stepping_actions;
{
static char tdp_buff[2048], step_buff[2048];
char *action_exp;
struct expression *exp = NULL;
+ struct expression *ifexp = NULL;
struct action_line *action;
int i;
value_ptr tempval;
struct collection_list *collect;
struct cmd_list_element *cmd;
struct agent_expr *aexpr;
long frame_reg, frame_offset;
clear_collection_list (&tracepoint_list);
clear_collection_list (&stepping_list);
collect = &tracepoint_list;
*tdp_actions = NULL;
*************** encode_actions (t, tdp_actions, stepping
*** 1540,1550 ****
action_exp = action->action;
while (isspace ((int) *action_exp))
action_exp++;
if (*action_exp == '#') /* comment line */
! return;
cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
if (cmd == 0)
error ("Bad action list item: %s", action_exp);
--- 1655,1665 ----
action_exp = action->action;
while (isspace ((int) *action_exp))
action_exp++;
if (*action_exp == '#') /* comment line */
! continue ;
cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
if (cmd == 0)
error ("Bad action list item: %s", action_exp);
*************** encode_actions (t, tdp_actions, stepping
*** 1582,1625 ****
}
else
{
unsigned long addr, len;
struct cleanup *old_chain = NULL;
! struct cleanup *old_chain1 = NULL;
struct agent_reqs areqs;
!
exp = parse_exp_1 (&action_exp, block_for_pc (t->address), 1);
old_chain = make_cleanup ((make_cleanup_func)
free_current_contents, &exp);
! switch (exp->elts[0].opcode)
! {
! case OP_REGISTER:
i = exp->elts[1].longconst;
if (info_verbose)
printf_filtered ("OP_REGISTER: ");
add_register (collect, i);
! break;
! case UNOP_MEMVAL:
/* safe because we know it's a simple expression */
tempval = evaluate_expression (exp);
addr = VALUE_ADDRESS (tempval) + VALUE_OFFSET (tempval);
len = TYPE_LENGTH (check_typedef (exp->elts[1].type));
add_memrange (collect, -1, addr, len);
! break;
! case OP_VAR_VALUE:
collect_symbol (collect,
exp->elts[2].symbol,
frame_reg,
frame_offset);
! break;
! default: /* full-fledged expression */
! aexpr = gen_trace_for_expr (t->address, exp);
old_chain1 = make_cleanup ((make_cleanup_func)
free_agent_expr, aexpr);
ax_reqs (aexpr, &areqs);
if (areqs.flaw != agent_flaw_none)
--- 1697,1804 ----
}
else
{
unsigned long addr, len;
struct cleanup *old_chain = NULL;
! struct cleanup *old_chain1 = NULL;
struct agent_reqs areqs;
exp = parse_exp_1 (&action_exp, block_for_pc (t->address), 1);
+ if (*action_exp) /* is it
an if command? */
+ {
+ while (isspace ((int) *action_exp)) action_exp ++;
+ if ( action_exp[0] == 'i' &&
+ action_exp[1] == 'f' &&
+ action_exp[2] == ' ')
+ { /* this is
an if command */
+ action_exp += 3;
+ ifexp = parse_exp_1 (&action_exp, block_for_pc
(t->address), 1);
+ }
+ }
+
old_chain = make_cleanup ((make_cleanup_func)
free_current_contents, &exp);
+ if (ifexp)
+ old_chain = make_cleanup ((make_cleanup_func)
+ free_current_contents,
&ifexp);
! if (!ifexp && exp->elts[0].opcode == OP_REGISTER)
! {
i = exp->elts[1].longconst;
if (info_verbose)
printf_filtered ("OP_REGISTER: ");
add_register (collect, i);
! }
! else if (!ifexp && exp->elts[0].opcode == UNOP_MEMVAL)
! {
/* safe because we know it's a simple expression */
tempval = evaluate_expression (exp);
addr = VALUE_ADDRESS (tempval) + VALUE_OFFSET (tempval);
len = TYPE_LENGTH (check_typedef (exp->elts[1].type));
add_memrange (collect, -1, addr, len);
! }
! else if (!ifexp && exp->elts[0].opcode == OP_VAR_VALUE)
! {
collect_symbol (collect,
exp->elts[2].symbol,
frame_reg,
frame_offset);
! }
! else /* full-fledged expression */
! {
+ aexpr = gen_trace_for_expr (t->address, exp, ifexp);
+
old_chain1 = make_cleanup ((make_cleanup_func)
free_agent_expr, aexpr);
ax_reqs (aexpr, &areqs);
if (areqs.flaw != agent_flaw_none)
*************** encode_actions (t, tdp_actions, stepping
*** 1650,1664 ****
/* it's used -- record it */
add_register (collect, ndx1 * 8 + ndx2);
}
}
}
! break;
! } /* switch */
do_cleanups (old_chain);
! } /* do */
! }
while (action_exp && *action_exp++ == ',');
} /* if */
else if (cmd->function.cfunc == while_stepping_pseudocommand)
{
collect = &stepping_list;
--- 1829,1842 ----
/* it's used -- record it */
add_register (collect, ndx1 * 8 + ndx2);
}
}
}
! }
do_cleanups (old_chain);
! }
! } /* do */
while (action_exp && *action_exp++ == ',');
} /* if */
else if (cmd->function.cfunc == while_stepping_pseudocommand)
{
collect = &stepping_list;
*************** trace_dump_command (args, from_tty)
*** 2536,2546 ****
char *args;
int from_tty;
{
struct tracepoint *t;
struct action_line *action;
! char *action_exp, *next_comma;
struct cleanup *old_cleanups;
int stepping_actions = 0;
int stepping_frame = 0;
if (!target_is_remote ())
--- 2722,2732 ----
char *args;
int from_tty;
{
struct tracepoint *t;
struct action_line *action;
! char *action_exp, *next_comma, *ifexpr;
struct cleanup *old_cleanups;
int stepping_actions = 0;
int stepping_frame = 0;
if (!target_is_remote ())
*************** trace_dump_command (args, from_tty)
*** 2627,2639 ****
--- 2814,2858 ----
if (next_comma)
{
make_cleanup (replace_comma, next_comma);
*next_comma = '\0';
}
+ /* always try to show conditional traces
*/
+ if ((ifexpr = strstr (action_exp, " if ")) != NULL)
+ *ifexpr = '\0' ;
printf_filtered ("%s = ", action_exp);
output_command (action_exp, from_tty);
printf_filtered ("\n");
+ if (ifexpr != NULL)
+ *ifexpr = ' ' ;
}
if (next_comma)
*next_comma = ',';
action_exp = next_comma;
}