This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Trace state variables


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.

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);
  
*************** 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"));
+     }
+ }
  
  
  /* 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;
+ }
  
  
  
*************** 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);
  
  
  /* 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"
+ 
+ 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]