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.

==> doc/ChangeLog <==
2009-12-28  Stan Shebs  <stan@codesourcery.com>

	* gdb.texinfo (Trace State Variables): New section.
	(Tracepoint Packets): Describe trace state variable packets.
	* agentexpr.texi (Bytecode Descriptions): Describe trace state
	variable bytecodes.

==> testsuite/ChangeLog <==
2009-12-28  Stan Shebs  <stan@codesourcery.com>

	* gdb.trace/tsv.exp: New file.
	* gdb.base/completion.exp: Update ambiguous info output.
This commit is contained in:
Stan Shebs 2009-12-28 23:39:10 +00:00
parent ae77ee9a7f
commit f61e138d9a
13 changed files with 792 additions and 120 deletions

View file

@ -1,3 +1,29 @@
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.
2009-12-28 Daniel Jacobowitz <dan@codesourcery.com>
* NEWS: Document "info variables" change.

View file

@ -24,6 +24,19 @@ Renesas RX rx
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
@ -75,6 +88,15 @@ set remotebreak [on | off]
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
@ -83,6 +105,14 @@ show follow-exec-mode
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.

View file

@ -36,6 +36,7 @@
#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,
@ -139,6 +140,12 @@ static void gen_sizeof (struct expression *exp, union exp_element **pc,
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);
@ -1441,7 +1448,7 @@ gen_expr (struct expression *exp, union exp_element **pc,
{
/* Used to hold the descriptions of operand expressions. */
struct axs_value value1, value2;
enum exp_opcode op = (*pc)[0].opcode;
enum exp_opcode op = (*pc)[0].opcode, op2;
/* If we're looking at a constant expression, just push its value. */
{
@ -1478,119 +1485,63 @@ gen_expr (struct expression *exp, union exp_element **pc,
(*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)
gen_expr_binop_rest (exp, op, pc, ax, value, &value1, &value2);
break;
case BINOP_ASSIGN:
(*pc)++;
if ((*pc)[0].opcode == OP_INTERNALVAR)
{
case BINOP_ADD:
if (TYPE_CODE (value1.type) == TYPE_CODE_INT
&& TYPE_CODE (value2.type) == TYPE_CODE_PTR)
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)
{
/* Swap the values and proceed normally. */
ax_simple (ax, aop_swap);
gen_ptradd (ax, value, &value2, &value1);
ax_tsv (ax, aop_setv, tsv->number);
if (trace_kludge)
ax_tsv (ax, aop_tracev, tsv->number);
}
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"));
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
@ -1644,7 +1595,24 @@ gen_expr (struct expression *exp, union exp_element **pc,
break;
case OP_INTERNALVAR:
error (_("GDB agent expressions cannot use convenience variables."));
{
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:
@ -1788,6 +1756,131 @@ gen_expr (struct expression *exp, union exp_element **pc,
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"));
}
}
/* Given a single variable and a scope, generate bytecodes to trace

View file

@ -272,6 +272,22 @@ ax_reg (struct agent_expr *x, int reg)
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;
}
@ -324,9 +340,9 @@ struct aop_map aop_map[] =
{"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 */
{"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 */
};

View file

@ -131,6 +131,9 @@ enum agent_op
aop_pop = 0x29,
aop_zero_ext = 0x2a,
aop_swap = 0x2b,
aop_getv = 0x2c,
aop_setv = 0x2d,
aop_tracev = 0x2e,
aop_trace16 = 0x30,
aop_last
};
@ -182,6 +185,9 @@ extern void ax_const_d (struct agent_expr *EXPR, LONGEST d);
/* 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);
/* Functions for printing out expressions, and otherwise debugging

View file

@ -1,3 +1,10 @@
2009-12-28 Stan Shebs <stan@codesourcery.com>
* gdb.texinfo (Trace State Variables): New section.
(Tracepoint Packets): Describe trace state variable packets.
* agentexpr.texi (Bytecode Descriptions): Describe trace state
variable bytecodes.
2009-12-28 Daniel Jacobowitz <dan@codesourcery.com>
* gdb.texinfo (Symbols): "info variables" prints definitions, not

View file

@ -440,6 +440,24 @@ 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{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.
@ -457,6 +475,10 @@ Identical to trace_quick, except that @var{size} is a 16-bit big-endian
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

View file

@ -9331,6 +9331,7 @@ conditions and actions.
* Enable and Disable Tracepoints::
* Tracepoint Passcounts::
* Tracepoint Conditions::
* Trace State Variables::
* Tracepoint Actions::
* Listing Tracepoints::
* Starting and Stopping Trace Experiments::
@ -9497,6 +9498,59 @@ search through.
(@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
@ -9929,7 +9983,8 @@ use @code{output} instead.
Here's a simple example of using these convenience variables for
stepping through all the trace snapshots and printing some of their
data.
data. Note that these are not the same as trace state variables,
which are managed by the target.
@smallexample
(@value{GDBP}) @b{tfind start}
@ -29978,6 +30033,16 @@ The packet was understood and carried out.
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
@ -30051,8 +30116,28 @@ There is no trace experiment running.
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

View file

@ -1,3 +1,8 @@
2009-12-28 Stan Shebs <stan@codesourcery.com>
* gdb.trace/tsv.exp: New file.
* gdb.base/completion.exp: Update ambiguous info output.
2009-12-28 Daniel Jacobowitz <dan@codesourcery.com>
* gdb.base/find.c (main): Reference search buffers.

View file

@ -211,7 +211,7 @@ gdb_expect {
-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 $"\
-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'"}
@ -227,7 +227,7 @@ gdb_expect {
-re "^info t\\\x07$"\
{ send_gdb "\n"
gdb_expect {
-re "Ambiguous info command \"t\": target, tasks, terminal, threads, tp, tracepoints, types\\..
-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'"}
@ -245,7 +245,7 @@ gdb_expect {
-re "^info t \\\x07$"\
{ send_gdb "\n"
gdb_expect {
-re "Ambiguous info command \"t \": target, tasks, terminal, threads, tp, tracepoints, types\\..
-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 '"}

View file

@ -0,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"

View file

@ -34,6 +34,7 @@
#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"
@ -111,6 +112,19 @@ extern void output_command (char *, int);
/* ======= 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;
@ -126,6 +140,9 @@ static struct symtab_and_line traceframe_sal;
/* 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);
@ -274,6 +291,205 @@ set_traceframe_context (struct frame_info *trace_frame)
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 */
@ -1254,9 +1470,6 @@ add_aexpr (struct collection_list *collect, struct agent_expr *aexpr)
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
@ -1312,9 +1525,11 @@ void download_tracepoint (struct breakpoint *t);
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. */
@ -1332,6 +1547,19 @@ trace_start_command (char *args, int from_tty)
}
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. */
@ -2235,6 +2463,23 @@ _initialize_tracepoint (void)
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."),

View file

@ -35,6 +35,34 @@ enum actionline_type
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. */
@ -49,4 +77,6 @@ enum actionline_type validate_actionline (char **, struct breakpoint *);
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 */