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]

[PATCH] Trace state variables


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.

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

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