* [PATCH] Trace state variables
@ 2009-12-15 13:51 Stan Shebs
2009-12-15 15:53 ` Eli Zaretskii
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Stan Shebs @ 2009-12-15 13:51 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 2622 bytes --]
One of our tracepoint enhancements is to add the notion of a "trace
state variable", which is a GDB-defined piece of data managed by the
tracepoint agent on the target; one could think of it as a target-side
convenience variable. You can both read and write from it, so you could
have a tracepoint action that says "collect $foo = $foo + 1" (for the
quick thinkers, yes, there is a no-collect action coming in a future
patch), and then a condition on a different tracepoint that only
triggers when $foo > 1000 . In keeping with their convenience-like
nature, they are introduced with a dollar sign, but you have to declare
them with the tvariable command, and to keep the target side simple,
they are always 64-bit signed integers.
This patch introduces the basic data structures and commands to create,
list, and delete. Pedro's upcoming gdbserver patches will support
tsv's, so you will be able to see how the target side works with them
(not too complicated, they're just indexed by small integers). Since
internalvar handling has changed recently, I've left off the value.c bit
to make "print $foo" work. And for the purists, yes, the tracepoint.c
changes include raw protocol usage, the patch to migrate tracepoint
operations to the target vector is still in the pipeline.
Comments appreciated, I expect to commit in a week or so.
Stan
2009-12-15 Stan Shebs <stan@codesourcery.com>
Add trace state variables.
* ax.h (enum agent_op): Add getv, setv, and tracev.
(ax_tsv): Declare.
* ax-gdb.c: Include tracepoint.h.
(gen_expr): Handle BINOP_ASSIGN and OP_INTERNALVAR.
* ax-general.c (ax_tsv): New function.
(aop_map): Add new bytecodes.
* tracepoint.h (struct trace_state_variable): New struct.
(tsv_s): New typedef.
(find_trace_state_variable): Declare.
* tracepoint.c (tvariables): New global.
(next_tsv_number): New global.
(create_trace_state_variable): New function.
(find_trace_state_variable): New function.
(delete_trace_state_variable): New function.
(trace_variable_command): New function.
(delete_trace_variable_command): New function.
(tvariables_info): New function.
(trace_start_command): Download tsvs with initial values.
(_initialize_tracepoint): Add new commands.
doc:
* gdb.texinfo (Trace State Variables): New section.
(Tracepoint Packets): Describe trace state variable packets.
* agentexpr.texi (Bytecode Descriptions): Describe trace state
variable bytecodes.
testsuite:
* gdb.trace/tsv.exp: New file.
* gdb.base/completion.exp: Update ambiguous info output.
[-- Attachment #2: tsv-patch-1 --]
[-- Type: text/plain, Size: 30565 bytes --]
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 15 Dec 2009 13:28:33 -0000
***************
*** 35,40 ****
--- 35,41 ----
#include "regcache.h"
#include "user-regs.h"
#include "language.h"
+ #include "tracepoint.h"
/* To make sense of this file, you should read doc/agentexpr.texi.
Then look at the types and enums in ax-gdb.h. For the code itself,
*************** gen_expr (struct expression *exp, union
*** 1592,1597 ****
--- 1593,1620 ----
}
break;
+ case BINOP_ASSIGN:
+ (*pc)++;
+ if ((*pc)[0].opcode == OP_INTERNALVAR)
+ {
+ char *name = internalvar_name ((*pc)[1].internalvar);
+ struct trace_state_variable *tsv;
+ (*pc) += 3;
+ gen_expr (exp, pc, ax, value);
+ tsv = find_trace_state_variable (name);
+ if (tsv)
+ {
+ ax_tsv (ax, aop_setv, tsv->number);
+ if (trace_kludge)
+ ax_tsv (ax, aop_tracev, tsv->number);
+ }
+ else
+ error (_("$%s is not a trace state variable, may not assign to it"), name);
+ }
+ else
+ error (_("May only assign to trace state variables"));
+ break;
+
/* Note that we need to be a little subtle about generating code
for comma. In C, we can do some optimizations here because
we know the left operand is only being evaluated for effect.
*************** gen_expr (struct expression *exp, union
*** 1643,1649 ****
break;
case OP_INTERNALVAR:
! error (_("GDB agent expressions cannot use convenience variables."));
/* Weirdo operator: see comments for gen_repeat for details. */
case BINOP_REPEAT:
--- 1666,1689 ----
break;
case OP_INTERNALVAR:
! {
! const char *name = internalvar_name ((*pc)[1].internalvar);
! struct trace_state_variable *tsv;
! (*pc) += 3;
! tsv = find_trace_state_variable (name);
! if (tsv)
! {
! ax_tsv (ax, aop_getv, tsv->number);
! if (trace_kludge)
! ax_tsv (ax, aop_tracev, tsv->number);
! /* Trace state variables are always 64-bit integers. */
! value->kind = axs_rvalue;
! value->type = builtin_type (exp->gdbarch)->builtin_long_long;
! }
! else
! error (_("$%s is not a trace state variable; GDB agent expressions cannot use convenience variables."), name);
! }
! break;
/* Weirdo operator: see comments for gen_repeat for details. */
case BINOP_REPEAT:
Index: ax-general.c
===================================================================
RCS file: /cvs/src/src/gdb/ax-general.c,v
retrieving revision 1.15
diff -p -r1.15 ax-general.c
*** ax-general.c 3 Jan 2009 05:57:50 -0000 1.15
--- ax-general.c 15 Dec 2009 13:28:33 -0000
*************** ax_reg (struct agent_expr *x, int reg)
*** 272,277 ****
--- 272,293 ----
x->buf[x->len + 2] = (reg) & 0xff;
x->len += 3;
}
+
+ /* Assemble code to operate on a trace state variable. */
+
+ void
+ ax_tsv (struct agent_expr *x, enum agent_op op, int num)
+ {
+ /* Make sure the tsv number is in range. */
+ if (num < 0 || num > 0xffff)
+ error (_("GDB bug: ax-general.c (ax_tsv): variable number out of range"));
+
+ grow_expr (x, 3);
+ x->buf[x->len] = op;
+ x->buf[x->len + 1] = (num >> 8) & 0xff;
+ x->buf[x->len + 2] = (num) & 0xff;
+ x->len += 3;
+ }
\f
*************** struct aop_map aop_map[] =
*** 324,332 ****
{"pop", 0, 0, 1, 0}, /* 0x29 */
{"zero_ext", 1, 0, 1, 1}, /* 0x2a */
{"swap", 0, 0, 2, 2}, /* 0x2b */
! {0, 0, 0, 0, 0}, /* 0x2c */
! {0, 0, 0, 0, 0}, /* 0x2d */
! {0, 0, 0, 0, 0}, /* 0x2e */
{0, 0, 0, 0, 0}, /* 0x2f */
{"trace16", 2, 0, 1, 1}, /* 0x30 */
};
--- 340,348 ----
{"pop", 0, 0, 1, 0}, /* 0x29 */
{"zero_ext", 1, 0, 1, 1}, /* 0x2a */
{"swap", 0, 0, 2, 2}, /* 0x2b */
! {"getv", 2, 0, 0, 1}, /* 0x2c */
! {"setv", 2, 0, 0, 1}, /* 0x2d */
! {"tracev", 2, 0, 0, 1}, /* 0x2e */
{0, 0, 0, 0, 0}, /* 0x2f */
{"trace16", 2, 0, 1, 1}, /* 0x30 */
};
Index: ax.h
===================================================================
RCS file: /cvs/src/src/gdb/ax.h,v
retrieving revision 1.10
diff -p -r1.10 ax.h
*** ax.h 3 Jan 2009 05:57:50 -0000 1.10
--- ax.h 15 Dec 2009 13:28:33 -0000
*************** enum agent_op
*** 131,136 ****
--- 131,139 ----
aop_pop = 0x29,
aop_zero_ext = 0x2a,
aop_swap = 0x2b,
+ aop_getv = 0x2c,
+ aop_setv = 0x2d,
+ aop_tracev = 0x2e,
aop_trace16 = 0x30,
aop_last
};
*************** extern void ax_const_d (struct agent_exp
*** 182,187 ****
--- 185,193 ----
/* Assemble code to push the value of register number REG on the
stack. */
extern void ax_reg (struct agent_expr *EXPR, int REG);
+
+ /* Assemble code to operate on a trace state variable. */
+ extern void ax_tsv (struct agent_expr *expr, enum agent_op op, int num);
\f
/* Functions for printing out expressions, and otherwise debugging
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 15 Dec 2009 13:28:33 -0000
***************
*** 34,39 ****
--- 34,40 ----
#include "tracepoint.h"
#include "remote.h"
extern int remote_supports_cond_tracepoints (void);
+ extern char *unpack_varlen_hex (char *buff, ULONGEST *result);
#include "linespec.h"
#include "regcache.h"
#include "completer.h"
*************** extern void output_command (char *, int)
*** 107,112 ****
--- 108,123 ----
/* ======= Important global variables: ======= */
+ /* The list of all trace state variables. We don't retain pointers to
+ any of these for any reason - API is by name or number only - so it
+ works to have a vector of objects. */
+
+ VEC(tsv_s) *tvariables;
+
+ /* The next integer to assign to a variable. */
+
+ int next_tsv_number = 1;
+
/* Number of last traceframe collected. */
static int traceframe_number;
*************** static struct symtab_and_line traceframe
*** 122,127 ****
--- 133,141 ----
/* Tracing command lists */
static struct cmd_list_element *tfindlist;
+ static char *target_buf;
+ static long target_buf_size;
+
/* ======= Important command functions: ======= */
static void trace_actions_command (char *, int);
static void trace_start_command (char *, int);
*************** set_traceframe_context (struct frame_inf
*** 270,275 ****
--- 284,483 ----
traceframe_sal.symtab->filename);
}
+ /* Create a new trace state variable with the given name. */
+
+ struct trace_state_variable *
+ create_trace_state_variable (const char *name)
+ {
+ struct trace_state_variable tsv;
+
+ memset (&tsv, 0, sizeof (tsv));
+ tsv.name = name;
+ tsv.number = next_tsv_number++;
+ return VEC_safe_push (tsv_s, tvariables, &tsv);
+ }
+
+ /* Look for a trace state variable of the given name. */
+
+ struct trace_state_variable *
+ find_trace_state_variable (const char *name)
+ {
+ struct trace_state_variable *tsv;
+ int ix;
+
+ for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
+ if (strcmp (name, tsv->name) == 0)
+ return tsv;
+
+ return NULL;
+ }
+
+ void
+ delete_trace_state_variable (const char *name)
+ {
+ struct trace_state_variable *tsv;
+ int ix;
+
+ /* Be relaxed about the special character. */
+ if (*name == '$')
+ ++name;
+
+ for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
+ if (strcmp (name, tsv->name) == 0)
+ {
+ VEC_unordered_remove (tsv_s, tvariables, ix);
+ return;
+ }
+
+ warning (_("No trace variable named \"$%s\", not deleting"), name);
+ }
+
+ /* The 'tvariable' command collects a name and optional expression to
+ evaluate into an initial value. */
+
+ void
+ trace_variable_command (char *args, int from_tty)
+ {
+ struct expression *expr;
+ struct cleanup *old_chain;
+ struct internalvar *intvar = NULL;
+ LONGEST initval = 0;
+ struct trace_state_variable *tsv;
+
+ if (!args || !*args)
+ error_no_arg (_("trace state variable name"));
+
+ /* All the possible valid arguments are expressions. */
+ expr = parse_expression (args);
+ old_chain = make_cleanup (free_current_contents, &expr);
+
+ if (expr->nelts == 0)
+ error (_("No expression?"));
+
+ /* Only allow two syntaxes; "$name" and "$name=value". */
+ if (expr->elts[0].opcode == OP_INTERNALVAR)
+ {
+ intvar = expr->elts[1].internalvar;
+ }
+ else if (expr->elts[0].opcode == BINOP_ASSIGN
+ && expr->elts[1].opcode == OP_INTERNALVAR)
+ {
+ intvar = expr->elts[2].internalvar;
+ initval = value_as_long (evaluate_subexpression_type (expr, 4));
+ }
+ else
+ error (_("Syntax must be $NAME [ = EXPR ]"));
+
+ if (!intvar)
+ error (_("No name given"));
+
+ if (strlen (internalvar_name (intvar)) <= 0)
+ error (_("Must supply a non-empty variable name"));
+
+ /* If the variable already exists, just change its initial value. */
+ tsv = find_trace_state_variable (internalvar_name (intvar));
+ if (tsv)
+ {
+ tsv->initial_value = initval;
+ printf_filtered (_("Trace state variable $%s now has initial value %s.\n"),
+ tsv->name, plongest (tsv->initial_value));
+ return;
+ }
+
+ /* Create a new variable. */
+ tsv = create_trace_state_variable (internalvar_name (intvar));
+ tsv->initial_value = initval;
+
+ printf_filtered (_("Trace state variable $%s created, with initial value %s.\n"),
+ tsv->name, plongest (tsv->initial_value));
+
+ do_cleanups (old_chain);
+ }
+
+ void
+ delete_trace_variable_command (char *args, int from_tty)
+ {
+ int i, ix;
+ char **argv;
+ struct cleanup *back_to;
+ struct trace_state_variable *tsv;
+
+ if (args == NULL)
+ {
+ if (query (_("Delete all trace state variables? ")))
+ VEC_free (tsv_s, tvariables);
+ dont_repeat ();
+ return;
+ }
+
+ argv = gdb_buildargv (args);
+ back_to = make_cleanup_freeargv (argv);
+
+ for (i = 0; argv[i] != NULL; i++)
+ {
+ delete_trace_state_variable (argv[i]);
+ }
+
+ do_cleanups (back_to);
+
+ dont_repeat ();
+ }
+
+ /* List all the trace state variables. */
+
+ static void
+ tvariables_info (char *args, int from_tty)
+ {
+ struct trace_state_variable *tsv;
+ int ix;
+ char *reply;
+ ULONGEST tval;
+
+ if (target_is_remote ())
+ {
+ char buf[20];
+
+ for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
+ {
+ /* We don't know anything about the value until we get a
+ valid packet. */
+ tsv->value_known = 0;
+ sprintf (buf, "qTV:%x", tsv->number);
+ putpkt (buf);
+ reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
+ if (reply && *reply)
+ {
+ if (*reply == 'V')
+ {
+ unpack_varlen_hex (reply + 1, &tval);
+ tsv->value = (LONGEST) tval;
+ tsv->value_known = 1;
+ }
+ /* FIXME say anything about oddball replies? */
+ }
+ }
+ }
+
+ printf_filtered (_("Name\t\t Initial\tCurrent\n"));
+
+ for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
+ {
+ printf_filtered ("$%s", tsv->name);
+ print_spaces_filtered (17 - strlen (tsv->name), gdb_stdout);
+ printf_filtered ("%s ", plongest (tsv->initial_value));
+ print_spaces_filtered (11 - strlen (plongest (tsv->initial_value)), gdb_stdout);
+ if (tsv->value_known)
+ printf_filtered (" %s", plongest (tsv->value));
+ else if (trace_running_p || traceframe_number >= 0)
+ /* The value is/was defined, but we don't have it. */
+ printf_filtered (" <unknown>");
+ else
+ /* It is not meaningful to ask about the value. */
+ printf_filtered (" <undefined>");
+ printf_filtered ("\n");
+ }
+ }
+
/* ACTIONS functions: */
/* Prototypes for action-parsing utility commands */
*************** add_aexpr (struct collection_list *colle
*** 1204,1212 ****
collect->next_aexpr_elt++;
}
- static char *target_buf;
- static long target_buf_size;
-
/* Set "transparent" memory ranges
Allow trace mechanism to treat text-like sections
--- 1412,1417 ----
*************** void download_tracepoint (struct breakpo
*** 1262,1270 ****
--- 1467,1477 ----
static void
trace_start_command (char *args, int from_tty)
{
+ char buf[2048];
VEC(breakpoint_p) *tp_vec = NULL;
int ix;
struct breakpoint *t;
+ struct trace_state_variable *tsv;
dont_repeat (); /* Like "run", dangerous to repeat accidentally. */
*************** trace_start_command (char *args, int fro
*** 1282,1287 ****
--- 1489,1507 ----
}
VEC_free (breakpoint_p, tp_vec);
+ /* Init any trace state variables that start with nonzero values. */
+
+ for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
+ {
+ if (tsv->initial_value != 0)
+ {
+ sprintf (buf, "QTDV:%x:%s",
+ tsv->number, phex ((ULONGEST) tsv->initial_value, 8));
+ putpkt (buf);
+ remote_get_noisy_reply (&target_buf, &target_buf_size);
+ }
+ }
+
/* Tell target to treat text-like sections as transparent. */
remote_set_transparent_ranges ();
/* Now insert traps and begin collecting data. */
*************** _initialize_tracepoint (void)
*** 2185,2190 ****
--- 2405,2422 ----
add_com ("tdump", class_trace, trace_dump_command,
_("Print everything collected at the current tracepoint."));
+ add_com ("tvariable", class_trace, trace_variable_command,_("\
+ Define a trace state variable."));
+
+ add_cmd ("tvariable", class_trace, delete_trace_variable_command, _("\
+ Delete one or more trace state variables.\n\
+ Arguments are the names of the variables to delete.\n\
+ If no arguments are supplied, delete all variables."), &deletelist);
+
+ add_info ("tvariables", tvariables_info, _("\
+ Status of trace state variables and their values.\n\
+ "));
+
add_prefix_cmd ("tfind", class_trace, trace_find_command, _("\
Select a trace frame;\n\
No argument means forward by one frame; '-' means backward by one frame."),
Index: tracepoint.h
===================================================================
RCS file: /cvs/src/src/gdb/tracepoint.h,v
retrieving revision 1.15
diff -p -r1.15 tracepoint.h
*** tracepoint.h 31 Mar 2009 05:08:32 -0000 1.15
--- tracepoint.h 15 Dec 2009 13:28:33 -0000
*************** enum actionline_type
*** 35,40 ****
--- 35,71 ----
STEPPING = 2
};
+ /* A trace state variable is a value managed by a target being
+ traced. A trace state variable (or tsv for short) can be accessed
+ and assigned to by tracepoint actions and conditionals, but is not
+ part of the program being traced, and it doesn't have to be
+ collected. Effectively the variables are scratch space for
+ tracepoints. */
+
+ struct trace_state_variable
+ {
+ /* The variable's name. The user has to prefix with a dollar sign,
+ but we don't store that internally. */
+ const char *name;
+
+ /* An id number assigned by GDB, and transmitted to targets. */
+ int number;
+
+ /* The initial value of a variable is a 64-bit signed integer. */
+ LONGEST initial_value;
+
+ /* 1 if the value is known, else 0. The value is known during a
+ trace run, or in tfind mode if the variable was collected into
+ the current trace frame. */
+ int value_known;
+
+ /* The value of a variable is a 64-bit signed integer. */
+ LONGEST value;
+ };
+
+ typedef struct trace_state_variable tsv_s;
+ DEF_VEC_O(tsv_s);
+
extern unsigned long trace_running_p;
/* A hook used to notify the UI of tracepoint operations. */
*************** enum actionline_type validate_actionline
*** 49,52 ****
--- 80,85 ----
extern void end_actions_pseudocommand (char *args, int from_tty);
extern void while_stepping_pseudocommand (char *args, int from_tty);
+ extern struct trace_state_variable *find_trace_state_variable (const char *name);
+
#endif /* TRACEPOINT_H */
Index: doc/agentexpr.texi
===================================================================
RCS file: /cvs/src/src/gdb/doc/agentexpr.texi,v
retrieving revision 1.9
diff -p -r1.9 agentexpr.texi
*** doc/agentexpr.texi 11 Nov 2009 15:08:50 -0000 1.9
--- doc/agentexpr.texi 15 Dec 2009 13:28:33 -0000
*************** alignment within the bytecode stream; th
*** 440,445 ****
--- 440,463 ----
16-bit on an unaligned address raises an exception, you should fetch the
register number one byte at a time.
+ @item @code{getv} (0x2c) @var{n}: @result{} @var{v}
+ Push the value of trace state variable number @var{n}, without sign
+ extension.
+
+ The variable number @var{n} is encoded as a 16-bit unsigned integer
+ immediately following the @code{getv} bytecode. It is always stored most
+ significant byte first, regardless of the target's normal endianness.
+ The variable number is not guaranteed to fall at any particular
+ alignment within the bytecode stream; thus, on machines where fetching a
+ 16-bit on an unaligned address raises an exception, you should fetch the
+ register number one byte at a time.
+
+ @item @code{setv} (0x2d) @var{n}: @result{} @var{v}
+ Set trace state variable number @var{n} to the value found on the top
+ of the stack. The stack is unchanged, so that the value is readily
+ available if the assignment is part of a larger expression. The
+ handling of @var{n} is as described for @code{getv}.
+
@item @code{trace} (0x0c): @var{addr} @var{size} @result{}
Record the contents of the @var{size} bytes at @var{addr} in a trace
buffer, for later retrieval by GDB.
*************** Identical to trace_quick, except that @v
*** 457,462 ****
--- 475,484 ----
unsigned integer, not a single byte. This should probably have been
named @code{trace_quick16}, for consistency.
+ @item @code{tracev} (0x2e) @var{n}: @result{} @var{a}
+ Record the value of trace state variable number @var{n} in the trace
+ buffer. The handling of @var{n} is as described for @code{getv}.
+
@item @code{end} (0x27): @result{}
Stop executing bytecode; the result should be the top element of the
stack. If the purpose of the expression was to compute an lvalue or a
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.648
diff -p -r1.648 gdb.texinfo
*** doc/gdb.texinfo 8 Dec 2009 14:06:02 -0000 1.648
--- doc/gdb.texinfo 15 Dec 2009 13:28:34 -0000
*************** conditions and actions.
*** 9331,9336 ****
--- 9331,9337 ----
* Enable and Disable Tracepoints::
* Tracepoint Passcounts::
* Tracepoint Conditions::
+ * Trace State Variables::
* Tracepoint Actions::
* Listing Tracepoints::
* Starting and Stopping Trace Experiments::
*************** search through.
*** 9497,9502 ****
--- 9498,9550 ----
(@value{GDBP}) @kbd{trace normal_operation if errcode > 0}
@end smallexample
+ @node Trace State Variables
+ @subsection Trace State Variables
+
+ A @dfn{trace state variable} is a special type of variable that is
+ created and managed by target-side code. The syntax is the same as
+ that for GDB's convenience variables (a string prefixed with ``$''),
+ but they are stored on the target. They must be created explicitly,
+ using a @code{tvariable} command. They are always 64-bit signed
+ integers, and always updated atomically.
+
+ Trace state variables are remembered by @value{GDBN}, and downloaded
+ to the target along with tracepoint information when the trace
+ experiment starts. There are no intrinsic limits on the number of
+ trace state variables, beyond memory limitations of the target.
+
+ Although trace state variables are managed by the target, you can use
+ them in print commands and expressions as if they were convenience
+ variables; @value{GDBN} will get the current value from the target
+ while the trace experiment is running. Trace state variables share
+ the same namespace as other ``$'' variables, which means that you
+ cannot have trace state variables with names like @code{$23} or
+ @code{$pc}, nor can you have a trace state variable and a convenience
+ variable with the same name.
+
+ @table @code
+
+ @item tvariable $@var{name} [ = @var{expression} ]
+ @kindex tvariable
+ @cindex trace state variable
+ The @code{tvariable} command creates a new trace state variable named
+ @code{$}@var{name}, and optionally gives it an initial value of
+ @var{expression}. @var{expression} is evaluated when this command is
+ entered; the result will be converted to an integer if possible,
+ otherwise @value{GDBN} will report an error. A second @code{tvariable}
+ command with the same name assigns a new value to the variable. The
+ default initial value is 0.
+
+ @item info tvariables
+ @kindex tvariables
+ List all the trace state variables along with their initial values.
+
+ @item delete tvariable @r{[} $@var{name} @dots{} @r{]}
+ Delete the given trace state variables, or all of them if no arguments
+ are specified.
+
+ @end table
+
@node Tracepoint Actions
@subsection Tracepoint Action Lists
*************** use @code{output} instead.
*** 9929,9935 ****
Here's a simple example of using these convenience variables for
stepping through all the trace snapshots and printing some of their
! data.
@smallexample
(@value{GDBP}) @b{tfind start}
--- 9977,9984 ----
Here's a simple example of using these convenience variables for
stepping through all the trace snapshots and printing some of their
! data. Note that these are not the same as trace state variables,
! which are managed by the target.
@smallexample
(@value{GDBP}) @b{tfind start}
*************** The packet was understood and carried ou
*** 29971,29976 ****
--- 30020,30033 ----
The packet was not recognized.
@end table
+ @item QTDV:@var{n}:@var{value}
+ Create a new trace state variable, number @var{n}, with an initial
+ value of @var{value}, which is a 64-bit signed integer. Both @var{n}
+ and @var{value} are encoded as hexadecimal values. @value{GDBN} has
+ the option of not using this packet for initial values of zero; the
+ target should simply create the trace state variables as they are
+ mentioned in expressions.
+
@item QTFrame:@var{n}
Select the @var{n}'th tracepoint frame from the buffer, and use the
register and memory contents recorded there to answer subsequent
*************** There is no trace experiment running.
*** 30044,30051 ****
--- 30101,30125 ----
There is a trace experiment running.
@end table
+ @item qTV:@var{var}
+ Ask the stub for the value of the trace state variable number @var{var}.
+
+ Replies:
+ @table @samp
+ @item V@var{value}
+ The value of the variable is @var{value}. This will be the current
+ value of the variable if the user is examining a running target, or a
+ saved value if the variable was collected in the trace frame that the
+ user is looking at. Note that multiple requests may result in different
+ reply values, such as for variables like @code{$trace_timestamp} that are
+ computed by the target program.
+ @item U
+ The value of the variable is unknown. This would occur, for example,
+ if the user is examining a trace frame in which the requested variable
+ was not collected.
@end table
+ @end table
@node Host I/O Packets
@section Host I/O Packets
Index: testsuite/gdb.base/completion.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/completion.exp,v
retrieving revision 1.39
diff -p -r1.39 completion.exp
*** testsuite/gdb.base/completion.exp 13 Jul 2009 19:24:18 -0000 1.39
--- testsuite/gdb.base/completion.exp 15 Dec 2009 13:28:34 -0000
*************** gdb_expect {
*** 211,217 ****
-re "^info t foo\\\x07$"\
{ send_gdb "\n"
gdb_expect {
! -re "Ambiguous info command \"t foo\": target, tasks, terminal, threads, tp, tracepoints, types\\..*$gdb_prompt $"\
{ pass "complete 'info t foo'"}
-re ".*$gdb_prompt $" { fail "complete 'info t foo'"}
timeout {fail "(timeout) complete 'info t foo'"}
--- 211,217 ----
-re "^info t foo\\\x07$"\
{ send_gdb "\n"
gdb_expect {
! -re "Ambiguous info command \"t foo\": target, tasks, terminal, threads, tp, tracepoints, tvariables, types\\..*$gdb_prompt $"\
{ pass "complete 'info t foo'"}
-re ".*$gdb_prompt $" { fail "complete 'info t foo'"}
timeout {fail "(timeout) complete 'info t foo'"}
*************** gdb_expect {
*** 227,233 ****
-re "^info t\\\x07$"\
{ send_gdb "\n"
gdb_expect {
! -re "Ambiguous info command \"t\": target, tasks, terminal, threads, tp, tracepoints, types\\..
*$gdb_prompt $"\
{ pass "complete 'info t'"}
-re ".*$gdb_prompt $" { fail "complete 'info t'"}
--- 227,233 ----
-re "^info t\\\x07$"\
{ send_gdb "\n"
gdb_expect {
! -re "Ambiguous info command \"t\": target, tasks, terminal, threads, tp, tracepoints, tvariables, types\\..
*$gdb_prompt $"\
{ pass "complete 'info t'"}
-re ".*$gdb_prompt $" { fail "complete 'info t'"}
*************** gdb_expect {
*** 245,251 ****
-re "^info t \\\x07$"\
{ send_gdb "\n"
gdb_expect {
! -re "Ambiguous info command \"t \": target, tasks, terminal, threads, tp, tracepoints, types\\..
*$gdb_prompt $"\
{ pass "complete 'info t '"}
-re ".*$gdb_prompt $" { fail "complete 'info t '"}
--- 245,251 ----
-re "^info t \\\x07$"\
{ send_gdb "\n"
gdb_expect {
! -re "Ambiguous info command \"t \": target, tasks, terminal, threads, tp, tracepoints, tvariables, types\\..
*$gdb_prompt $"\
{ pass "complete 'info t '"}
-re ".*$gdb_prompt $" { fail "complete 'info t '"}
Index: testsuite/gdb.trace/tsv.exp
===================================================================
RCS file: testsuite/gdb.trace/tsv.exp
diff -N testsuite/gdb.trace/tsv.exp
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gdb.trace/tsv.exp 15 Dec 2009 13:28:34 -0000
***************
*** 0 ****
--- 1,107 ----
+ # Copyright 2009 Free Software Foundation, Inc.
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+ # the Free Software Foundation; either version 3 of the License, or
+ # (at your option) any later version.
+ #
+ # This program is distributed in the hope that it will be useful,
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ # GNU General Public License for more details.
+ #
+ # You should have received a copy of the GNU General Public License
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ load_lib "trace-support.exp";
+
+ if $tracelevel then {
+ strace $tracelevel
+ }
+
+ set prms_id 0
+ set bug_id 0
+
+ gdb_exit
+ gdb_start
+ set testfile "actions"
+ set srcfile ${testfile}.c
+ set binfile $objdir/$subdir/tsv
+ if { [gdb_compile "$srcdir/$subdir/$srcfile" $binfile \
+ executable {debug nowarnings}] != "" } {
+ untested tracecmd.exp
+ return -1
+ }
+ gdb_reinitialize_dir $srcdir/$subdir
+
+ # If testing on a remote host, download the source file.
+ # remote_download host $srcdir/$subdir/$srcfile
+
+ gdb_file_cmd $binfile
+
+ gdb_test "tvariable \$tvar1" \
+ "Trace state variable \\\$tvar1 created, with initial value 0." \
+ "Create a trace state variable"
+
+ gdb_test "tvariable \$tvar2 = 45" \
+ "Trace state variable \\\$tvar2 created, with initial value 45." \
+ "Create a trace state variable with initial value"
+
+ gdb_test "tvariable \$tvar2 = -92" \
+ "Trace state variable \\\$tvar2 now has initial value -92." \
+ "Change initial value of a trace state variable"
+
+ gdb_test "tvariable \$tvar3 = 2 + 3" \
+ "Trace state variable \\\$tvar3 created, with initial value 5." \
+ "Create a trace state variable with expression"
+
+ gdb_test "tvariable \$tvar3 = 1234567000000" \
+ "Trace state variable \\\$tvar3 now has initial value 1234567000000." \
+ "Init trace state variable to a 64-bit value"
+
+ gdb_test "tvariable main" \
+ "Syntax must be \\\$NAME \\\[ = EXPR \\\]" \
+ "tvariable syntax error, bad name"
+
+ gdb_test "tvariable \$tvar1 - 93" \
+ "Syntax must be \\\$NAME \\\[ = EXPR \\\]" \
+ "tvariable syntax error, not an assignment"
+
+ gdb_test "info tvariables" \
+ "Name\[\t \]+Initial\[\t \]+Current.*
+ \\\$tvar1\[\t \]+0\[\t \]+<undefined>.*
+ \\\$tvar2\[\t \]+-92\[\t \]+<undefined>.*
+ \\\$tvar3\[\t \]+1234567000000\[\t \]+.*<undefined>.*" \
+ "List tvariables"
+
+ gdb_test "delete tvariable \$tvar2" \
+ "" \
+ "delete trace state variable"
+
+ gdb_test "info tvariables" \
+ "Name\[\t \]+Initial\[\t \]+Current.*
+ \\\$tvar1\[\t \]+0\[\t \]+<undefined>.*
+ \\\$tvar3\[\t \]+1234567000000\[\t \]+.*<undefined>.*" \
+ "List tvariables after deletion"
+
+ send_gdb "delete tvariable\n"
+ gdb_expect 30 {
+ -re "Delete all trace state variables.*y or n.*$" {
+ send_gdb "y\n"
+ gdb_expect 30 {
+ -re "$gdb_prompt $" {
+ pass "Delete all trace state variables"
+ }
+ timeout { fail "Delete all trace state variables (timeout)" }
+ }
+ }
+ -re "$gdb_prompt $" { # This happens if there were no variables
+ }
+ timeout { perror "Delete all trace state variables (timeout)" ; return }
+ }
+
+ gdb_test "info tvariables" \
+ "Name\[\t \]+Initial\[\t \]+Current.*" \
+ "List tvariables after deleting all"
+
+
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH] Trace state variables 2009-12-15 13:51 [PATCH] Trace state variables Stan Shebs @ 2009-12-15 15:53 ` Eli Zaretskii 2009-12-15 19:04 ` Stan Shebs 2009-12-15 19:17 ` Tom Tromey 2009-12-29 17:21 ` Stan Shebs 2 siblings, 1 reply; 7+ messages in thread From: Eli Zaretskii @ 2009-12-15 15:53 UTC (permalink / raw) To: Stan Shebs; +Cc: gdb-patches > Date: Tue, 15 Dec 2009 05:51:18 -0800 > From: Stan Shebs <stan@codesourcery.com> > > One of our tracepoint enhancements is to add the notion of a "trace > state variable", which is a GDB-defined piece of data managed by the > tracepoint agent on the target; one could think of it as a target-side > convenience variable. Thanks. > In keeping with their convenience-like nature, they are introduced > with a dollar sign But the code seems to allow with or without the $, right? Like here: > + /* Be relaxed about the special character. */ > + if (*name == '$') > + ++name; A few comments: > + /* Make sure the tsv number is in range. */ > + if (num < 0 || num > 0xffff) > + error (_("GDB bug: ax-general.c (ax_tsv): variable number out of range")); Should this be internal_error instead? > + warning (_("No trace variable named \"$%s\", not deleting"), name); The "not deleting" part seems unnecessary. > + printf_filtered (" <unknown>"); > + else > + /* It is not meaningful to ask about the value. */ > + printf_filtered (" <undefined>"); No translations for these two? > Index: doc/agentexpr.texi > =================================================================== > RCS file: /cvs/src/src/gdb/doc/agentexpr.texi,v > retrieving revision 1.9 > diff -p -r1.9 agentexpr.texi > *** doc/agentexpr.texi 11 Nov 2009 15:08:50 -0000 1.9 > --- doc/agentexpr.texi 15 Dec 2009 13:28:33 -0000 This part is fine. > + @node Trace State Variables > + @subsection Trace State Variables > + > + A @dfn{trace state variable} is a special type of variable that is > + created and managed by target-side code. The syntax is the same as This introduces a new terminology, so please add an index entry for it. > + but they are stored on the target. They must be created explicitly, ^^ Two spaces between sentences, please (here and elsewhere). > + while the trace experiment is running. Trace state variables share > + the same namespace as other ``$'' variables, which means that you > + cannot have trace state variables with names like @code{$23} or > + @code{$pc}, nor can you have a trace state variable and a convenience > + variable with the same name. I would suggest here an index entry like @cindex convenience variables, and trace state variables > + @item tvariable $@var{name} [ = @var{expression} ] > + @kindex tvariable > + @cindex trace state variable This @cindex entry should be moved to the beginning of the subsection, and will then serve as the indexing of the term "trace state variable" that this section introduces. > + The @code{tvariable} command creates a new trace state variable named > + @code{$}@var{name} ^^^^^^^^^^^^^^^^^^ @code{$@var{name}} > + A second @code{tvariable} > + command with the same name assigns a new value to the variable. I don't understand this sentence: what ``second command''? what ``new value''? Did you mean to say that each tvariable command overwrites the previous value by a new one? > + @item info tvariables > + @kindex tvariables We already have "@kindex tvariable" a few lines above, so this @kindex is not useful. Suggest to remove it, or replace with @kindex info tvariables > + List all the trace state variables along with their initial values. ^^^^^^^^^^^^^^^^^^^^ But in reality the current values are displayed as well, right? > + @item QTDV:@var{n}:@var{value} Don't we have index entries for all the packets we support? > + @item V@var{value} > + The value of the variable is @var{value}. This will be the current > + value of the variable if the user is examining a running target, or a > + saved value if the variable was collected in the trace frame that the > + user is looking at. Note that multiple requests may result in different > + reply values, such as for variables like @code{$trace_timestamp} that are > + computed by the target program. What is this $trace_timestamp variable mentioned in the last sentence? I thought trace state variables need to be declared before they can be used, so how come we evidently have special internally generated variables with magic features? What am I missing here? ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Trace state variables 2009-12-15 15:53 ` Eli Zaretskii @ 2009-12-15 19:04 ` Stan Shebs 0 siblings, 0 replies; 7+ messages in thread From: Stan Shebs @ 2009-12-15 19:04 UTC (permalink / raw) To: Eli Zaretskii; +Cc: Stan Shebs, gdb-patches Eli Zaretskii wrote: >> Date: Tue, 15 Dec 2009 05:51:18 -0800 >> From: Stan Shebs <stan@codesourcery.com> >> >> One of our tracepoint enhancements is to add the notion of a "trace >> state variable", which is a GDB-defined piece of data managed by the >> tracepoint agent on the target; one could think of it as a target-side >> convenience variable. >> > > Thanks. > > >> In keeping with their convenience-like nature, they are introduced >> with a dollar sign >> > > But the code seems to allow with or without the $, right? Like here: > > >> + /* Be relaxed about the special character. */ >> + if (*name == '$') >> + ++name; >> I was thinking to let internal API work or without, for flexibility, but this routine is only called in one place, so I'll just make it consistently require. > > A few comments: > > >> + /* Make sure the tsv number is in range. */ >> + if (num < 0 || num > 0xffff) >> + error (_("GDB bug: ax-general.c (ax_tsv): variable number out of range")); >> > > Should this be internal_error instead? > Yep. > >> + warning (_("No trace variable named \"$%s\", not deleting"), name); >> > > The "not deleting" part seems unnecessary. > I suppose so. I always like to have warnings say what GDB is going to do with the situation, even if it seems somewhat obvious to us, because it may not be as obvious to the user (after all, they're getting a warning because things are not going as expected). >> + printf_filtered (" <unknown>"); >> + else >> + /* It is not meaningful to ask about the value. */ >> + printf_filtered (" <undefined>"); >> > > No translations for these two? > > Oversight. >> + A second @code{tvariable} >> + command with the same name assigns a new value to the variable. >> > > I don't understand this sentence: what ``second command''? what ``new > value''? Did you mean to say that each tvariable command overwrites > the previous value by a new one? > Yeah, I'll improve the phrasing. >> + List all the trace state variables along with their initial values. >> > ^^^^^^^^^^^^^^^^^^^^ > But in reality the current values are displayed as well, right? > Yep. >> + @item QTDV:@var{n}:@var{value} >> > > Don't we have index entries for all the packets we support? > Excellent idea, I should do that. :-) >> + @item V@var{value} >> + The value of the variable is @var{value}. This will be the current >> + value of the variable if the user is examining a running target, or a >> + saved value if the variable was collected in the trace frame that the >> + user is looking at. Note that multiple requests may result in different >> + reply values, such as for variables like @code{$trace_timestamp} that are >> + computed by the target program. >> > > What is this $trace_timestamp variable mentioned in the last sentence? > I thought trace state variables need to be declared before they can be > used, so how come we evidently have special internally generated > variables with magic features? What am I missing here? > > Oops, a communique from the future. :-) An upcoming patch will add the capability for a target to define its own builtin variables, whose definitions are uploaded upon connection. Stan ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Trace state variables 2009-12-15 13:51 [PATCH] Trace state variables Stan Shebs 2009-12-15 15:53 ` Eli Zaretskii @ 2009-12-15 19:17 ` Tom Tromey 2009-12-18 20:03 ` Stan Shebs 2009-12-29 17:21 ` Stan Shebs 2 siblings, 1 reply; 7+ messages in thread From: Tom Tromey @ 2009-12-15 19:17 UTC (permalink / raw) To: Stan Shebs; +Cc: gdb-patches >>>>> "Stan" == Stan Shebs <stan@codesourcery.com> writes: Stan> Since internalvar handling has changed recently, I've left off the Stan> value.c bit to make "print $foo" work. Will this be forthcoming? Stan> + case BINOP_ASSIGN: It seems a little odd to add BINOP_ASSIGN but not BINOP_ASSIGN_MODIFY. Stan> extern int remote_supports_cond_tracepoints (void); Stan> + extern char *unpack_varlen_hex (char *buff, ULONGEST *result); It seems like this could be in a header somewhere. Stan> + /* The list of all trace state variables. We don't retain pointers to Stan> + any of these for any reason - API is by name or number only - so it Stan> + works to have a vector of objects. */ Stan> + Stan> + VEC(tsv_s) *tvariables; Stan> + Stan> + /* The next integer to assign to a variable. */ Stan> + Stan> + int next_tsv_number = 1; It seems like these, plus some of the new functions, could be static. It is hard to say for sure since I don't know what future patches might do. Stan> + void Stan> + trace_variable_command (char *args, int from_tty) Stan> + { [...] Stan> + /* All the possible valid arguments are expressions. */ Stan> + expr = parse_expression (args); Stan> + old_chain = make_cleanup (free_current_contents, &expr); I think set_cmd_completer (..., expression_completer) is probably in order, in the file's initialize function. Stan> + void Stan> + delete_trace_variable_command (char *args, int from_tty) It would be nice to have a completer function for this. Stan> + static void Stan> + tvariables_info (char *args, int from_tty) [...] Stan> + printf_filtered (_("Name\t\t Initial\tCurrent\n")); I think that brand-new formatted output should be done using the ui_out machinery. Is there some drawback to doing that? I really don't know... I would have expected ui_out to be used universally but instead it seems somewhat random, and I don't know why. (I assume that whoever was doing this transition ran out of steam... ?) Stan> + typedef struct trace_state_variable tsv_s; Stan> + DEF_VEC_O(tsv_s); AFAICT, this VEC is only used in a single .c file. It is better to put the DEF_VEC there, to avoid duplicating the static functions in other compilation units where they aren't needed. Tom ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Trace state variables 2009-12-15 19:17 ` Tom Tromey @ 2009-12-18 20:03 ` Stan Shebs 2009-12-18 20:47 ` Tom Tromey 0 siblings, 1 reply; 7+ messages in thread From: Stan Shebs @ 2009-12-18 20:03 UTC (permalink / raw) To: tromey; +Cc: Stan Shebs, gdb-patches Tom Tromey wrote: >>>>>> "Stan" == Stan Shebs <stan@codesourcery.com> writes: >>>>>> > > Stan> Since internalvar handling has changed recently, I've left off the > Stan> value.c bit to make "print $foo" work. > > Will this be forthcoming? > Yep, just have to figure out the new way of things. > Stan> + case BINOP_ASSIGN: > > It seems a little odd to add BINOP_ASSIGN but not BINOP_ASSIGN_MODIFY. > <groan> You're going to make me do it, aren't you. :-) > Stan> extern int remote_supports_cond_tracepoints (void); > Stan> + extern char *unpack_varlen_hex (char *buff, ULONGEST *result); > > It seems like this could be in a header somewhere. > This is one of the temporary hacks pending target-vectorization of tracepoint ops. > Stan> + /* The list of all trace state variables. We don't retain pointers to > Stan> + any of these for any reason - API is by name or number only - so it > Stan> + works to have a vector of objects. */ > Stan> + > Stan> + VEC(tsv_s) *tvariables; > Stan> + > Stan> + /* The next integer to assign to a variable. */ > Stan> + > Stan> + int next_tsv_number = 1; > > It seems like these, plus some of the new functions, could be static. > It is hard to say for sure since I don't know what future patches might do. > They could be, yeah, remote.c code will handle tsv's one-by-one, no need to pass whole list. > Stan> + static void > Stan> + tvariables_info (char *args, int from_tty) > [...] > Stan> + printf_filtered (_("Name\t\t Initial\tCurrent\n")); > > I think that brand-new formatted output should be done using the ui_out > machinery. Is there some drawback to doing that? I really don't > know... I would have expected ui_out to be used universally but instead > it seems somewhat random, and I don't know why. (I assume that whoever > was doing this transition ran out of steam... ?) > I can't even remember why I didn't use ui_out. Well, that's why we do reviews... :-) Stan ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Trace state variables 2009-12-18 20:03 ` Stan Shebs @ 2009-12-18 20:47 ` Tom Tromey 0 siblings, 0 replies; 7+ messages in thread From: Tom Tromey @ 2009-12-18 20:47 UTC (permalink / raw) To: Stan Shebs; +Cc: gdb-patches >>>>> "Stan" == Stan Shebs <stan@codesourcery.com> writes: Stan> + case BINOP_ASSIGN: >> It seems a little odd to add BINOP_ASSIGN but not BINOP_ASSIGN_MODIFY. Stan> <groan> You're going to make me do it, aren't you. :-) :-) It is really up to you, I won't insist on it. I don't think it is much code, though... Stan> extern int remote_supports_cond_tracepoints (void); Stan> + extern char *unpack_varlen_hex (char *buff, ULONGEST *result); >> It seems like this could be in a header somewhere. Stan> This is one of the temporary hacks pending target-vectorization of Stan> tracepoint ops. Aha, thanks. Tom ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Trace state variables 2009-12-15 13:51 [PATCH] Trace state variables Stan Shebs 2009-12-15 15:53 ` Eli Zaretskii 2009-12-15 19:17 ` Tom Tromey @ 2009-12-29 17:21 ` Stan Shebs 2 siblings, 0 replies; 7+ messages in thread From: Stan Shebs @ 2009-12-29 17:21 UTC (permalink / raw) To: Stan Shebs; +Cc: gdb-patches [-- Attachment #1: Type: text/plain, Size: 1648 bytes --] Here's what I committed. I incorporated the feedback (thanks!), including adding BINOP_ASSIGN_MODIFY (messier than one would think, required refactoring binary operation compilation), and added a NEWS item. Now on to the next new tracing feature! :-) Stan 2009-12-28 Stan Shebs <stan@codesourcery.com> Add trace state variables. * ax.h (enum agent_op): Add getv, setv, and tracev. (ax_tsv): Declare. * ax-gdb.c: Include tracepoint.h. (gen_expr): Handle BINOP_ASSIGN, BINOP_ASSIGN_MODIFY, and OP_INTERNALVAR. (gen_expr_binop_rest): New function, split from gen_expr. * ax-general.c (ax_tsv): New function. (aop_map): Add new bytecodes. * tracepoint.h (struct trace_state_variable): New struct. (tsv_s): New typedef. (find_trace_state_variable): Declare. * tracepoint.c (tvariables): New global. (next_tsv_number): New global. (create_trace_state_variable): New function. (find_trace_state_variable): New function. (delete_trace_state_variable): New function. (trace_variable_command): New function. (delete_trace_variable_command): New function. (tvariables_info): New function. (trace_start_command): Download tsvs with initial values. (_initialize_tracepoint): Add new commands. * NEWS: Mention the addition of trace state variables. * gdb.texinfo (Trace State Variables): New section. (Tracepoint Packets): Describe trace state variable packets. * agentexpr.texi (Bytecode Descriptions): Describe trace state variable bytecodes. * gdb.trace/tsv.exp: New file. * gdb.base/completion.exp: Update ambiguous info output. [-- Attachment #2: tsv-patch-2 --] [-- Type: text/plain, Size: 44295 bytes --] Index: NEWS =================================================================== RCS file: /cvs/src/src/gdb/NEWS,v retrieving revision 1.341 diff -p -r1.341 NEWS *** NEWS 28 Dec 2009 21:29:53 -0000 1.341 --- NEWS 28 Dec 2009 23:37:28 -0000 *************** Renesas RX rx *** 24,29 **** --- 24,42 ---- lists inferiors that are not running yet or that have exited already. See also "New commands" and "New options" below. + * Trace state variables + + GDB tracepoints now include support for trace state variables, which + are variables managed by the target agent during a tracing + experiment. They are useful for tracepoints that trigger each + other, so for instance one tracepoint can count hits in a variable, + and then a second tracepoint has a condition that is true when the + count reaches a particular value. Trace state variables share the + $-syntax of GDB convenience variables, and can appear in both + tracepoint actions and condition expressions. Use the "tvariable" + command to create, and "info tvariables" to view; see "Trace State + Variables" in the manual for more detail. + * Changed commands disassemble *************** set remotebreak [on | off] *** 75,80 **** --- 88,102 ---- show remotebreak Deprecated. Use "set/show remote interrupt-sequence" instead. + tvariable $NAME [ = EXP ] + Create or modify a trace state variable. + + info tvariables + List trace state variables and their values. + + delete tvariable $NAME ... + Delete one or more trace state variables. + * New options set follow-exec-mode new|same *************** show follow-exec-mode *** 83,88 **** --- 105,118 ---- creates a new one. This is useful to be able to restart the old executable after the inferior having done an exec call. + * New remote packets + + QTDV + Define a trace state variable. + + qTV + Get the current value of a trace state variable. + * Bug fixes Process record now works correctly with hardware watchpoints. Index: ax-gdb.c =================================================================== RCS file: /cvs/src/src/gdb/ax-gdb.c,v retrieving revision 1.56 diff -p -r1.56 ax-gdb.c *** ax-gdb.c 28 Dec 2009 16:49:14 -0000 1.56 --- ax-gdb.c 28 Dec 2009 23:37:28 -0000 *************** *** 36,41 **** --- 36,42 ---- #include "user-regs.h" #include "language.h" #include "dictionary.h" + #include "tracepoint.h" /* To make sense of this file, you should read doc/agentexpr.texi. Then look at the types and enums in ax-gdb.h. For the code itself, *************** static void gen_sizeof (struct expressio *** 139,144 **** --- 140,151 ---- struct type *size_type); static void gen_expr (struct expression *exp, union exp_element **pc, struct agent_expr *ax, struct axs_value *value); + static void gen_expr_binop_rest (struct expression *exp, + enum exp_opcode op, union exp_element **pc, + struct agent_expr *ax, + struct axs_value *value, + struct axs_value *value1, + struct axs_value *value2); static void agent_command (char *exp, int from_tty); \f *************** gen_expr (struct expression *exp, union *** 1441,1447 **** { /* Used to hold the descriptions of operand expressions. */ struct axs_value value1, value2; ! enum exp_opcode op = (*pc)[0].opcode; /* If we're looking at a constant expression, just push its value. */ { --- 1448,1454 ---- { /* Used to hold the descriptions of operand expressions. */ struct axs_value value1, value2; ! enum exp_opcode op = (*pc)[0].opcode, op2; /* If we're looking at a constant expression, just push its value. */ { *************** gen_expr (struct expression *exp, union *** 1478,1596 **** (*pc)++; gen_expr (exp, pc, ax, &value1); gen_usual_unary (exp, ax, &value1); ! gen_expr (exp, pc, ax, &value2); ! gen_usual_unary (exp, ax, &value2); ! gen_usual_arithmetic (exp, ax, &value1, &value2); ! switch (op) { ! case BINOP_ADD: ! if (TYPE_CODE (value1.type) == TYPE_CODE_INT ! && TYPE_CODE (value2.type) == TYPE_CODE_PTR) { ! /* Swap the values and proceed normally. */ ! ax_simple (ax, aop_swap); ! gen_ptradd (ax, value, &value2, &value1); } - else if (TYPE_CODE (value1.type) == TYPE_CODE_PTR - && TYPE_CODE (value2.type) == TYPE_CODE_INT) - gen_ptradd (ax, value, &value1, &value2); - else - gen_binop (ax, value, &value1, &value2, - aop_add, aop_add, 1, "addition"); - break; - case BINOP_SUB: - if (TYPE_CODE (value1.type) == TYPE_CODE_PTR - && TYPE_CODE (value2.type) == TYPE_CODE_INT) - gen_ptrsub (ax,value, &value1, &value2); - else if (TYPE_CODE (value1.type) == TYPE_CODE_PTR - && TYPE_CODE (value2.type) == TYPE_CODE_PTR) - /* FIXME --- result type should be ptrdiff_t */ - gen_ptrdiff (ax, value, &value1, &value2, - builtin_type (exp->gdbarch)->builtin_long); else ! gen_binop (ax, value, &value1, &value2, ! aop_sub, aop_sub, 1, "subtraction"); ! break; ! case BINOP_MUL: ! gen_binop (ax, value, &value1, &value2, ! aop_mul, aop_mul, 1, "multiplication"); ! break; ! case BINOP_DIV: ! gen_binop (ax, value, &value1, &value2, ! aop_div_signed, aop_div_unsigned, 1, "division"); ! break; ! case BINOP_REM: ! gen_binop (ax, value, &value1, &value2, ! aop_rem_signed, aop_rem_unsigned, 1, "remainder"); ! break; ! case BINOP_SUBSCRIPT: ! gen_ptradd (ax, value, &value1, &value2); ! if (TYPE_CODE (value->type) != TYPE_CODE_PTR) ! error (_("Invalid combination of types in array subscripting.")); ! gen_deref (ax, value); ! break; ! case BINOP_BITWISE_AND: ! gen_binop (ax, value, &value1, &value2, ! aop_bit_and, aop_bit_and, 0, "bitwise and"); ! break; ! ! case BINOP_BITWISE_IOR: ! gen_binop (ax, value, &value1, &value2, ! aop_bit_or, aop_bit_or, 0, "bitwise or"); ! break; ! ! case BINOP_BITWISE_XOR: ! gen_binop (ax, value, &value1, &value2, ! aop_bit_xor, aop_bit_xor, 0, "bitwise exclusive-or"); ! break; ! ! case BINOP_EQUAL: ! gen_binop (ax, value, &value1, &value2, ! aop_equal, aop_equal, 0, "equal"); ! break; ! ! case BINOP_NOTEQUAL: ! gen_binop (ax, value, &value1, &value2, ! aop_equal, aop_equal, 0, "equal"); ! gen_logical_not (ax, value, ! language_bool_type (exp->language_defn, ! exp->gdbarch)); ! break; ! ! case BINOP_LESS: ! gen_binop (ax, value, &value1, &value2, ! aop_less_signed, aop_less_unsigned, 0, "less than"); ! break; ! ! case BINOP_GTR: ! ax_simple (ax, aop_swap); ! gen_binop (ax, value, &value1, &value2, ! aop_less_signed, aop_less_unsigned, 0, "less than"); ! break; ! ! case BINOP_LEQ: ! ax_simple (ax, aop_swap); ! gen_binop (ax, value, &value1, &value2, ! aop_less_signed, aop_less_unsigned, 0, "less than"); ! gen_logical_not (ax, value, ! language_bool_type (exp->language_defn, ! exp->gdbarch)); ! break; ! ! case BINOP_GEQ: ! gen_binop (ax, value, &value1, &value2, ! aop_less_signed, aop_less_unsigned, 0, "less than"); ! gen_logical_not (ax, value, ! language_bool_type (exp->language_defn, ! exp->gdbarch)); ! break; ! default: ! /* We should only list operators in the outer case statement ! that we actually handle in the inner case statement. */ ! internal_error (__FILE__, __LINE__, ! _("gen_expr: op case sets don't match")); } break; /* Note that we need to be a little subtle about generating code --- 1485,1547 ---- (*pc)++; gen_expr (exp, pc, ax, &value1); gen_usual_unary (exp, ax, &value1); ! gen_expr_binop_rest (exp, op, pc, ax, value, &value1, &value2); ! break; ! ! case BINOP_ASSIGN: ! (*pc)++; ! if ((*pc)[0].opcode == OP_INTERNALVAR) { ! char *name = internalvar_name ((*pc)[1].internalvar); ! struct trace_state_variable *tsv; ! (*pc) += 3; ! gen_expr (exp, pc, ax, value); ! tsv = find_trace_state_variable (name); ! if (tsv) { ! ax_tsv (ax, aop_setv, tsv->number); ! if (trace_kludge) ! ax_tsv (ax, aop_tracev, tsv->number); } else ! error (_("$%s is not a trace state variable, may not assign to it"), name); ! } ! else ! error (_("May only assign to trace state variables")); ! break; ! case BINOP_ASSIGN_MODIFY: ! (*pc)++; ! op2 = (*pc)[0].opcode; ! (*pc)++; ! (*pc)++; ! if ((*pc)[0].opcode == OP_INTERNALVAR) ! { ! char *name = internalvar_name ((*pc)[1].internalvar); ! struct trace_state_variable *tsv; ! (*pc) += 3; ! tsv = find_trace_state_variable (name); ! if (tsv) ! { ! /* The tsv will be the left half of the binary operation. */ ! ax_tsv (ax, aop_getv, tsv->number); ! if (trace_kludge) ! ax_tsv (ax, aop_tracev, tsv->number); ! /* Trace state variables are always 64-bit integers. */ ! value1.kind = axs_rvalue; ! value1.type = builtin_type (exp->gdbarch)->builtin_long_long; ! /* Now do right half of expression. */ ! gen_expr_binop_rest (exp, op2, pc, ax, value, &value1, &value2); ! /* We have a result of the binary op, set the tsv. */ ! ax_tsv (ax, aop_setv, tsv->number); ! if (trace_kludge) ! ax_tsv (ax, aop_tracev, tsv->number); ! } ! else ! error (_("$%s is not a trace state variable, may not assign to it"), name); } + else + error (_("May only assign to trace state variables")); break; /* Note that we need to be a little subtle about generating code *************** gen_expr (struct expression *exp, union *** 1644,1650 **** break; case OP_INTERNALVAR: ! error (_("GDB agent expressions cannot use convenience variables.")); /* Weirdo operator: see comments for gen_repeat for details. */ case BINOP_REPEAT: --- 1595,1618 ---- break; case OP_INTERNALVAR: ! { ! const char *name = internalvar_name ((*pc)[1].internalvar); ! struct trace_state_variable *tsv; ! (*pc) += 3; ! tsv = find_trace_state_variable (name); ! if (tsv) ! { ! ax_tsv (ax, aop_getv, tsv->number); ! if (trace_kludge) ! ax_tsv (ax, aop_tracev, tsv->number); ! /* Trace state variables are always 64-bit integers. */ ! value->kind = axs_rvalue; ! value->type = builtin_type (exp->gdbarch)->builtin_long_long; ! } ! else ! error (_("$%s is not a trace state variable; GDB agent expressions cannot use convenience variables."), name); ! } ! break; /* Weirdo operator: see comments for gen_repeat for details. */ case BINOP_REPEAT: *************** gen_expr (struct expression *exp, union *** 1788,1793 **** --- 1756,1886 ---- error (_("Unsupported operator in expression.")); } } + + /* This handles the middle-to-right-side of code generation for binary + expressions, which is shared between regular binary operations and + assign-modify (+= and friends) expressions. */ + + static void + gen_expr_binop_rest (struct expression *exp, + enum exp_opcode op, union exp_element **pc, + struct agent_expr *ax, struct axs_value *value, + struct axs_value *value1, struct axs_value *value2) + { + gen_expr (exp, pc, ax, value2); + gen_usual_unary (exp, ax, value2); + gen_usual_arithmetic (exp, ax, value1, value2); + switch (op) + { + case BINOP_ADD: + if (TYPE_CODE (value1->type) == TYPE_CODE_INT + && TYPE_CODE (value2->type) == TYPE_CODE_PTR) + { + /* Swap the values and proceed normally. */ + ax_simple (ax, aop_swap); + gen_ptradd (ax, value, value2, value1); + } + else if (TYPE_CODE (value1->type) == TYPE_CODE_PTR + && TYPE_CODE (value2->type) == TYPE_CODE_INT) + gen_ptradd (ax, value, value1, value2); + else + gen_binop (ax, value, value1, value2, + aop_add, aop_add, 1, "addition"); + break; + case BINOP_SUB: + if (TYPE_CODE (value1->type) == TYPE_CODE_PTR + && TYPE_CODE (value2->type) == TYPE_CODE_INT) + gen_ptrsub (ax,value, value1, value2); + else if (TYPE_CODE (value1->type) == TYPE_CODE_PTR + && TYPE_CODE (value2->type) == TYPE_CODE_PTR) + /* FIXME --- result type should be ptrdiff_t */ + gen_ptrdiff (ax, value, value1, value2, + builtin_type (exp->gdbarch)->builtin_long); + else + gen_binop (ax, value, value1, value2, + aop_sub, aop_sub, 1, "subtraction"); + break; + case BINOP_MUL: + gen_binop (ax, value, value1, value2, + aop_mul, aop_mul, 1, "multiplication"); + break; + case BINOP_DIV: + gen_binop (ax, value, value1, value2, + aop_div_signed, aop_div_unsigned, 1, "division"); + break; + case BINOP_REM: + gen_binop (ax, value, value1, value2, + aop_rem_signed, aop_rem_unsigned, 1, "remainder"); + break; + case BINOP_SUBSCRIPT: + gen_ptradd (ax, value, value1, value2); + if (TYPE_CODE (value->type) != TYPE_CODE_PTR) + error (_("Invalid combination of types in array subscripting.")); + gen_deref (ax, value); + break; + case BINOP_BITWISE_AND: + gen_binop (ax, value, value1, value2, + aop_bit_and, aop_bit_and, 0, "bitwise and"); + break; + + case BINOP_BITWISE_IOR: + gen_binop (ax, value, value1, value2, + aop_bit_or, aop_bit_or, 0, "bitwise or"); + break; + + case BINOP_BITWISE_XOR: + gen_binop (ax, value, value1, value2, + aop_bit_xor, aop_bit_xor, 0, "bitwise exclusive-or"); + break; + + case BINOP_EQUAL: + gen_binop (ax, value, value1, value2, + aop_equal, aop_equal, 0, "equal"); + break; + + case BINOP_NOTEQUAL: + gen_binop (ax, value, value1, value2, + aop_equal, aop_equal, 0, "equal"); + gen_logical_not (ax, value, + language_bool_type (exp->language_defn, + exp->gdbarch)); + break; + + case BINOP_LESS: + gen_binop (ax, value, value1, value2, + aop_less_signed, aop_less_unsigned, 0, "less than"); + break; + + case BINOP_GTR: + ax_simple (ax, aop_swap); + gen_binop (ax, value, value1, value2, + aop_less_signed, aop_less_unsigned, 0, "less than"); + break; + + case BINOP_LEQ: + ax_simple (ax, aop_swap); + gen_binop (ax, value, value1, value2, + aop_less_signed, aop_less_unsigned, 0, "less than"); + gen_logical_not (ax, value, + language_bool_type (exp->language_defn, + exp->gdbarch)); + break; + + case BINOP_GEQ: + gen_binop (ax, value, value1, value2, + aop_less_signed, aop_less_unsigned, 0, "less than"); + gen_logical_not (ax, value, + language_bool_type (exp->language_defn, + exp->gdbarch)); + break; + + default: + /* We should only list operators in the outer case statement + that we actually handle in the inner case statement. */ + internal_error (__FILE__, __LINE__, + _("gen_expr: op case sets don't match")); + } + } \f /* Given a single variable and a scope, generate bytecodes to trace Index: ax-general.c =================================================================== RCS file: /cvs/src/src/gdb/ax-general.c,v retrieving revision 1.15 diff -p -r1.15 ax-general.c *** ax-general.c 3 Jan 2009 05:57:50 -0000 1.15 --- ax-general.c 28 Dec 2009 23:37:28 -0000 *************** ax_reg (struct agent_expr *x, int reg) *** 272,277 **** --- 272,293 ---- x->buf[x->len + 2] = (reg) & 0xff; x->len += 3; } + + /* Assemble code to operate on a trace state variable. */ + + void + ax_tsv (struct agent_expr *x, enum agent_op op, int num) + { + /* Make sure the tsv number is in range. */ + if (num < 0 || num > 0xffff) + internal_error (__FILE__, __LINE__, _("ax-general.c (ax_tsv): variable number is %d, out of range"), num); + + grow_expr (x, 3); + x->buf[x->len] = op; + x->buf[x->len + 1] = (num >> 8) & 0xff; + x->buf[x->len + 2] = (num) & 0xff; + x->len += 3; + } \f *************** struct aop_map aop_map[] = *** 324,332 **** {"pop", 0, 0, 1, 0}, /* 0x29 */ {"zero_ext", 1, 0, 1, 1}, /* 0x2a */ {"swap", 0, 0, 2, 2}, /* 0x2b */ ! {0, 0, 0, 0, 0}, /* 0x2c */ ! {0, 0, 0, 0, 0}, /* 0x2d */ ! {0, 0, 0, 0, 0}, /* 0x2e */ {0, 0, 0, 0, 0}, /* 0x2f */ {"trace16", 2, 0, 1, 1}, /* 0x30 */ }; --- 340,348 ---- {"pop", 0, 0, 1, 0}, /* 0x29 */ {"zero_ext", 1, 0, 1, 1}, /* 0x2a */ {"swap", 0, 0, 2, 2}, /* 0x2b */ ! {"getv", 2, 0, 0, 1}, /* 0x2c */ ! {"setv", 2, 0, 0, 1}, /* 0x2d */ ! {"tracev", 2, 0, 0, 1}, /* 0x2e */ {0, 0, 0, 0, 0}, /* 0x2f */ {"trace16", 2, 0, 1, 1}, /* 0x30 */ }; Index: ax.h =================================================================== RCS file: /cvs/src/src/gdb/ax.h,v retrieving revision 1.10 diff -p -r1.10 ax.h *** ax.h 3 Jan 2009 05:57:50 -0000 1.10 --- ax.h 28 Dec 2009 23:37:28 -0000 *************** enum agent_op *** 131,136 **** --- 131,139 ---- aop_pop = 0x29, aop_zero_ext = 0x2a, aop_swap = 0x2b, + aop_getv = 0x2c, + aop_setv = 0x2d, + aop_tracev = 0x2e, aop_trace16 = 0x30, aop_last }; *************** extern void ax_const_d (struct agent_exp *** 182,187 **** --- 185,193 ---- /* Assemble code to push the value of register number REG on the stack. */ extern void ax_reg (struct agent_expr *EXPR, int REG); + + /* Assemble code to operate on a trace state variable. */ + extern void ax_tsv (struct agent_expr *expr, enum agent_op op, int num); \f /* Functions for printing out expressions, and otherwise debugging Index: tracepoint.c =================================================================== RCS file: /cvs/src/src/gdb/tracepoint.c,v retrieving revision 1.128 diff -p -r1.128 tracepoint.c *** tracepoint.c 24 Dec 2009 00:40:49 -0000 1.128 --- tracepoint.c 28 Dec 2009 23:37:28 -0000 *************** *** 34,39 **** --- 34,40 ---- #include "tracepoint.h" #include "remote.h" extern int remote_supports_cond_tracepoints (void); + extern char *unpack_varlen_hex (char *buff, ULONGEST *result); #include "linespec.h" #include "regcache.h" #include "completer.h" *************** extern void output_command (char *, int) *** 111,116 **** --- 112,130 ---- /* ======= Important global variables: ======= */ + /* The list of all trace state variables. We don't retain pointers to + any of these for any reason - API is by name or number only - so it + works to have a vector of objects. */ + + typedef struct trace_state_variable tsv_s; + DEF_VEC_O(tsv_s); + + static VEC(tsv_s) *tvariables; + + /* The next integer to assign to a variable. */ + + static int next_tsv_number = 1; + /* Number of last traceframe collected. */ static int traceframe_number; *************** static struct symtab_and_line traceframe *** 126,131 **** --- 140,148 ---- /* Tracing command lists */ static struct cmd_list_element *tfindlist; + static char *target_buf; + static long target_buf_size; + /* ======= Important command functions: ======= */ static void trace_actions_command (char *, int); static void trace_start_command (char *, int); *************** set_traceframe_context (struct frame_inf *** 274,279 **** --- 291,495 ---- traceframe_sal.symtab->filename); } + /* Create a new trace state variable with the given name. */ + + struct trace_state_variable * + create_trace_state_variable (const char *name) + { + struct trace_state_variable tsv; + + memset (&tsv, 0, sizeof (tsv)); + tsv.name = name; + tsv.number = next_tsv_number++; + return VEC_safe_push (tsv_s, tvariables, &tsv); + } + + /* Look for a trace state variable of the given name. */ + + struct trace_state_variable * + find_trace_state_variable (const char *name) + { + struct trace_state_variable *tsv; + int ix; + + for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix) + if (strcmp (name, tsv->name) == 0) + return tsv; + + return NULL; + } + + void + delete_trace_state_variable (const char *name) + { + struct trace_state_variable *tsv; + int ix; + + for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix) + if (strcmp (name, tsv->name) == 0) + { + VEC_unordered_remove (tsv_s, tvariables, ix); + return; + } + + warning (_("No trace variable named \"$%s\", not deleting"), name); + } + + /* The 'tvariable' command collects a name and optional expression to + evaluate into an initial value. */ + + void + trace_variable_command (char *args, int from_tty) + { + struct expression *expr; + struct cleanup *old_chain; + struct internalvar *intvar = NULL; + LONGEST initval = 0; + struct trace_state_variable *tsv; + + if (!args || !*args) + error_no_arg (_("trace state variable name")); + + /* All the possible valid arguments are expressions. */ + expr = parse_expression (args); + old_chain = make_cleanup (free_current_contents, &expr); + + if (expr->nelts == 0) + error (_("No expression?")); + + /* Only allow two syntaxes; "$name" and "$name=value". */ + if (expr->elts[0].opcode == OP_INTERNALVAR) + { + intvar = expr->elts[1].internalvar; + } + else if (expr->elts[0].opcode == BINOP_ASSIGN + && expr->elts[1].opcode == OP_INTERNALVAR) + { + intvar = expr->elts[2].internalvar; + initval = value_as_long (evaluate_subexpression_type (expr, 4)); + } + else + error (_("Syntax must be $NAME [ = EXPR ]")); + + if (!intvar) + error (_("No name given")); + + if (strlen (internalvar_name (intvar)) <= 0) + error (_("Must supply a non-empty variable name")); + + /* If the variable already exists, just change its initial value. */ + tsv = find_trace_state_variable (internalvar_name (intvar)); + if (tsv) + { + tsv->initial_value = initval; + printf_filtered (_("Trace state variable $%s now has initial value %s.\n"), + tsv->name, plongest (tsv->initial_value)); + return; + } + + /* Create a new variable. */ + tsv = create_trace_state_variable (internalvar_name (intvar)); + tsv->initial_value = initval; + + printf_filtered (_("Trace state variable $%s created, with initial value %s.\n"), + tsv->name, plongest (tsv->initial_value)); + + do_cleanups (old_chain); + } + + void + delete_trace_variable_command (char *args, int from_tty) + { + int i, ix; + char **argv; + struct cleanup *back_to; + struct trace_state_variable *tsv; + + if (args == NULL) + { + if (query (_("Delete all trace state variables? "))) + VEC_free (tsv_s, tvariables); + dont_repeat (); + return; + } + + argv = gdb_buildargv (args); + back_to = make_cleanup_freeargv (argv); + + for (i = 0; argv[i] != NULL; i++) + { + if (*argv[i] == '$') + delete_trace_state_variable (argv[i] + 1); + else + warning (_("Name \"%s\" not prefixed with '$', ignoring"), argv[i]); + } + + do_cleanups (back_to); + + dont_repeat (); + } + + /* List all the trace state variables. */ + + static void + tvariables_info (char *args, int from_tty) + { + struct trace_state_variable *tsv; + int ix; + char *reply; + ULONGEST tval; + + if (target_is_remote ()) + { + char buf[20]; + + for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix) + { + /* We don't know anything about the value until we get a + valid packet. */ + tsv->value_known = 0; + sprintf (buf, "qTV:%x", tsv->number); + putpkt (buf); + reply = remote_get_noisy_reply (&target_buf, &target_buf_size); + if (reply && *reply) + { + if (*reply == 'V') + { + unpack_varlen_hex (reply + 1, &tval); + tsv->value = (LONGEST) tval; + tsv->value_known = 1; + } + /* FIXME say anything about oddball replies? */ + } + } + } + + if (VEC_length (tsv_s, tvariables) == 0) + { + printf_filtered (_("No trace state variables.\n")); + return; + } + + printf_filtered (_("Name\t\t Initial\tCurrent\n")); + + for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix) + { + printf_filtered ("$%s", tsv->name); + print_spaces_filtered (17 - strlen (tsv->name), gdb_stdout); + printf_filtered ("%s ", plongest (tsv->initial_value)); + print_spaces_filtered (11 - strlen (plongest (tsv->initial_value)), gdb_stdout); + if (tsv->value_known) + printf_filtered (" %s", plongest (tsv->value)); + else if (trace_running_p || traceframe_number >= 0) + /* The value is/was defined, but we don't have it. */ + printf_filtered (_(" <unknown>")); + else + /* It is not meaningful to ask about the value. */ + printf_filtered (_(" <undefined>")); + printf_filtered ("\n"); + } + } + /* ACTIONS functions: */ /* Prototypes for action-parsing utility commands */ *************** add_aexpr (struct collection_list *colle *** 1254,1262 **** collect->next_aexpr_elt++; } - static char *target_buf; - static long target_buf_size; - /* Set "transparent" memory ranges Allow trace mechanism to treat text-like sections --- 1470,1475 ---- *************** void download_tracepoint (struct breakpo *** 1312,1320 **** --- 1525,1535 ---- static void trace_start_command (char *args, int from_tty) { + char buf[2048]; VEC(breakpoint_p) *tp_vec = NULL; int ix; struct breakpoint *t; + struct trace_state_variable *tsv; dont_repeat (); /* Like "run", dangerous to repeat accidentally. */ *************** trace_start_command (char *args, int fro *** 1332,1337 **** --- 1547,1565 ---- } VEC_free (breakpoint_p, tp_vec); + /* Init any trace state variables that start with nonzero values. */ + + for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix) + { + if (tsv->initial_value != 0) + { + sprintf (buf, "QTDV:%x:%s", + tsv->number, phex ((ULONGEST) tsv->initial_value, 8)); + putpkt (buf); + remote_get_noisy_reply (&target_buf, &target_buf_size); + } + } + /* Tell target to treat text-like sections as transparent. */ remote_set_transparent_ranges (); /* Now insert traps and begin collecting data. */ *************** _initialize_tracepoint (void) *** 2235,2240 **** --- 2463,2485 ---- add_com ("tdump", class_trace, trace_dump_command, _("Print everything collected at the current tracepoint.")); + c = add_com ("tvariable", class_trace, trace_variable_command,_("\ + Define a trace state variable.\n\ + Argument is a $-prefixed name, optionally followed\n\ + by '=' and an expression that sets the initial value\n\ + at the start of tracing.")); + set_cmd_completer (c, expression_completer); + + add_cmd ("tvariable", class_trace, delete_trace_variable_command, _("\ + Delete one or more trace state variables.\n\ + Arguments are the names of the variables to delete.\n\ + If no arguments are supplied, delete all variables."), &deletelist); + /* FIXME add a trace variable completer */ + + add_info ("tvariables", tvariables_info, _("\ + Status of trace state variables and their values.\n\ + ")); + add_prefix_cmd ("tfind", class_trace, trace_find_command, _("\ Select a trace frame;\n\ No argument means forward by one frame; '-' means backward by one frame."), Index: tracepoint.h =================================================================== RCS file: /cvs/src/src/gdb/tracepoint.h,v retrieving revision 1.16 diff -p -r1.16 tracepoint.h *** tracepoint.h 23 Dec 2009 23:21:29 -0000 1.16 --- tracepoint.h 28 Dec 2009 23:37:28 -0000 *************** enum actionline_type *** 35,40 **** --- 35,68 ---- STEPPING = 2 }; + /* A trace state variable is a value managed by a target being + traced. A trace state variable (or tsv for short) can be accessed + and assigned to by tracepoint actions and conditionals, but is not + part of the program being traced, and it doesn't have to be + collected. Effectively the variables are scratch space for + tracepoints. */ + + struct trace_state_variable + { + /* The variable's name. The user has to prefix with a dollar sign, + but we don't store that internally. */ + const char *name; + + /* An id number assigned by GDB, and transmitted to targets. */ + int number; + + /* The initial value of a variable is a 64-bit signed integer. */ + LONGEST initial_value; + + /* 1 if the value is known, else 0. The value is known during a + trace run, or in tfind mode if the variable was collected into + the current trace frame. */ + int value_known; + + /* The value of a variable is a 64-bit signed integer. */ + LONGEST value; + }; + extern unsigned long trace_running_p; /* A hook used to notify the UI of tracepoint operations. */ *************** enum actionline_type validate_actionline *** 49,52 **** --- 77,82 ---- extern void end_actions_pseudocommand (char *args, int from_tty); extern void while_stepping_pseudocommand (char *args, int from_tty); + extern struct trace_state_variable *find_trace_state_variable (const char *name); + #endif /* TRACEPOINT_H */ Index: doc/agentexpr.texi =================================================================== RCS file: /cvs/src/src/gdb/doc/agentexpr.texi,v retrieving revision 1.9 diff -p -r1.9 agentexpr.texi *** doc/agentexpr.texi 11 Nov 2009 15:08:50 -0000 1.9 --- doc/agentexpr.texi 28 Dec 2009 23:37:28 -0000 *************** alignment within the bytecode stream; th *** 440,445 **** --- 440,463 ---- 16-bit on an unaligned address raises an exception, you should fetch the register number one byte at a time. + @item @code{getv} (0x2c) @var{n}: @result{} @var{v} + Push the value of trace state variable number @var{n}, without sign + extension. + + The variable number @var{n} is encoded as a 16-bit unsigned integer + immediately following the @code{getv} bytecode. It is always stored most + significant byte first, regardless of the target's normal endianness. + The variable number is not guaranteed to fall at any particular + alignment within the bytecode stream; thus, on machines where fetching a + 16-bit on an unaligned address raises an exception, you should fetch the + register number one byte at a time. + + @item @code{setv} (0x2d) @var{n}: @result{} @var{v} + Set trace state variable number @var{n} to the value found on the top + of the stack. The stack is unchanged, so that the value is readily + available if the assignment is part of a larger expression. The + handling of @var{n} is as described for @code{getv}. + @item @code{trace} (0x0c): @var{addr} @var{size} @result{} Record the contents of the @var{size} bytes at @var{addr} in a trace buffer, for later retrieval by GDB. *************** Identical to trace_quick, except that @v *** 457,462 **** --- 475,484 ---- unsigned integer, not a single byte. This should probably have been named @code{trace_quick16}, for consistency. + @item @code{tracev} (0x2e) @var{n}: @result{} @var{a} + Record the value of trace state variable number @var{n} in the trace + buffer. The handling of @var{n} is as described for @code{getv}. + @item @code{end} (0x27): @result{} Stop executing bytecode; the result should be the top element of the stack. If the purpose of the expression was to compute an lvalue or a Index: doc/gdb.texinfo =================================================================== RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v retrieving revision 1.650 diff -p -r1.650 gdb.texinfo *** doc/gdb.texinfo 28 Dec 2009 21:29:53 -0000 1.650 --- doc/gdb.texinfo 28 Dec 2009 23:37:29 -0000 *************** conditions and actions. *** 9331,9336 **** --- 9331,9337 ---- * Enable and Disable Tracepoints:: * Tracepoint Passcounts:: * Tracepoint Conditions:: + * Trace State Variables:: * Tracepoint Actions:: * Listing Tracepoints:: * Starting and Stopping Trace Experiments:: *************** search through. *** 9497,9502 **** --- 9498,9556 ---- (@value{GDBP}) @kbd{trace normal_operation if errcode > 0} @end smallexample + @node Trace State Variables + @subsection Trace State Variables + @cindex trace state variables + + A @dfn{trace state variable} is a special type of variable that is + created and managed by target-side code. The syntax is the same as + that for GDB's convenience variables (a string prefixed with ``$''), + but they are stored on the target. They must be created explicitly, + using a @code{tvariable} command. They are always 64-bit signed + integers. + + Trace state variables are remembered by @value{GDBN}, and downloaded + to the target along with tracepoint information when the trace + experiment starts. There are no intrinsic limits on the number of + trace state variables, beyond memory limitations of the target. + + @cindex convenience variables, and trace state variables + Although trace state variables are managed by the target, you can use + them in print commands and expressions as if they were convenience + variables; @value{GDBN} will get the current value from the target + while the trace experiment is running. Trace state variables share + the same namespace as other ``$'' variables, which means that you + cannot have trace state variables with names like @code{$23} or + @code{$pc}, nor can you have a trace state variable and a convenience + variable with the same name. + + @table @code + + @item tvariable $@var{name} [ = @var{expression} ] + @kindex tvariable + The @code{tvariable} command creates a new trace state variable named + @code{$@var{name}}, and optionally gives it an initial value of + @var{expression}. @var{expression} is evaluated when this command is + entered; the result will be converted to an integer if possible, + otherwise @value{GDBN} will report an error. A subsequent + @code{tvariable} command specifying the same name does not create a + variable, but instead assigns the supplied initial value to the + existing variable of that name, overwriting any previous initial + value. The default initial value is 0. + + @item info tvariables + @kindex info tvariables + List all the trace state variables along with their initial values. + Their current values may also be displayed, if the trace experiment is + currently running. + + @item delete tvariable @r{[} $@var{name} @dots{} @r{]} + @kindex delete tvariable + Delete the given trace state variables, or all of them if no arguments + are specified. + + @end table + @node Tracepoint Actions @subsection Tracepoint Action Lists *************** use @code{output} instead. *** 9929,9935 **** Here's a simple example of using these convenience variables for stepping through all the trace snapshots and printing some of their ! data. @smallexample (@value{GDBP}) @b{tfind start} --- 9983,9990 ---- Here's a simple example of using these convenience variables for stepping through all the trace snapshots and printing some of their ! data. Note that these are not the same as trace state variables, ! which are managed by the target. @smallexample (@value{GDBP}) @b{tfind start} *************** The packet was understood and carried ou *** 29978,29983 **** --- 30033,30048 ---- The packet was not recognized. @end table + @item QTDV:@var{n}:@var{value} + @cindex define trace state variable, remote request + @cindex @samp{QTDV} packet + Create a new trace state variable, number @var{n}, with an initial + value of @var{value}, which is a 64-bit signed integer. Both @var{n} + and @var{value} are encoded as hexadecimal values. @value{GDBN} has + the option of not using this packet for initial values of zero; the + target should simply create the trace state variables as they are + mentioned in expressions. + @item QTFrame:@var{n} Select the @var{n}'th tracepoint frame from the buffer, and use the register and memory contents recorded there to answer subsequent *************** There is no trace experiment running. *** 30051,30058 **** --- 30116,30143 ---- There is a trace experiment running. @end table + @item qTV:@var{var} + @cindex trace state variable value, remote request + @cindex @samp{qTV} packet + Ask the stub for the value of the trace state variable number @var{var}. + + Replies: + @table @samp + @item V@var{value} + The value of the variable is @var{value}. This will be the current + value of the variable if the user is examining a running target, or a + saved value if the variable was collected in the trace frame that the + user is looking at. Note that multiple requests may result in + different reply values, such as when requesting values while the + program is running. + + @item U + The value of the variable is unknown. This would occur, for example, + if the user is examining a trace frame in which the requested variable + was not collected. @end table + @end table @node Host I/O Packets @section Host I/O Packets Index: testsuite/gdb.base/completion.exp =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.base/completion.exp,v retrieving revision 1.39 diff -p -r1.39 completion.exp *** testsuite/gdb.base/completion.exp 13 Jul 2009 19:24:18 -0000 1.39 --- testsuite/gdb.base/completion.exp 28 Dec 2009 23:37:29 -0000 *************** gdb_expect { *** 211,217 **** -re "^info t foo\\\x07$"\ { send_gdb "\n" gdb_expect { ! -re "Ambiguous info command \"t foo\": target, tasks, terminal, threads, tp, tracepoints, types\\..*$gdb_prompt $"\ { pass "complete 'info t foo'"} -re ".*$gdb_prompt $" { fail "complete 'info t foo'"} timeout {fail "(timeout) complete 'info t foo'"} --- 211,217 ---- -re "^info t foo\\\x07$"\ { send_gdb "\n" gdb_expect { ! -re "Ambiguous info command \"t foo\": target, tasks, terminal, threads, tp, tracepoints, tvariables, types\\..*$gdb_prompt $"\ { pass "complete 'info t foo'"} -re ".*$gdb_prompt $" { fail "complete 'info t foo'"} timeout {fail "(timeout) complete 'info t foo'"} *************** gdb_expect { *** 227,233 **** -re "^info t\\\x07$"\ { send_gdb "\n" gdb_expect { ! -re "Ambiguous info command \"t\": target, tasks, terminal, threads, tp, tracepoints, types\\.. *$gdb_prompt $"\ { pass "complete 'info t'"} -re ".*$gdb_prompt $" { fail "complete 'info t'"} --- 227,233 ---- -re "^info t\\\x07$"\ { send_gdb "\n" gdb_expect { ! -re "Ambiguous info command \"t\": target, tasks, terminal, threads, tp, tracepoints, tvariables, types\\.. *$gdb_prompt $"\ { pass "complete 'info t'"} -re ".*$gdb_prompt $" { fail "complete 'info t'"} *************** gdb_expect { *** 245,251 **** -re "^info t \\\x07$"\ { send_gdb "\n" gdb_expect { ! -re "Ambiguous info command \"t \": target, tasks, terminal, threads, tp, tracepoints, types\\.. *$gdb_prompt $"\ { pass "complete 'info t '"} -re ".*$gdb_prompt $" { fail "complete 'info t '"} --- 245,251 ---- -re "^info t \\\x07$"\ { send_gdb "\n" gdb_expect { ! -re "Ambiguous info command \"t \": target, tasks, terminal, threads, tp, tracepoints, tvariables, types\\.. *$gdb_prompt $"\ { pass "complete 'info t '"} -re ".*$gdb_prompt $" { fail "complete 'info t '"} Index: testsuite/gdb.trace/tsv.exp =================================================================== RCS file: testsuite/gdb.trace/tsv.exp diff -N testsuite/gdb.trace/tsv.exp *** /dev/null 1 Jan 1970 00:00:00 -0000 --- testsuite/gdb.trace/tsv.exp 28 Dec 2009 23:37:29 -0000 *************** *** 0 **** --- 1,107 ---- + # Copyright 2009 Free Software Foundation, Inc. + # + # This program is free software; you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by + # the Free Software Foundation; either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with this program. If not, see <http://www.gnu.org/licenses/>. + + load_lib "trace-support.exp"; + + if $tracelevel then { + strace $tracelevel + } + + set prms_id 0 + set bug_id 0 + + gdb_exit + gdb_start + set testfile "actions" + set srcfile ${testfile}.c + set binfile $objdir/$subdir/tsv + if { [gdb_compile "$srcdir/$subdir/$srcfile" $binfile \ + executable {debug nowarnings}] != "" } { + untested tracecmd.exp + return -1 + } + gdb_reinitialize_dir $srcdir/$subdir + + # If testing on a remote host, download the source file. + # remote_download host $srcdir/$subdir/$srcfile + + gdb_file_cmd $binfile + + gdb_test "tvariable \$tvar1" \ + "Trace state variable \\\$tvar1 created, with initial value 0." \ + "Create a trace state variable" + + gdb_test "tvariable \$tvar2 = 45" \ + "Trace state variable \\\$tvar2 created, with initial value 45." \ + "Create a trace state variable with initial value" + + gdb_test "tvariable \$tvar2 = -92" \ + "Trace state variable \\\$tvar2 now has initial value -92." \ + "Change initial value of a trace state variable" + + gdb_test "tvariable \$tvar3 = 2 + 3" \ + "Trace state variable \\\$tvar3 created, with initial value 5." \ + "Create a trace state variable with expression" + + gdb_test "tvariable \$tvar3 = 1234567000000" \ + "Trace state variable \\\$tvar3 now has initial value 1234567000000." \ + "Init trace state variable to a 64-bit value" + + gdb_test "tvariable main" \ + "Syntax must be \\\$NAME \\\[ = EXPR \\\]" \ + "tvariable syntax error, bad name" + + gdb_test "tvariable \$tvar1 - 93" \ + "Syntax must be \\\$NAME \\\[ = EXPR \\\]" \ + "tvariable syntax error, not an assignment" + + gdb_test "info tvariables" \ + "Name\[\t \]+Initial\[\t \]+Current.* + \\\$tvar1\[\t \]+0\[\t \]+<undefined>.* + \\\$tvar2\[\t \]+-92\[\t \]+<undefined>.* + \\\$tvar3\[\t \]+1234567000000\[\t \]+.*<undefined>.*" \ + "List tvariables" + + gdb_test "delete tvariable \$tvar2" \ + "" \ + "delete trace state variable" + + gdb_test "info tvariables" \ + "Name\[\t \]+Initial\[\t \]+Current.* + \\\$tvar1\[\t \]+0\[\t \]+<undefined>.* + \\\$tvar3\[\t \]+1234567000000\[\t \]+.*<undefined>.*" \ + "List tvariables after deletion" + + send_gdb "delete tvariable\n" + gdb_expect 30 { + -re "Delete all trace state variables.*y or n.*$" { + send_gdb "y\n" + gdb_expect 30 { + -re "$gdb_prompt $" { + pass "Delete all trace state variables" + } + timeout { fail "Delete all trace state variables (timeout)" } + } + } + -re "$gdb_prompt $" { # This happens if there were no variables + } + timeout { perror "Delete all trace state variables (timeout)" ; return } + } + + gdb_test "info tvariables" \ + "No trace state variables.*" \ + "List tvariables after deleting all" + + ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2009-12-29 17:21 UTC | newest] Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2009-12-15 13:51 [PATCH] Trace state variables Stan Shebs 2009-12-15 15:53 ` Eli Zaretskii 2009-12-15 19:04 ` Stan Shebs 2009-12-15 19:17 ` Tom Tromey 2009-12-18 20:03 ` Stan Shebs 2009-12-18 20:47 ` Tom Tromey 2009-12-29 17:21 ` Stan Shebs
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox