static int disconnected_tracing;
+/* This variable controls whether we ask the target for a linear or
+ circular trace buffer. */
+
+static int circular_trace_buffer;
+
/* ======= Important command functions: ======= */
static void trace_actions_command (char *, int);
static void trace_start_command (char *, int);
static char *mem2hex (gdb_byte *, char *, int);
static void add_register (struct collection_list *collection,
unsigned int regno);
-static struct cleanup *make_cleanup_free_actions (struct breakpoint *t);
extern void send_disconnected_tracing_value (int value);
"tstop",
"tfull",
"tdisconnected",
- "tpasscount"
+ "tpasscount",
+ "terror"
};
struct trace_status *
struct trace_state_variable tsv;
memset (&tsv, 0, sizeof (tsv));
- tsv.name = name;
+ tsv.name = xstrdup (name);
tsv.number = next_tsv_number++;
return VEC_safe_push (tsv_s, tvariables, &tsv);
}
for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
if (strcmp (name, tsv->name) == 0)
{
+ xfree ((void *)tsv->name);
VEC_unordered_remove (tsv_s, tvariables, ix);
return;
}
dont_repeat ();
}
-/* List all the trace state variables. */
-
-static void
-tvariables_info (char *args, int from_tty)
+void
+tvariables_info_1 (void)
{
struct trace_state_variable *tsv;
int ix;
- char *reply;
- ULONGEST tval;
+ int count = 0;
+ struct cleanup *back_to;
- if (VEC_length (tsv_s, tvariables) == 0)
+ if (VEC_length (tsv_s, tvariables) == 0 && !ui_out_is_mi_like_p (uiout))
{
printf_filtered (_("No trace state variables.\n"));
return;
}
/* Try to acquire values from the target. */
- for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
+ for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix, ++count)
tsv->value_known = target_get_trace_state_variable_value (tsv->number,
&(tsv->value));
- printf_filtered (_("Name\t\t Initial\tCurrent\n"));
+ back_to = make_cleanup_ui_out_table_begin_end (uiout, 3,
+ count, "trace-variables");
+ ui_out_table_header (uiout, 15, ui_left, "name", "Name");
+ ui_out_table_header (uiout, 11, ui_left, "initial", "Initial");
+ ui_out_table_header (uiout, 11, ui_left, "current", "Current");
+
+ ui_out_table_body (uiout);
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);
+ struct cleanup *back_to2;
+ char *c;
+ char *name;
+
+ back_to2 = make_cleanup_ui_out_tuple_begin_end (uiout, "variable");
+
+ name = concat ("$", tsv->name, NULL);
+ make_cleanup (xfree, name);
+ ui_out_field_string (uiout, "name", name);
+ ui_out_field_string (uiout, "initial", plongest (tsv->initial_value));
+
if (tsv->value_known)
- printf_filtered (" %s", plongest (tsv->value));
+ c = plongest (tsv->value);
+ else if (ui_out_is_mi_like_p (uiout))
+ /* For MI, we prefer not to use magic string constants, but rather
+ omit the field completely. The difference between unknown and
+ undefined does not seem important enough to represent. */
+ c = NULL;
else if (current_trace_status ()->running || traceframe_number >= 0)
/* The value is/was defined, but we don't have it. */
- printf_filtered (_(" <unknown>"));
+ c = "<unknown>";
else
/* It is not meaningful to ask about the value. */
- printf_filtered (_(" <undefined>"));
- printf_filtered ("\n");
+ c = "<undefined>";
+ if (c)
+ ui_out_field_string (uiout, "current", c);
+ ui_out_text (uiout, "\n");
+
+ do_cleanups (back_to2);
}
+
+ do_cleanups (back_to);
}
-/* ACTIONS functions: */
+/* List all the trace state variables. */
-/* Prototypes for action-parsing utility commands */
-static void read_actions (struct breakpoint *);
+static void
+tvariables_info (char *args, int from_tty)
+{
+ tvariables_info_1 ();
+}
+
+/* ACTIONS functions: */
/* The three functions:
collect_pseudocommand,
trace_actions_command (char *args, int from_tty)
{
struct breakpoint *t;
- char tmpbuf[128];
- char *end_msg = "End with a line saying just \"end\".";
+ struct command_line *l;
t = get_tracepoint_by_number (&args, 0, 1);
if (t)
{
- sprintf (tmpbuf, "Enter actions for tracepoint %d, one per line.",
- t->number);
-
- if (from_tty)
- {
- if (deprecated_readline_begin_hook)
- (*deprecated_readline_begin_hook) ("%s %s\n", tmpbuf, end_msg);
- else if (input_from_terminal_p ())
- printf_filtered ("%s\n%s\n", tmpbuf, end_msg);
- }
+ char *tmpbuf =
+ xstrprintf ("Enter actions for tracepoint %d, one per line.",
+ t->number);
+ struct cleanup *cleanups = make_cleanup (xfree, tmpbuf);
- free_actions (t);
- t->step_count = 0; /* read_actions may set this */
- read_actions (t);
-
- if (deprecated_readline_end_hook)
- (*deprecated_readline_end_hook) ();
- /* tracepoints_changed () */
+ l = read_command_lines (tmpbuf, from_tty, 1, check_tracepoint_command, t);
+ do_cleanups (cleanups);
+ breakpoint_set_commands (t, l);
}
/* else just return */
}
-/* worker function */
-static void
-read_actions (struct breakpoint *t)
-{
- char *line;
- char *prompt1 = "> ", *prompt2 = " > ";
- char *prompt = prompt1;
- enum actionline_type linetype;
- extern FILE *instream;
- struct action_line *next = NULL, *temp;
- struct cleanup *old_chain;
-
- /* Control-C quits instantly if typed while in this loop
- since it should not wait until the user types a newline. */
- immediate_quit++;
- /* FIXME: kettenis/20010823: Something is wrong here. In this file
- STOP_SIGNAL is never defined. So this code has been left out, at
- least for quite a while now. Replacing STOP_SIGNAL with SIGTSTP
- leads to compilation failures since the variable job_control
- isn't declared. Leave this alone for now. */
-#ifdef STOP_SIGNAL
- if (job_control)
- signal (STOP_SIGNAL, handle_stop_sig);
-#endif
- old_chain = make_cleanup_free_actions (t);
- while (1)
- {
- /* Make sure that all output has been output. Some machines may
- let you get away with leaving out some of the gdb_flush, but
- not all. */
- wrap_here ("");
- gdb_flush (gdb_stdout);
- gdb_flush (gdb_stderr);
-
- if (deprecated_readline_hook && instream == NULL)
- line = (*deprecated_readline_hook) (prompt);
- else if (instream == stdin && ISATTY (instream))
- {
- line = gdb_readline_wrapper (prompt);
- if (line && *line) /* add it to command history */
- add_history (line);
- }
- else
- line = gdb_readline (0);
-
- if (!line)
- {
- line = xstrdup ("end");
- printf_filtered ("end\n");
- }
-
- linetype = validate_actionline (&line, t);
- if (linetype == BADLINE)
- continue; /* already warned -- collect another line */
-
- temp = xmalloc (sizeof (struct action_line));
- temp->next = NULL;
- temp->action = line;
-
- if (next == NULL) /* first action for this tracepoint? */
- t->actions = next = temp;
- else
- {
- next->next = temp;
- next = temp;
- }
-
- if (linetype == STEPPING) /* begin "while-stepping" */
- {
- if (prompt == prompt2)
- {
- warning (_("Already processing 'while-stepping'"));
- continue;
- }
- else
- prompt = prompt2; /* change prompt for stepping actions */
- }
- else if (linetype == END)
- {
- if (prompt == prompt2)
- {
- prompt = prompt1; /* end of single-stepping actions */
- }
- else
- { /* end of actions */
- if (t->actions->next == NULL)
- {
- /* An "end" all by itself with no other actions
- means this tracepoint has no actions.
- Discard empty list. */
- free_actions (t);
- }
- break;
- }
- }
- }
-#ifdef STOP_SIGNAL
- if (job_control)
- signal (STOP_SIGNAL, SIG_DFL);
-#endif
- immediate_quit--;
- discard_cleanups (old_chain);
-}
-
/* worker function */
enum actionline_type
validate_actionline (char **line, struct breakpoint *t)
struct cmd_list_element *c;
struct expression *exp = NULL;
struct cleanup *old_chain = NULL;
- char *p;
+ char *p, *tmp_p;
+ struct bp_location *loc;
/* if EOF is typed, *line is NULL */
if (*line == NULL)
}
/* else fall thru, treat p as an expression and parse it! */
}
- exp = parse_exp_1 (&p, block_for_pc (t->loc->address), 1);
- old_chain = make_cleanup (free_current_contents, &exp);
-
- if (exp->elts[0].opcode == OP_VAR_VALUE)
+ tmp_p = p;
+ for (loc = t->loc; loc; loc = loc->next)
{
- if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_CONST)
- {
- warning (_("constant %s (value %ld) will not be collected."),
- SYMBOL_PRINT_NAME (exp->elts[2].symbol),
- SYMBOL_VALUE (exp->elts[2].symbol));
- return BADLINE;
- }
- else if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_OPTIMIZED_OUT)
+ p = tmp_p;
+ exp = parse_exp_1 (&p, block_for_pc (loc->address), 1);
+ old_chain = make_cleanup (free_current_contents, &exp);
+
+ if (exp->elts[0].opcode == OP_VAR_VALUE)
{
- warning (_("%s is optimized away and cannot be collected."),
- SYMBOL_PRINT_NAME (exp->elts[2].symbol));
- return BADLINE;
+ if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_CONST)
+ {
+ warning (_("constant %s (value %ld) will not be collected."),
+ SYMBOL_PRINT_NAME (exp->elts[2].symbol),
+ SYMBOL_VALUE (exp->elts[2].symbol));
+ return BADLINE;
+ }
+ else if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_OPTIMIZED_OUT)
+ {
+ warning (_("%s is optimized away and cannot be collected."),
+ SYMBOL_PRINT_NAME (exp->elts[2].symbol));
+ return BADLINE;
+ }
}
- }
- /* We have something to collect, make sure that the expr to
- bytecode translator can handle it and that it's not too
- long. */
- aexpr = gen_trace_for_expr (t->loc->address, exp);
- make_cleanup_free_agent_expr (aexpr);
+ /* We have something to collect, make sure that the expr to
+ bytecode translator can handle it and that it's not too
+ long. */
+ aexpr = gen_trace_for_expr (loc->address, exp);
+ make_cleanup_free_agent_expr (aexpr);
- if (aexpr->len > MAX_AGENT_EXPR_LEN)
- error (_("expression too complicated, try simplifying"));
+ if (aexpr->len > MAX_AGENT_EXPR_LEN)
+ error (_("expression too complicated, try simplifying"));
- ax_reqs (aexpr, &areqs);
- (void) make_cleanup (xfree, areqs.reg_mask);
+ ax_reqs (aexpr, &areqs);
+ (void) make_cleanup (xfree, areqs.reg_mask);
- if (areqs.flaw != agent_flaw_none)
- error (_("malformed expression"));
+ if (areqs.flaw != agent_flaw_none)
+ error (_("malformed expression"));
- if (areqs.min_height < 0)
- error (_("gdb: Internal error: expression has min height < 0"));
+ if (areqs.min_height < 0)
+ error (_("gdb: Internal error: expression has min height < 0"));
- if (areqs.max_height > 20)
- error (_("expression too complicated, try simplifying"));
+ if (areqs.max_height > 20)
+ error (_("expression too complicated, try simplifying"));
- do_cleanups (old_chain);
+ do_cleanups (old_chain);
+ }
}
while (p && *p++ == ',');
return GENERIC;
while (isspace ((int) *p))
p++;
- /* Only expressions are allowed for this action. */
- exp = parse_exp_1 (&p, block_for_pc (t->loc->address), 1);
- old_chain = make_cleanup (free_current_contents, &exp);
+ tmp_p = p;
+ for (loc = t->loc; loc; loc = loc->next)
+ {
+ p = tmp_p;
+ /* Only expressions are allowed for this action. */
+ exp = parse_exp_1 (&p, block_for_pc (loc->address), 1);
+ old_chain = make_cleanup (free_current_contents, &exp);
- /* We have something to evaluate, make sure that the expr to
- bytecode translator can handle it and that it's not too
- long. */
- aexpr = gen_eval_for_expr (t->loc->address, exp);
- make_cleanup_free_agent_expr (aexpr);
+ /* We have something to evaluate, make sure that the expr to
+ bytecode translator can handle it and that it's not too
+ long. */
+ aexpr = gen_eval_for_expr (loc->address, exp);
+ make_cleanup_free_agent_expr (aexpr);
- if (aexpr->len > MAX_AGENT_EXPR_LEN)
- error (_("expression too complicated, try simplifying"));
+ if (aexpr->len > MAX_AGENT_EXPR_LEN)
+ error (_("expression too complicated, try simplifying"));
- do_cleanups (old_chain);
+ do_cleanups (old_chain);
+ }
}
while (p && *p++ == ',');
return GENERIC;
if (*p == '\0' ||
(t->step_count = strtol (p, &p, 0)) == 0)
{
- warning (_("'%s': bad step-count; command ignored."), *line);
- return BADLINE;
+ error (_("'%s': bad step-count."), *line);
}
return STEPPING;
}
return END;
else
{
- warning (_("'%s' is not a supported tracepoint action."), *line);
- return BADLINE;
+ error (_("'%s' is not a supported tracepoint action."), *line);
}
}
-/* worker function */
-void
-free_actions (struct breakpoint *t)
-{
- struct action_line *line, *next;
-
- for (line = t->actions; line; line = next)
- {
- next = line->next;
- if (line->action)
- xfree (line->action);
- xfree (line);
- }
- t->actions = NULL;
-}
-
-static void
-do_free_actions_cleanup (void *t)
-{
- free_actions (t);
-}
-
-static struct cleanup *
-make_cleanup_free_actions (struct breakpoint *t)
-{
- return make_cleanup (do_free_actions_cleanup, t);
-}
-
enum {
memrange_absolute = -1
};
unsigned long len;
unsigned int reg;
bfd_signed_vma offset;
+ int treat_as_expr = 0;
len = TYPE_LENGTH (check_typedef (SYMBOL_TYPE (sym)));
switch (SYMBOL_CLASS (sym))
SYMBOL_PRINT_NAME (sym), len,
tmp /* address */);
}
- add_memrange (collect, memrange_absolute, offset, len);
+ /* A struct may be a C++ class with static fields, go to general
+ expression handling. */
+ if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT)
+ treat_as_expr = 1;
+ else
+ add_memrange (collect, memrange_absolute, offset, len);
break;
case LOC_REGISTER:
reg = SYMBOL_REGISTER_OPS (sym)->register_number (sym, gdbarch);
}
add_memrange (collect, reg, offset, len);
break;
+
case LOC_UNRESOLVED:
- printf_filtered ("Don't know LOC_UNRESOLVED %s\n",
- SYMBOL_PRINT_NAME (sym));
+ treat_as_expr = 1;
break;
+
case LOC_OPTIMIZED_OUT:
printf_filtered ("%s has been optimized out of existence.\n",
SYMBOL_PRINT_NAME (sym));
break;
case LOC_COMPUTED:
- {
- struct agent_expr *aexpr;
- struct cleanup *old_chain1 = NULL;
- struct agent_reqs areqs;
-
- aexpr = gen_trace_for_var (scope, sym);
-
- old_chain1 = make_cleanup_free_agent_expr (aexpr);
-
- ax_reqs (aexpr, &areqs);
- if (areqs.flaw != agent_flaw_none)
- error (_("malformed expression"));
-
- if (areqs.min_height < 0)
- error (_("gdb: Internal error: expression has min height < 0"));
- if (areqs.max_height > 20)
- error (_("expression too complicated, try simplifying"));
-
- discard_cleanups (old_chain1);
- add_aexpr (collect, aexpr);
-
- /* take care of the registers */
- if (areqs.reg_mask_len > 0)
- {
- int ndx1, ndx2;
-
- for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++)
- {
- QUIT; /* allow user to bail out with ^C */
- if (areqs.reg_mask[ndx1] != 0)
- {
- /* assume chars have 8 bits */
- for (ndx2 = 0; ndx2 < 8; ndx2++)
- if (areqs.reg_mask[ndx1] & (1 << ndx2))
- /* it's used -- record it */
- add_register (collect,
- ndx1 * 8 + ndx2);
- }
- }
- }
- }
+ treat_as_expr = 1;
break;
}
+
+ /* Expressions are the most general case. */
+ if (treat_as_expr)
+ {
+ struct agent_expr *aexpr;
+ struct cleanup *old_chain1 = NULL;
+ struct agent_reqs areqs;
+
+ aexpr = gen_trace_for_var (scope, gdbarch, sym);
+
+ /* It can happen that the symbol is recorded as a computed
+ location, but it's been optimized away and doesn't actually
+ have a location expression. */
+ if (!aexpr)
+ {
+ printf_filtered ("%s has been optimized out of existence.\n",
+ SYMBOL_PRINT_NAME (sym));
+ return;
+ }
+
+ old_chain1 = make_cleanup_free_agent_expr (aexpr);
+
+ ax_reqs (aexpr, &areqs);
+ if (areqs.flaw != agent_flaw_none)
+ error (_("malformed expression"));
+
+ if (areqs.min_height < 0)
+ error (_("gdb: Internal error: expression has min height < 0"));
+ if (areqs.max_height > 20)
+ error (_("expression too complicated, try simplifying"));
+
+ discard_cleanups (old_chain1);
+ add_aexpr (collect, aexpr);
+
+ /* take care of the registers */
+ if (areqs.reg_mask_len > 0)
+ {
+ int ndx1, ndx2;
+
+ for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++)
+ {
+ QUIT; /* allow user to bail out with ^C */
+ if (areqs.reg_mask[ndx1] != 0)
+ {
+ /* assume chars have 8 bits */
+ for (ndx2 = 0; ndx2 < 8; ndx2++)
+ if (areqs.reg_mask[ndx1] & (1 << ndx2))
+ /* it's used -- record it */
+ add_register (collect, ndx1 * 8 + ndx2);
+ }
+ }
+ }
+ }
}
/* Add all locals (or args) symbols to collection list */
return *str_list;
}
-/* Render all actions into gdb protocol. */
-/*static*/ void
-encode_actions (struct breakpoint *t, char ***tdp_actions,
- char ***stepping_actions)
+
+static void
+encode_actions_1 (struct command_line *action,
+ struct breakpoint *t,
+ struct bp_location *tloc,
+ int frame_reg,
+ LONGEST frame_offset,
+ struct collection_list *collect,
+ struct collection_list *stepping_list)
{
- static char tdp_buff[2048], step_buff[2048];
char *action_exp;
struct expression *exp = NULL;
- struct action_line *action;
+ struct command_line *actions;
int i;
struct value *tempval;
- struct collection_list *collect;
struct cmd_list_element *cmd;
struct agent_expr *aexpr;
- int frame_reg;
- LONGEST frame_offset;
- char *default_collect_line = NULL;
- struct action_line *default_collect_action = NULL;
-
- clear_collection_list (&tracepoint_list);
- clear_collection_list (&stepping_list);
- collect = &tracepoint_list;
-
- *tdp_actions = NULL;
- *stepping_actions = NULL;
-
- gdbarch_virtual_frame_pointer (t->gdbarch,
- t->loc->address, &frame_reg, &frame_offset);
-
- action = t->actions;
-
- /* If there are default expressions to collect, make up a collect
- action and prepend to the action list to encode. Note that since
- validation is per-tracepoint (local var "xyz" might be valid for
- one tracepoint and not another, etc), we make up the action on
- the fly, and don't cache it. */
- if (*default_collect)
- {
- char *line;
- enum actionline_type linetype;
-
- default_collect_line = xmalloc (12 + strlen (default_collect));
- sprintf (default_collect_line, "collect %s", default_collect);
- line = default_collect_line;
- linetype = validate_actionline (&line, t);
- if (linetype != BADLINE)
- {
- default_collect_action = xmalloc (sizeof (struct action_line));
- default_collect_action->next = t->actions;
- default_collect_action->action = line;
- action = default_collect_action;
- }
- }
for (; action; action = action->next)
{
QUIT; /* allow user to bail out with ^C */
- action_exp = action->action;
+ action_exp = action->line;
while (isspace ((int) *action_exp))
action_exp++;
- if (*action_exp == '#') /* comment line */
- return;
-
cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
if (cmd == 0)
error (_("Bad action list item: %s"), action_exp);
{
add_local_symbols (collect,
t->gdbarch,
- t->loc->address,
+ tloc->address,
frame_reg,
frame_offset,
'A');
{
add_local_symbols (collect,
t->gdbarch,
- t->loc->address,
+ tloc->address,
frame_reg,
frame_offset,
'L');
struct agent_reqs areqs;
exp = parse_exp_1 (&action_exp,
- block_for_pc (t->loc->address), 1);
+ block_for_pc (tloc->address), 1);
old_chain = make_cleanup (free_current_contents, &exp);
switch (exp->elts[0].opcode)
t->gdbarch,
frame_reg,
frame_offset,
- t->loc->address);
+ tloc->address);
break;
default: /* full-fledged expression */
- aexpr = gen_trace_for_expr (t->loc->address, exp);
+ aexpr = gen_trace_for_expr (tloc->address, exp);
old_chain1 = make_cleanup_free_agent_expr (aexpr);
struct agent_reqs areqs;
exp = parse_exp_1 (&action_exp,
- block_for_pc (t->loc->address), 1);
+ block_for_pc (tloc->address), 1);
old_chain = make_cleanup (free_current_contents, &exp);
- aexpr = gen_eval_for_expr (t->loc->address, exp);
+ aexpr = gen_eval_for_expr (tloc->address, exp);
old_chain1 = make_cleanup_free_agent_expr (aexpr);
ax_reqs (aexpr, &areqs);
} /* if */
else if (cmd_cfunc_eq (cmd, while_stepping_pseudocommand))
{
- collect = &stepping_list;
+ /* We check against nested while-stepping when setting
+ breakpoint action, so no way to run into nested
+ here. */
+ gdb_assert (stepping_list);
+
+ encode_actions_1 (action->body_list[0], t, tloc, frame_reg, frame_offset,
+ stepping_list, NULL);
}
- else if (cmd_cfunc_eq (cmd, end_actions_pseudocommand))
+ else
+ error (_("Invalid tracepoint command '%s'"), action->line);
+ } /* for */
+}
+
+/* Render all actions into gdb protocol. */
+/*static*/ void
+encode_actions (struct breakpoint *t, struct bp_location *tloc,
+ char ***tdp_actions, char ***stepping_actions)
+{
+ static char tdp_buff[2048], step_buff[2048];
+ char *default_collect_line = NULL;
+ struct command_line *actions;
+ struct command_line *default_collect_action = NULL;
+ int frame_reg;
+ LONGEST frame_offset;
+ struct cleanup *back_to;
+
+ back_to = make_cleanup (null_cleanup, NULL);
+
+ clear_collection_list (&tracepoint_list);
+ clear_collection_list (&stepping_list);
+
+ *tdp_actions = NULL;
+ *stepping_actions = NULL;
+
+ gdbarch_virtual_frame_pointer (t->gdbarch,
+ t->loc->address, &frame_reg, &frame_offset);
+
+ actions = t->commands->commands;
+
+ /* If there are default expressions to collect, make up a collect
+ action and prepend to the action list to encode. Note that since
+ validation is per-tracepoint (local var "xyz" might be valid for
+ one tracepoint and not another, etc), we make up the action on
+ the fly, and don't cache it. */
+ if (*default_collect)
+ {
+ char *line;
+ enum actionline_type linetype;
+
+ default_collect_line = xstrprintf ("collect %s", default_collect);
+ make_cleanup (xfree, default_collect_line);
+
+ line = default_collect_line;
+ linetype = validate_actionline (&line, t);
+ if (linetype != BADLINE)
{
- if (collect == &stepping_list) /* end stepping actions */
- collect = &tracepoint_list;
- else
- break; /* end tracepoint actions */
+ default_collect_action = xmalloc (sizeof (struct command_line));
+ make_cleanup (xfree, default_collect_action);
+ default_collect_action->next = t->commands->commands;
+ default_collect_action->line = line;
+ actions = default_collect_action;
}
- } /* for */
+ }
+ encode_actions_1 (actions, t, tloc, frame_reg, frame_offset,
+ &tracepoint_list, &stepping_list);
+
memrange_sortmerge (&tracepoint_list);
memrange_sortmerge (&stepping_list);
- *tdp_actions = stringify_collection_list (&tracepoint_list,
+ *tdp_actions = stringify_collection_list (&tracepoint_list,
tdp_buff);
- *stepping_actions = stringify_collection_list (&stepping_list,
+ *stepping_actions = stringify_collection_list (&stepping_list,
step_buff);
- xfree (default_collect_line);
- xfree (default_collect_action);
+ do_cleanups (back_to);
}
static void
collect->next_aexpr_elt++;
}
-/* tstart command:
- Tell target to clear any previous trace experiment.
- Walk the list of tracepoints, and send them (and their actions)
- to the target. If no errors,
- Tell target to start a new trace experiment. */
-
-static void
-trace_start_command (char *args, int from_tty)
+void
+start_tracing (void)
{
char buf[2048];
VEC(breakpoint_p) *tp_vec = NULL;
int ix;
struct breakpoint *t;
struct trace_state_variable *tsv;
- int any_downloaded = 0;
+ int any_enabled = 0;
+
+ tp_vec = all_tracepoints ();
- dont_repeat (); /* Like "run", dangerous to repeat accidentally. */
+ /* No point in tracing without any tracepoints... */
+ if (VEC_length (breakpoint_p, tp_vec) == 0)
+ {
+ VEC_free (breakpoint_p, tp_vec);
+ error (_("No tracepoints defined, not starting trace"));
+ }
+
+ for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
+ {
+ if (t->enable_state == bp_enabled)
+ {
+ any_enabled = 1;
+ break;
+ }
+ }
+
+ /* No point in tracing with only disabled tracepoints. */
+ if (!any_enabled)
+ {
+ VEC_free (breakpoint_p, tp_vec);
+ error (_("No tracepoints enabled, not starting trace"));
+ }
target_trace_init ();
-
- tp_vec = all_tracepoints ();
+
for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
{
t->number_on_target = 0;
target_download_tracepoint (t);
t->number_on_target = t->number;
- any_downloaded = 1;
}
VEC_free (breakpoint_p, tp_vec);
-
- /* No point in tracing without any tracepoints... */
- if (!any_downloaded)
- error ("No tracepoints downloaded, not starting trace");
-
+
/* Send down all the trace state variables too. */
for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
{
/* Tell target to treat text-like sections as transparent. */
target_trace_set_readonly_regions ();
+ /* Set some mode flags. */
+ target_set_disconnected_tracing (disconnected_tracing);
+ target_set_circular_trace_buffer (circular_trace_buffer);
/* Now insert traps and begin collecting data. */
target_trace_start ();
current_trace_status()->running = 1;
}
+/* tstart command:
+
+ Tell target to clear any previous trace experiment.
+ Walk the list of tracepoints, and send them (and their actions)
+ to the target. If no errors,
+ Tell target to start a new trace experiment. */
+
+static void
+trace_start_command (char *args, int from_tty)
+{
+ dont_repeat (); /* Like "run", dangerous to repeat accidentally. */
+
+ start_tracing ();
+}
+
/* tstop command */
static void
trace_stop_command (char *args, int from_tty)
}
void
-stop_tracing ()
+stop_tracing (void)
{
target_trace_stop ();
/* should change in response to reply? */
printf_filtered (_("Trace stopped because of disconnection.\n"));
break;
case tracepoint_passcount:
- /* FIXME account for number on target */
printf_filtered (_("Trace stopped by tracepoint %d.\n"),
ts->stopping_tracepoint);
break;
+ case tracepoint_error:
+ if (ts->stopping_tracepoint)
+ printf_filtered (_("Trace stopped by an error (%s, tracepoint %d).\n"),
+ ts->error_desc, ts->stopping_tracepoint);
+ else
+ printf_filtered (_("Trace stopped by an error (%s).\n"),
+ ts->error_desc);
+ break;
case trace_stop_reason_unknown:
printf_filtered (_("Trace stopped for an unknown reason.\n"));
break;
}
}
- if (ts->traceframe_count >= 0)
+ if (ts->traceframes_created >= 0
+ && ts->traceframe_count != ts->traceframes_created)
+ {
+ printf_filtered (_("Buffer contains %d trace frames (of %d created total).\n"),
+ ts->traceframe_count, ts->traceframes_created);
+ }
+ else if (ts->traceframe_count >= 0)
{
printf_filtered (_("Collected %d trace frames.\n"),
ts->traceframe_count);
}
- if (ts->buffer_free)
+ if (ts->buffer_free >= 0)
{
- printf_filtered (_("Trace buffer has %llu bytes free.\n"),
- ts->buffer_free);
+ if (ts->buffer_size >= 0)
+ {
+ printf_filtered (_("Trace buffer has %d bytes of %d bytes free"),
+ ts->buffer_free, ts->buffer_size);
+ if (ts->buffer_size > 0)
+ printf_filtered (_(" (%d%% full)"),
+ ((int) ((((long long) (ts->buffer_size
+ - ts->buffer_free)) * 100)
+ / ts->buffer_size)));
+ printf_filtered (_(".\n"));
+ }
+ else
+ printf_filtered (_("Trace buffer has %d bytes free.\n"),
+ ts->buffer_free);
}
/* Now report on what we're doing with tfind. */
printf_filtered (_("Not looking at any trace frame.\n"));
}
+/* Report the trace status to uiout, in a way suitable for MI, and not
+ suitable for CLI. If ON_STOP is true, suppress a few fields that
+ are not meaningful in the -trace-stop response.
+
+ The implementation is essentially parallel to trace_status_command, but
+ merging them will result in unreadable code. */
+void
+trace_status_mi (int on_stop)
+{
+ struct trace_status *ts = current_trace_status ();
+ int status;
+ char *string_status;
+
+ status = target_get_trace_status (ts);
+
+ if (status == -1 && !ts->from_file)
+ {
+ ui_out_field_string (uiout, "supported", "0");
+ return;
+ }
+
+ if (ts->from_file)
+ ui_out_field_string (uiout, "supported", "file");
+ else if (!on_stop)
+ ui_out_field_string (uiout, "supported", "1");
+
+ gdb_assert (ts->running_known);
+
+ if (ts->running)
+ {
+ ui_out_field_string (uiout, "running", "1");
+
+ /* Unlike CLI, do not show the state of 'disconnected-tracing' variable.
+ Given that the frontend gets the status either on -trace-stop, or from
+ -trace-status after re-connection, it does not seem like this
+ information is necessary for anything. It is not necessary for either
+ figuring the vital state of the target nor for navigation of trace
+ frames. If the frontend wants to show the current state is some
+ configure dialog, it can request the value when such dialog is
+ invoked by the user. */
+ }
+ else
+ {
+ char *stop_reason = NULL;
+ int stopping_tracepoint = -1;
+
+ if (!on_stop)
+ ui_out_field_string (uiout, "running", "0");
+
+ if (ts->stop_reason != trace_stop_reason_unknown)
+ {
+ switch (ts->stop_reason)
+ {
+ case tstop_command:
+ stop_reason = "request";
+ break;
+ case trace_buffer_full:
+ stop_reason = "overflow";
+ break;
+ case trace_disconnected:
+ stop_reason = "disconnection";
+ break;
+ case tracepoint_passcount:
+ stop_reason = "passcount";
+ stopping_tracepoint = ts->stopping_tracepoint;
+ break;
+ case tracepoint_error:
+ stop_reason = "error";
+ stopping_tracepoint = ts->stopping_tracepoint;
+ break;
+ }
+
+ if (stop_reason)
+ {
+ ui_out_field_string (uiout, "stop-reason", stop_reason);
+ if (stopping_tracepoint != -1)
+ ui_out_field_int (uiout, "stopping-tracepoint",
+ stopping_tracepoint);
+ if (ts->stop_reason == tracepoint_error)
+ ui_out_field_string (uiout, "error-description",
+ ts->error_desc);
+ }
+ }
+ }
+
+
+ if ((int) ts->traceframe_count != -1)
+ ui_out_field_int (uiout, "frames", ts->traceframe_count);
+ if ((int) ts->buffer_size != -1)
+ ui_out_field_int (uiout, "buffer-size", (int) ts->buffer_size);
+ if ((int) ts->buffer_free != -1)
+ ui_out_field_int (uiout, "buffer-free", (int) ts->buffer_free);
+}
+
+
void
disconnect_or_stop_tracing (int from_tty)
{
if (!cont)
stop_tracing ();
}
+
+ /* Also we want to be out of tfind mode, otherwise things can get
+ confusing upon reconnection. Just use these calls instead of
+ full tfind_1 behavior because we're in the middle of detaching,
+ and there's no point to updating current stack frame etc. */
+ set_traceframe_number (-1);
+ set_traceframe_context (NULL);
}
/* Worker function for the various flavors of the tfind command. */
-static void
-finish_tfind_command (enum trace_find_type type, int num,
- ULONGEST addr1, ULONGEST addr2,
- int from_tty)
+void
+tfind_1 (enum trace_find_type type, int num,
+ ULONGEST addr1, ULONGEST addr2,
+ int from_tty)
{
int target_frameno = -1, target_tracept = -1;
struct frame_id old_frame_id;
reinit_frame_cache ();
registers_changed ();
+ target_dcache_invalidate ();
set_traceframe_num (target_frameno);
set_tracepoint_num (tp ? tp->number : target_tracept);
if (target_frameno == -1)
else
set_traceframe_context (get_current_frame ());
+ if (traceframe_number >= 0)
+ {
+ /* Use different branches for MI and CLI to make CLI messages
+ i18n-eable. */
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ ui_out_field_string (uiout, "found", "1");
+ ui_out_field_int (uiout, "tracepoint", tracepoint_number);
+ ui_out_field_int (uiout, "traceframe", traceframe_number);
+ }
+ else
+ {
+ printf_unfiltered (_("Found trace frame %d, tracepoint %d\n"),
+ traceframe_number, tracepoint_number);
+ }
+ }
+ else
+ {
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "found", "0");
+ else
+ printf_unfiltered (_("No trace frame found"));
+ }
+
/* If we're in nonstop mode and getting out of looking at trace
frames, there won't be any current frame to go back to and
display. */
if (frameno < -1)
error (_("invalid input (%d is less than zero)"), frameno);
- finish_tfind_command (tfind_number, frameno, 0, 0, from_tty);
+ tfind_1 (tfind_number, frameno, 0, 0, from_tty);
}
/* tfind end */
else
pc = parse_and_eval_address (args);
- finish_tfind_command (tfind_pc, 0, pc, 0, from_tty);
+ tfind_1 (tfind_pc, 0, pc, 0, from_tty);
}
/* tfind tracepoint command */
if (tp)
tdp = tp->number_on_target;
- finish_tfind_command (tfind_tp, tdp, 0, 0, from_tty);
+ tfind_1 (tfind_tp, tdp, 0, 0, from_tty);
}
/* TFIND LINE command:
sals.sals[0] = sal;
}
else
- {
+ {
sals = decode_line_spec (args, 1);
sal = sals.sals[0];
}
old_chain = make_cleanup (xfree, sals.sals);
if (sal.symtab == 0)
- {
- printf_filtered ("TFIND: No line number information available");
- if (sal.pc != 0)
- {
- /* This is useful for "info line *0x7f34". If we can't
- tell the user about a source line, at least let them
- have the symbolic address. */
- printf_filtered (" for address ");
- wrap_here (" ");
- print_address (get_current_arch (), sal.pc, gdb_stdout);
- printf_filtered (";\n -- will attempt to find by PC. \n");
- }
- else
- {
- printf_filtered (".\n");
- return; /* No line, no PC; what can we do? */
- }
- }
- else if (sal.line > 0
- && find_line_pc_range (sal, &start_pc, &end_pc))
+ error (_("No line number information available."));
+
+ if (sal.line > 0 && find_line_pc_range (sal, &start_pc, &end_pc))
{
if (start_pc == end_pc)
{
/* Find within range of stated line. */
if (args && *args)
- finish_tfind_command (tfind_range, 0, start_pc, end_pc - 1, from_tty);
+ tfind_1 (tfind_range, 0, start_pc, end_pc - 1, from_tty);
else
- finish_tfind_command (tfind_outside, 0, start_pc, end_pc - 1, from_tty);
+ tfind_1 (tfind_outside, 0, start_pc, end_pc - 1, from_tty);
do_cleanups (old_chain);
}
stop = start + 1; /* ??? */
}
- finish_tfind_command (tfind_range, 0, start, stop, from_tty);
+ tfind_1 (tfind_range, 0, start, stop, from_tty);
}
/* tfind outside command */
stop = start + 1; /* ??? */
}
- finish_tfind_command (tfind_outside, 0, start, stop, from_tty);
+ tfind_1 (tfind_outside, 0, start, stop, from_tty);
}
/* info scope command: list the locals for a scope. */
struct regcache *regcache;
struct gdbarch *gdbarch;
struct breakpoint *t;
- struct action_line *action;
+ struct command_line *action;
char *action_exp, *next_comma;
struct cleanup *old_cleanups;
int stepping_actions = 0;
int stepping_frame = 0;
+ struct bp_location *loc;
if (tracepoint_number == -1)
{
regcache = get_current_regcache ();
gdbarch = get_regcache_arch (regcache);
- stepping_frame = (t->loc->address != (regcache_read_pc (regcache)));
+ /* If the traceframe's address matches any of the tracepoint's
+ locations, assume it is a direct hit rather than a while-stepping
+ frame. (FIXME this is not reliable, should record each frame's
+ type.) */
+ stepping_frame = 1;
+ for (loc = t->loc; loc; loc = loc->next)
+ if (loc->address == regcache_read_pc (regcache))
+ stepping_frame = 0;
- for (action = t->actions; action; action = action->next)
+ for (action = t->commands->commands; action; action = action->next)
{
struct cmd_list_element *cmd;
QUIT; /* allow user to bail out with ^C */
- action_exp = action->action;
+ action_exp = action->line;
while (isspace ((int) *action_exp))
action_exp++;
discard_cleanups (old_cleanups);
}
+/* Encode a piece of a tracepoint's source-level definition in a form
+ that is suitable for both protocol and saving in files. */
+/* This version does not do multiple encodes for long strings; it should
+ return an offset to the next piece to encode. FIXME */
+
+extern int
+encode_source_string (int tpnum, ULONGEST addr,
+ char *srctype, char *src, char *buf, int buf_size)
+{
+ if (80 + strlen (srctype) > buf_size)
+ error (_("Buffer too small for source encoding"));
+ sprintf (buf, "%x:%s:%s:%x:%x:",
+ tpnum, phex_nz (addr, sizeof (addr)), srctype, 0, (int) strlen (src));
+ if (strlen (buf) + strlen (src) * 2 >= buf_size)
+ error (_("Source string too long for buffer"));
+ bin2hex (src, buf + strlen (buf), 0);
+ return -1;
+}
+
extern int trace_regblock_size;
-static void
-trace_save_command (char *args, int from_tty)
+/* Save tracepoint data to file named FILENAME. If TARGET_DOES_SAVE is
+ non-zero, the save is performed on the target, otherwise GDB obtains all
+ trace data and saves it locally. */
+
+void
+trace_save (const char *filename, int target_does_save)
{
- char **argv;
- char *filename = NULL, *pathname;
- int target_does_save = 0;
struct cleanup *cleanup;
+ char *pathname;
struct trace_status *ts = current_trace_status ();
int err, status;
FILE *fp;
struct uploaded_tp *uploaded_tps = NULL, *utp;
struct uploaded_tsv *uploaded_tsvs = NULL, *utsv;
int a;
+ struct uploaded_string *cmd;
LONGEST gotten = 0;
ULONGEST offset = 0;
#define MAX_TRACE_UPLOAD 2000
gdb_byte buf[MAX_TRACE_UPLOAD];
int written;
- if (args == NULL)
- error_no_arg (_("file in which to save trace data"));
-
- argv = gdb_buildargv (args);
- make_cleanup_freeargv (argv);
-
- for (; *argv; ++argv)
- {
- if (strcmp (*argv, "-r") == 0)
- target_does_save = 1;
- else if (**argv == '-')
- error (_("unknown option `%s'"), *argv);
- else
- filename = *argv;
- }
-
- if (!filename)
- error_no_arg (_("file in which to save trace data"));
-
/* If the target is to save the data to a file on its own, then just
send the command and be done with it. */
if (target_does_save)
target is losing, we can get out without touching files. */
status = target_get_trace_status (ts);
- pathname = tilde_expand (args);
+ pathname = tilde_expand (filename);
cleanup = make_cleanup (xfree, pathname);
fp = fopen (pathname, "w");
if (!fp)
error (_("Unable to open file '%s' for saving trace data (%s)"),
- args, safe_strerror (errno));
+ filename, safe_strerror (errno));
make_cleanup_fclose (fp);
/* Write a file header, with a high-bit-set char to indicate a
binary file, plus a hint as what this file is, and a version
number in case of future needs. */
written = fwrite ("\x7fTRACE0\n", 8, 1, fp);
- if (written < 8)
+ if (written < 1)
perror_with_name (pathname);
/* Write descriptive info. */
fprintf (fp, "R %x\n", trace_regblock_size);
/* Write out status of the tracing run (aka "tstatus" info). */
- fprintf (fp, "status %c;%s:%x;tframes:%x;tfree:%llx\n",
- (ts->running ? '1' : '0'),
- stop_reason_names[ts->stop_reason], ts->stopping_tracepoint,
- ts->traceframe_count, ts->buffer_free);
+ fprintf (fp, "status %c;%s",
+ (ts->running ? '1' : '0'), stop_reason_names[ts->stop_reason]);
+ if (ts->stop_reason == tracepoint_error)
+ {
+ char *buf = (char *) alloca (strlen (ts->error_desc) * 2 + 1);
+ bin2hex ((gdb_byte *) ts->error_desc, buf, 0);
+ fprintf (fp, ":%s", buf);
+ }
+ fprintf (fp, ":%x", ts->stopping_tracepoint);
+ if (ts->traceframe_count >= 0)
+ fprintf (fp, ";tframes:%x", ts->traceframe_count);
+ if (ts->traceframes_created >= 0)
+ fprintf (fp, ";tcreated:%x", ts->traceframes_created);
+ if (ts->buffer_free >= 0)
+ fprintf (fp, ";tfree:%x", ts->buffer_free);
+ if (ts->buffer_size >= 0)
+ fprintf (fp, ";tsize:%x", ts->buffer_size);
+ fprintf (fp, "\n");
/* Note that we want to upload tracepoints and save those, rather
than simply writing out the local ones, because the user may have
fprintf (fp, "tp S%x:%s:%s\n",
utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
utp->step_actions[a]);
+ if (utp->at_string)
+ {
+ encode_source_string (utp->number, utp->addr,
+ "at", utp->at_string, buf, MAX_TRACE_UPLOAD);
+ fprintf (fp, "tp Z%s\n", buf);
+ }
+ if (utp->cond_string)
+ {
+ encode_source_string (utp->number, utp->addr,
+ "cond", utp->cond_string, buf, MAX_TRACE_UPLOAD);
+ fprintf (fp, "tp Z%s\n", buf);
+ }
+ for (cmd = utp->cmd_strings; cmd; cmd = cmd->next)
+ {
+ encode_source_string (utp->number, utp->addr, "cmd", cmd->str,
+ buf, MAX_TRACE_UPLOAD);
+ fprintf (fp, "tp Z%s\n", buf);
+ }
}
free_uploaded_tps (&uploaded_tps);
if (gotten == 0)
break;
written = fwrite (buf, gotten, 1, fp);
- if (written < gotten)
+ if (written < 1)
perror_with_name (pathname);
offset += gotten;
}
- /* Mark the end of trace data. */
+ /* Mark the end of trace data. (We know that gotten is 0 at this point.) */
written = fwrite (&gotten, 4, 1, fp);
- if (written < 4)
+ if (written < 1)
perror_with_name (pathname);
do_cleanups (cleanup);
+}
+
+static void
+trace_save_command (char *args, int from_tty)
+{
+ int target_does_save = 0;
+ char **argv;
+ char *filename = NULL;
+ struct cleanup *back_to;
+
+ if (args == NULL)
+ error_no_arg (_("file in which to save trace data"));
+
+ argv = gdb_buildargv (args);
+ back_to = make_cleanup_freeargv (argv);
+
+ for (; *argv; ++argv)
+ {
+ if (strcmp (*argv, "-r") == 0)
+ target_does_save = 1;
+ else if (**argv == '-')
+ error (_("unknown option `%s'"), *argv);
+ else
+ filename = *argv;
+ }
+
+ if (!filename)
+ error_no_arg (_("file in which to save trace data"));
+
+ trace_save (filename, target_does_save);
+
if (from_tty)
printf_filtered (_("Trace data saved to file '%s'.\n"), args);
+
+ do_cleanups (back_to);
}
/* Tell the target what to do with an ongoing tracing run if GDB
send_disconnected_tracing_value (disconnected_tracing);
}
+static void
+set_circular_trace_buffer (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ target_set_circular_trace_buffer (circular_trace_buffer);
+}
+
/* Convert the memory pointed to by mem into hex, placing result in buf.
* Return a pointer to the last char put in buf (null)
* "stolen" from sparc-stub.c
return traceframe_number;
}
+/* Make the traceframe NUM be the current trace frame. Does nothing
+ if NUM is already current. */
+
+void
+set_traceframe_number (int num)
+{
+ int newnum;
+
+ if (traceframe_number == num)
+ {
+ /* Nothing to do. */
+ return;
+ }
+
+ newnum = target_trace_find (tfind_number, num, 0, 0, NULL);
+
+ if (newnum != num)
+ warning (_("could not change traceframe"));
+
+ traceframe_number = newnum;
+
+ /* Changing the traceframe changes our view of registers and of the
+ frame chain. */
+ registers_changed ();
+}
+
+/* A cleanup used when switching away and back from tfind mode. */
+
+struct current_traceframe_cleanup
+{
+ /* The traceframe we were inspecting. */
+ int traceframe_number;
+};
+
+static void
+do_restore_current_traceframe_cleanup (void *arg)
+{
+ struct current_traceframe_cleanup *old = arg;
+
+ set_traceframe_number (old->traceframe_number);
+}
+
+static void
+restore_current_traceframe_cleanup_dtor (void *arg)
+{
+ struct current_traceframe_cleanup *old = arg;
+
+ xfree (old);
+}
+
+struct cleanup *
+make_cleanup_restore_current_traceframe (void)
+{
+ struct current_traceframe_cleanup *old;
+
+ old = xmalloc (sizeof (struct current_traceframe_cleanup));
+ old->traceframe_number = traceframe_number;
+
+ return make_cleanup_dtor (do_restore_current_traceframe_cleanup, old,
+ restore_current_traceframe_cleanup_dtor);
+}
/* Given a number and address, return an uploaded tracepoint with that
number, creating if necessary. */
void
parse_trace_status (char *line, struct trace_status *ts)
{
- char *p = line, *p1, *p_temp;
+ char *p = line, *p1, *p2, *p_temp;
ULONGEST val;
ts->running_known = 1;
ts->running = (*p++ == '1');
ts->stop_reason = trace_stop_reason_unknown;
+ xfree (ts->error_desc);
+ ts->error_desc = NULL;
+ ts->traceframe_count = -1;
+ ts->traceframes_created = -1;
+ ts->buffer_free = -1;
+ ts->buffer_size = -1;
+
while (*p++)
{
p1 = strchr (p, ':');
p = unpack_varlen_hex (++p1, &val);
ts->stop_reason = tstop_command;
}
- if (strncmp (p, "tframes", p1 - p) == 0)
+ else if (strncmp (p, stop_reason_names[tracepoint_error], p1 - p) == 0)
+ {
+ p2 = strchr (++p1, ':');
+ if (p2 != p1)
+ {
+ int end;
+
+ ts->error_desc = xmalloc ((p2 - p1) / 2 + 1);
+ end = hex2bin (p1, ts->error_desc, (p2 - p1) / 2);
+ ts->error_desc[end] = '\0';
+ }
+ else
+ ts->error_desc = xstrdup ("");
+
+ p = unpack_varlen_hex (++p2, &val);
+ ts->stopping_tracepoint = val;
+ ts->stop_reason = tracepoint_error;
+ }
+ else if (strncmp (p, "tframes", p1 - p) == 0)
{
p = unpack_varlen_hex (++p1, &val);
ts->traceframe_count = val;
}
- if (strncmp (p, "tfree", p1 - p) == 0)
+ else if (strncmp (p, "tcreated", p1 - p) == 0)
+ {
+ p = unpack_varlen_hex (++p1, &val);
+ ts->traceframes_created = val;
+ }
+ else if (strncmp (p, "tfree", p1 - p) == 0)
{
p = unpack_varlen_hex (++p1, &val);
ts->buffer_free = val;
}
+ else if (strncmp (p, "tsize", p1 - p) == 0)
+ {
+ p = unpack_varlen_hex (++p1, &val);
+ ts->buffer_size = val;
+ }
else
{
/* Silently skip unknown optional info. */
}
}
-/* Given a line of text defining a tracepoint or tracepoint action, parse
- it into an "uploaded tracepoint". */
+/* Given a line of text defining a part of a tracepoint, parse it into
+ an "uploaded tracepoint". */
void
parse_tracepoint_definition (char *line, struct uploaded_tp **utpp)
{
char *p;
char piece;
- ULONGEST num, addr, step, pass, orig_size, xlen;
- int enabled, i;
+ ULONGEST num, addr, step, pass, orig_size, xlen, start;
+ int enabled, i, end;
enum bptype type;
- char *cond;
+ char *cond, *srctype, *src, *buf;
struct uploaded_tp *utp = NULL;
p = line;
p += 2 * xlen;
}
else
- warning ("Unrecognized char '%c' in tracepoint definition, skipping rest", *p);
+ warning (_("Unrecognized char '%c' in tracepoint definition, skipping rest"), *p);
}
utp = get_uploaded_tp (num, addr, utpp);
utp->type = type;
utp = get_uploaded_tp (num, addr, utpp);
utp->step_actions[utp->num_step_actions++] = xstrdup (p);
}
+ else if (piece == 'Z')
+ {
+ /* Parse a chunk of source form definition. */
+ utp = get_uploaded_tp (num, addr, utpp);
+ srctype = p;
+ p = strchr (p, ':');
+ p++; /* skip a colon */
+ p = unpack_varlen_hex (p, &start);
+ p++; /* skip a colon */
+ p = unpack_varlen_hex (p, &xlen);
+ p++; /* skip a colon */
+
+ buf = alloca (strlen (line));
+
+ end = hex2bin (p, (gdb_byte *) buf, strlen (p) / 2);
+ buf[end] = '\0';
+
+ if (strncmp (srctype, "at:", strlen ("at:")) == 0)
+ utp->at_string = xstrdup (buf);
+ else if (strncmp (srctype, "cond:", strlen ("cond:")) == 0)
+ utp->cond_string = xstrdup (buf);
+ else if (strncmp (srctype, "cmd:", strlen ("cmd:")) == 0)
+ {
+ /* FIXME consider using a vector? */
+ struct uploaded_string *last, *newlast;
+ newlast = (struct uploaded_string *) xmalloc (sizeof (struct uploaded_string));
+ newlast->str = xstrdup (buf);
+ newlast->next = NULL;
+ if (utp->cmd_strings)
+ {
+ for (last = utp->cmd_strings; last->next; last = last->next)
+ ;
+ last->next = newlast;
+ }
+ else
+ utp->cmd_strings = newlast;
+ }
+ }
else
{
- error ("Invalid tracepoint piece");
+ /* Don't error out, the target might be sending us optional
+ info that we don't care about. */
+ warning (_("Unrecognized tracepoint piece '%c', ignoring"), piece);
}
}
error (_("Premature end of file while reading trace file"));
tp = get_tracepoint_by_number_on_target (tpnum);
+ /* FIXME this is a poor heuristic if multiple locations */
if (tp && tp->loc)
addr = tp->loc->address;
}
if (found)
{
- printf_filtered ("Found traceframe %d.\n", tfnum);
if (tpp)
*tpp = tpnum;
cur_offset = offset;
&setlist,
&showlist);
+ add_setshow_boolean_cmd ("circular-trace-buffer", no_class,
+ &circular_trace_buffer, _("\
+Set target's use of circular trace buffer."), _("\
+Show target's use of circular trace buffer."), _("\
+Use this to make the trace buffer into a circular buffer,\n\
+which will discard traceframes (oldest first) instead of filling\n\
+up and stopping the trace run."),
+ set_circular_trace_buffer,
+ NULL,
+ &setlist,
+ &showlist);
+
init_tfile_ops ();
add_target (&tfile_ops);