summaryrefslogtreecommitdiff
path: root/gdb/tracepoint.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/tracepoint.c')
-rw-r--r--gdb/tracepoint.c251
1 files changed, 248 insertions, 3 deletions
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 87e78821269..702d348badf 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -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."),