/* Tracing functionality for remote targets in custom GDB protocol
- Copyright (C) 1997-2012 Free Software Foundation, Inc.
+ Copyright (C) 1997-2013 Free Software Foundation, Inc.
This file is part of GDB.
#include "memrange.h"
#include "exceptions.h"
#include "cli/cli-utils.h"
+#include "probe.h"
+#include "ctf.h"
+#include "completer.h"
/* readline include files */
#include "readline/readline.h"
#define O_LARGEFILE 0
#endif
-extern int hex2bin (const char *hex, gdb_byte *bin, int count);
-extern int bin2hex (const gdb_byte *bin, char *hex, int count);
-
/* Maximum length of an agent aexpression.
This accounts for the fact that packets are limited to 400 bytes
(which includes everything -- including the checksum), and assumes
extern char *(*deprecated_readline_hook) (char *);
extern void (*deprecated_readline_end_hook) (void);
-/* GDB commands implemented in other modules:
- */
-
-extern void output_command (char *, int);
-
/*
Tracepoint.c:
typedef struct trace_state_variable tsv_s;
DEF_VEC_O(tsv_s);
-/* An object describing the contents of a traceframe. */
-
-struct traceframe_info
-{
- /* Collected memory. */
- VEC(mem_range_s) *memory;
-};
-
static VEC(tsv_s) *tvariables;
/* The next integer to assign to a variable. */
static int circular_trace_buffer;
+/* This variable is the requested trace buffer size, or -1 to indicate
+ that we don't care and leave it up to the target to set a size. */
+
+static int trace_buffer_size = -1;
+
/* Textual notes applying to the current and/or future trace runs. */
char *trace_user = NULL;
/* Save file name as "$trace_file", a debugger variable visible to
users. */
- if (traceframe_sal.symtab == NULL
- || traceframe_sal.symtab->filename == NULL)
+ if (traceframe_sal.symtab == NULL)
clear_internalvar (lookup_internalvar ("trace_file"));
else
set_internalvar_string (lookup_internalvar ("trace_file"),
- traceframe_sal.symtab->filename);
+ symtab_to_filename_for_display (traceframe_sal.symtab));
}
/* Create a new trace state variable with the given name. */
return NULL;
}
-void
+static void
delete_trace_state_variable (const char *name)
{
struct trace_state_variable *tsv;
for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
if (strcmp (name, tsv->name) == 0)
{
+ observer_notify_tsv_deleted (tsv);
+
xfree ((void *)tsv->name);
VEC_unordered_remove (tsv_s, tvariables, ix);
+
return;
}
warning (_("No trace variable named \"$%s\", not deleting"), name);
}
+/* Throws an error if NAME is not valid syntax for a trace state
+ variable's name. */
+
+void
+validate_trace_state_variable_name (const char *name)
+{
+ const char *p;
+
+ if (*name == '\0')
+ error (_("Must supply a non-empty variable name"));
+
+ /* All digits in the name is reserved for value history
+ references. */
+ for (p = name; isdigit (*p); p++)
+ ;
+ if (*p == '\0')
+ error (_("$%s is not a valid trace state variable name"), name);
+
+ for (p = name; isalnum (*p) || *p == '_'; p++)
+ ;
+ if (*p != '\0')
+ error (_("$%s is not a valid trace state variable name"), name);
+}
+
/* The 'tvariable' command collects a name and optional expression to
evaluate into an initial value. */
-void
+static 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;
+ char *name, *p;
if (!args || !*args)
- error_no_arg (_("trace state variable name"));
+ error_no_arg (_("Syntax is $NAME [ = EXPR ]"));
- /* All the possible valid arguments are expressions. */
- expr = parse_expression (args);
- old_chain = make_cleanup (free_current_contents, &expr);
+ /* Only allow two syntaxes; "$name" and "$name=value". */
+ p = skip_spaces (args);
- if (expr->nelts == 0)
- error (_("No expression?"));
+ if (*p++ != '$')
+ error (_("Name of trace variable should start with '$'"));
- /* 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
+ name = p;
+ while (isalnum (*p) || *p == '_')
+ p++;
+ name = savestring (name, p - name);
+ old_chain = make_cleanup (xfree, name);
+
+ p = skip_spaces (p);
+ if (*p != '=' && *p != '\0')
error (_("Syntax must be $NAME [ = EXPR ]"));
- if (!intvar)
- error (_("No name given"));
+ validate_trace_state_variable_name (name);
- if (strlen (internalvar_name (intvar)) <= 0)
- error (_("Must supply a non-empty variable name"));
+ if (*p == '=')
+ initval = value_as_long (parse_and_eval (++p));
/* If the variable already exists, just change its initial value. */
- tsv = find_trace_state_variable (internalvar_name (intvar));
+ tsv = find_trace_state_variable (name);
if (tsv)
{
- tsv->initial_value = initval;
+ if (tsv->initial_value != initval)
+ {
+ tsv->initial_value = initval;
+ observer_notify_tsv_modified (tsv);
+ }
printf_filtered (_("Trace state variable $%s "
"now has initial value %s.\n"),
tsv->name, plongest (tsv->initial_value));
}
/* Create a new variable. */
- tsv = create_trace_state_variable (internalvar_name (intvar));
+ tsv = create_trace_state_variable (name);
tsv->initial_value = initval;
+ observer_notify_tsv_created (tsv);
+
printf_filtered (_("Trace state variable $%s "
"created, with initial value %s.\n"),
tsv->name, plongest (tsv->initial_value));
do_cleanups (old_chain);
}
-void
+static void
delete_trace_variable_command (char *args, int from_tty)
{
int ix;
if (query (_("Delete all trace state variables? ")))
VEC_free (tsv_s, tvariables);
dont_repeat ();
+ observer_notify_tsv_deleted (NULL);
return;
}
it means that somebody issued the "command" at the top level,
which is always an error. */
-void
+static void
end_actions_pseudocommand (char *args, int from_tty)
{
error (_("This command cannot be used at the top level."));
}
-void
+static void
while_stepping_pseudocommand (char *args, int from_tty)
{
error (_("This command can only be used in a tracepoint actions list."));
/* Parse any collection options, such as /s for strings. */
-char *
-decode_agent_options (char *exp)
+const char *
+decode_agent_options (const char *exp, int *trace_string)
{
struct value_print_options opts;
+ *trace_string = 0;
+
if (*exp != '/')
return exp;
/* Allow an optional decimal number giving an explicit maximum
string length, defaulting it to the "print elements" value;
so "collect/s80 mystr" gets at most 80 bytes of string. */
- trace_string_kludge = opts.print_max;
+ *trace_string = opts.print_max;
exp++;
if (*exp >= '0' && *exp <= '9')
- trace_string_kludge = atoi (exp);
+ *trace_string = atoi (exp);
while (*exp >= '0' && *exp <= '9')
exp++;
}
else
error (_("Undefined collection format \"%c\"."), *exp);
- exp = skip_spaces (exp);
+ exp = skip_spaces_const (exp);
return exp;
}
/* worker function */
void
-validate_actionline (char **line, struct breakpoint *b)
+validate_actionline (const char *line, struct breakpoint *b)
{
struct cmd_list_element *c;
struct expression *exp = NULL;
struct cleanup *old_chain = NULL;
- char *p, *tmp_p;
+ const char *tmp_p;
+ const char *p;
struct bp_location *loc;
struct agent_expr *aexpr;
struct tracepoint *t = (struct tracepoint *) b;
/* If EOF is typed, *line is NULL. */
- if (*line == NULL)
+ if (line == NULL)
return;
- for (p = *line; isspace ((int) *p);)
- p++;
+ p = skip_spaces_const (line);
/* Symbol lookup etc. */
if (*p == '\0') /* empty line: just prompt for another line. */
if (cmd_cfunc_eq (c, collect_pseudocommand))
{
- trace_string_kludge = 0;
+ int trace_string = 0;
+
if (*p == '/')
- p = decode_agent_options (p);
+ p = decode_agent_options (p, &trace_string);
do
{ /* Repeat over a comma-separated list. */
QUIT; /* Allow user to bail out with ^C. */
- while (isspace ((int) *p))
- p++;
+ p = skip_spaces_const (p);
if (*p == '$') /* Look for special pseudo-symbols. */
{
for (loc = t->base.loc; loc; loc = loc->next)
{
p = tmp_p;
- exp = parse_exp_1 (&p, block_for_pc (loc->address), 1);
+ exp = parse_exp_1 (&p, loc->address,
+ block_for_pc (loc->address), 1);
old_chain = make_cleanup (free_current_contents, &exp);
if (exp->elts[0].opcode == OP_VAR_VALUE)
{
if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_CONST)
{
- error (_("constant `%s' (value %ld) "
+ error (_("constant `%s' (value %s) "
"will not be collected."),
SYMBOL_PRINT_NAME (exp->elts[2].symbol),
- SYMBOL_VALUE (exp->elts[2].symbol));
+ plongest (SYMBOL_VALUE (exp->elts[2].symbol)));
}
else if (SYMBOL_CLASS (exp->elts[2].symbol)
== LOC_OPTIMIZED_OUT)
/* 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);
+ aexpr = gen_trace_for_expr (loc->address, exp, trace_string);
make_cleanup_free_agent_expr (aexpr);
if (aexpr->len > MAX_AGENT_EXPR_LEN)
do
{ /* Repeat over a comma-separated list. */
QUIT; /* Allow user to bail out with ^C. */
- while (isspace ((int) *p))
- p++;
+ p = skip_spaces_const (p);
tmp_p = p;
for (loc = t->base.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);
+ exp = parse_exp_1 (&p, loc->address,
+ 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
else if (cmd_cfunc_eq (c, while_stepping_pseudocommand))
{
- char *steparg; /* In case warning is necessary. */
+ char *endp;
- while (isspace ((int) *p))
- p++;
- steparg = p;
-
- if (*p == '\0' || (t->step_count = strtol (p, &p, 0)) == 0)
- error (_("while-stepping step count `%s' is malformed."), *line);
+ p = skip_spaces_const (p);
+ t->step_count = strtol (p, &endp, 0);
+ if (endp == p || t->step_count == 0)
+ error (_("while-stepping step count `%s' is malformed."), line);
+ p = endp;
}
else if (cmd_cfunc_eq (c, end_actions_pseudocommand))
;
else
- error (_("`%s' is not a supported tracepoint action."), *line);
+ error (_("`%s' is not a supported tracepoint action."), line);
}
enum {
struct symbol *sym,
struct gdbarch *gdbarch,
long frame_regno, long frame_offset,
- CORE_ADDR scope)
+ CORE_ADDR scope,
+ int trace_string)
{
unsigned long len;
unsigned int reg;
SYMBOL_CLASS (sym));
break;
case LOC_CONST:
- printf_filtered ("constant %s (value %ld) will not be collected.\n",
- SYMBOL_PRINT_NAME (sym), SYMBOL_VALUE (sym));
+ printf_filtered ("constant %s (value %s) will not be collected.\n",
+ SYMBOL_PRINT_NAME (sym), plongest (SYMBOL_VALUE (sym)));
break;
case LOC_STATIC:
offset = SYMBOL_VALUE_ADDRESS (sym);
struct agent_expr *aexpr;
struct cleanup *old_chain1 = NULL;
- aexpr = gen_trace_for_var (scope, gdbarch, sym);
+ aexpr = gen_trace_for_var (scope, gdbarch, sym, trace_string);
/* It can happen that the symbol is recorded as a computed
location, but it's been optimized away and doesn't actually
long frame_regno;
long frame_offset;
int count;
+ int trace_string;
};
/* The callback for the locals and args iterators. */
struct add_local_symbols_data *p = cb_data;
collect_symbol (p->collect, sym, p->gdbarch, p->frame_regno,
- p->frame_offset, p->pc);
+ p->frame_offset, p->pc, p->trace_string);
p->count++;
}
static void
add_local_symbols (struct collection_list *collect,
struct gdbarch *gdbarch, CORE_ADDR pc,
- long frame_regno, long frame_offset, int type)
+ long frame_regno, long frame_offset, int type,
+ int trace_string)
{
struct block *block;
struct add_local_symbols_data cb_data;
cb_data.frame_regno = frame_regno;
cb_data.frame_offset = frame_offset;
cb_data.count = 0;
+ cb_data.trace_string = trace_string;
if (type == 'L')
{
struct collection_list *collect,
struct collection_list *stepping_list)
{
- char *action_exp;
+ const char *action_exp;
struct expression *exp = NULL;
int i;
struct value *tempval;
{
QUIT; /* Allow user to bail out with ^C. */
action_exp = action->line;
- while (isspace ((int) *action_exp))
- action_exp++;
+ action_exp = skip_spaces_const (action_exp);
cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
if (cmd == 0)
if (cmd_cfunc_eq (cmd, collect_pseudocommand))
{
- trace_string_kludge = 0;
+ int trace_string = 0;
+
if (*action_exp == '/')
- action_exp = decode_agent_options (action_exp);
+ action_exp = decode_agent_options (action_exp, &trace_string);
do
{ /* Repeat over a comma-separated list. */
QUIT; /* Allow user to bail out with ^C. */
- while (isspace ((int) *action_exp))
- action_exp++;
+ action_exp = skip_spaces_const (action_exp);
if (0 == strncasecmp ("$reg", action_exp, 4))
{
tloc->address,
frame_reg,
frame_offset,
- 'A');
+ 'A',
+ trace_string);
action_exp = strchr (action_exp, ','); /* more? */
}
else if (0 == strncasecmp ("$loc", action_exp, 4))
tloc->address,
frame_reg,
frame_offset,
- 'L');
+ 'L',
+ trace_string);
action_exp = strchr (action_exp, ','); /* more? */
}
else if (0 == strncasecmp ("$_ret", action_exp, 5))
struct cleanup *old_chain1 = NULL;
aexpr = gen_trace_for_return_address (tloc->address,
- tloc->gdbarch);
+ tloc->gdbarch,
+ trace_string);
old_chain1 = make_cleanup_free_agent_expr (aexpr);
}
else
{
- unsigned long addr, len;
+ unsigned long addr;
struct cleanup *old_chain = NULL;
struct cleanup *old_chain1 = NULL;
- exp = parse_exp_1 (&action_exp,
+ exp = parse_exp_1 (&action_exp, tloc->address,
block_for_pc (tloc->address), 1);
old_chain = make_cleanup (free_current_contents, &exp);
/* Safe because we know it's a simple expression. */
tempval = evaluate_expression (exp);
addr = value_address (tempval);
- len = TYPE_LENGTH (check_typedef (exp->elts[1].type));
- add_memrange (collect, memrange_absolute, addr, len);
+ /* Initialize the TYPE_LENGTH if it is a typedef. */
+ check_typedef (exp->elts[1].type);
+ add_memrange (collect, memrange_absolute, addr,
+ TYPE_LENGTH (exp->elts[1].type));
break;
case OP_VAR_VALUE:
tloc->gdbarch,
frame_reg,
frame_offset,
- tloc->address);
+ tloc->address,
+ trace_string);
break;
default: /* Full-fledged expression. */
- aexpr = gen_trace_for_expr (tloc->address, exp);
+ aexpr = gen_trace_for_expr (tloc->address, exp,
+ trace_string);
old_chain1 = make_cleanup_free_agent_expr (aexpr);
do
{ /* Repeat over a comma-separated list. */
QUIT; /* Allow user to bail out with ^C. */
- while (isspace ((int) *action_exp))
- action_exp++;
+ action_exp = skip_spaces_const (action_exp);
{
struct cleanup *old_chain = NULL;
struct cleanup *old_chain1 = NULL;
- exp = parse_exp_1 (&action_exp,
+ exp = parse_exp_1 (&action_exp, tloc->address,
block_for_pc (tloc->address), 1);
old_chain = make_cleanup (free_current_contents, &exp);
}
/* Render all actions into gdb protocol. */
-/*static*/ void
+
+void
encode_actions (struct breakpoint *t, struct bp_location *tloc,
char ***tdp_actions, char ***stepping_actions)
{
the fly, and don't cache it. */
if (*default_collect)
{
- char *line;
-
default_collect_line = xstrprintf ("collect %s", default_collect);
make_cleanup (xfree, default_collect_line);
- line = default_collect_line;
- validate_actionline (&line, t);
+ validate_actionline (default_collect_line, t);
default_collect_action = xmalloc (sizeof (struct command_line));
make_cleanup (xfree, default_collect_action);
default_collect_action->next = actions;
- default_collect_action->line = line;
+ default_collect_action->line = default_collect_line;
actions = default_collect_action;
}
encode_actions_1 (actions, t, tloc, frame_reg, frame_offset,
for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, b); ix++)
{
struct tracepoint *t = (struct tracepoint *) b;
+ struct bp_location *loc;
if (b->enable_state == bp_enabled)
any_enabled = 1;
{
struct tracepoint *t = (struct tracepoint *) b;
struct bp_location *loc;
+ int bp_location_downloaded = 0;
/* Clear `inserted' flag. */
for (loc = b->loc; loc; loc = loc->next)
target_download_tracepoint (loc);
loc->inserted = 1;
+ bp_location_downloaded = 1;
}
t->number_on_target = b->number;
+
+ for (loc = b->loc; loc; loc = loc->next)
+ if (loc->probe != NULL)
+ loc->probe->pops->set_semaphore (loc->probe, loc->gdbarch);
+
+ if (bp_location_downloaded)
+ observer_notify_breakpoint_modified (b);
}
VEC_free (breakpoint_p, tp_vec);
/* Set some mode flags. */
target_set_disconnected_tracing (disconnected_tracing);
target_set_circular_trace_buffer (circular_trace_buffer);
+ target_set_trace_buffer_size (trace_buffer_size);
if (!notes)
notes = trace_notes;
ret = target_set_trace_notes (trace_user, notes, NULL);
if (!ret && (trace_user || notes))
- warning ("Target does not support trace user/notes, info ignored");
+ warning (_("Target does not support trace user/notes, info ignored"));
/* Now insert traps and begin collecting data. */
target_trace_start ();
stop_tracing (char *note)
{
int ret;
+ VEC(breakpoint_p) *tp_vec = NULL;
+ int ix;
+ struct breakpoint *t;
target_trace_stop ();
+ tp_vec = all_tracepoints ();
+ for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
+ {
+ struct bp_location *loc;
+
+ if ((t->type == bp_fast_tracepoint
+ ? !may_insert_fast_tracepoints
+ : !may_insert_tracepoints))
+ continue;
+
+ for (loc = t->loc; loc; loc = loc->next)
+ {
+ /* GDB can be totally absent in some disconnected trace scenarios,
+ but we don't really care if this semaphore goes out of sync.
+ That's why we are decrementing it here, but not taking care
+ in other places. */
+ if (loc->probe != NULL)
+ loc->probe->pops->clear_semaphore (loc->probe, loc->gdbarch);
+ }
+ }
+
+ VEC_free (breakpoint_p, tp_vec);
+
if (!note)
note = trace_stop_notes;
ret = target_set_trace_notes (NULL, NULL, note);
if (!ret && note)
- warning ("Target does not support trace notes, note ignored");
+ warning (_("Target does not support trace notes, note ignored"));
/* Should change in response to reply? */
current_trace_status ()->running = 0;
if (status == -1)
{
- if (ts->from_file)
+ if (ts->filename != NULL)
printf_filtered (_("Using a trace file.\n"));
else
{
status = target_get_trace_status (ts);
- if (status == -1 && !ts->from_file)
+ if (status == -1 && ts->filename == NULL)
{
ui_out_field_string (uiout, "supported", "0");
return;
}
- if (ts->from_file)
+ if (ts->filename != NULL)
ui_out_field_string (uiout, "supported", "file");
else if (!on_stop)
ui_out_field_string (uiout, "supported", "1");
+ if (ts->filename != NULL)
+ ui_out_field_string (uiout, "trace-file", ts->filename);
+
gdb_assert (ts->running_known);
if (ts->running)
full tfind_1 behavior because we're in the middle of detaching,
and there's no point to updating current stack frame etc. */
set_current_traceframe (-1);
+ set_tracepoint_num (-1);
set_traceframe_context (NULL);
}
/* Worker function for the various flavors of the tfind command. */
void
tfind_1 (enum trace_find_type type, int num,
- ULONGEST addr1, ULONGEST addr2,
+ CORE_ADDR addr1, CORE_ADDR addr2,
int from_tty)
{
int target_frameno = -1, target_tracept = -1;
tp = get_tracepoint_by_number_on_target (target_tracept);
reinit_frame_cache ();
- registers_changed ();
target_dcache_invalidate ();
- set_traceframe_num (target_frameno);
- clear_traceframe_info ();
+
set_tracepoint_num (tp ? tp->base.number : target_tracept);
+
+ if (target_frameno != get_traceframe_number ())
+ observer_notify_traceframe_changed (target_frameno, tracepoint_number);
+
+ set_current_traceframe (target_frameno);
+
if (target_frameno == -1)
set_traceframe_context (NULL);
else
{ /* This should only be called with a numeric argument. */
int frameno = -1;
- if (current_trace_status ()->running && !current_trace_status ()->from_file)
+ if (current_trace_status ()->running
+ && current_trace_status ()->filename == NULL)
error (_("May not look at trace frames while trace is running."));
if (args == 0 || *args == 0)
trace_find_command ("-1", from_tty);
}
-/* tfind none */
-static void
-trace_find_none_command (char *args, int from_tty)
-{
- trace_find_command ("-1", from_tty);
-}
-
/* tfind start */
static void
trace_find_start_command (char *args, int from_tty)
{
CORE_ADDR pc;
- if (current_trace_status ()->running && !current_trace_status ()->from_file)
+ if (current_trace_status ()->running
+ && current_trace_status ()->filename == NULL)
error (_("May not look at trace frames while trace is running."));
if (args == 0 || *args == 0)
int tdp;
struct tracepoint *tp;
- if (current_trace_status ()->running && !current_trace_status ()->from_file)
+ if (current_trace_status ()->running
+ && current_trace_status ()->filename == NULL)
error (_("May not look at trace frames while trace is running."));
if (args == 0 || *args == 0)
struct symtab_and_line sal;
struct cleanup *old_chain;
- if (current_trace_status ()->running && !current_trace_status ()->from_file)
+ if (current_trace_status ()->running
+ && current_trace_status ()->filename == NULL)
error (_("May not look at trace frames while trace is running."));
if (args == 0 || *args == 0)
}
else
{
- sals = decode_line_spec (args, DECODE_LINE_FUNFIRSTLINE);
+ sals = decode_line_with_current_source (args, DECODE_LINE_FUNFIRSTLINE);
sal = sals.sals[0];
}
if (start_pc == end_pc)
{
printf_filtered ("Line %d of \"%s\"",
- sal.line, sal.symtab->filename);
+ sal.line,
+ symtab_to_filename_for_display (sal.symtab));
wrap_here (" ");
printf_filtered (" is at address ");
print_address (get_current_arch (), start_pc, gdb_stdout);
which the user would want to see? If we have debugging
symbols and no line numbers? */
error (_("Line number %d is out of range for \"%s\"."),
- sal.line, sal.symtab->filename);
+ sal.line, symtab_to_filename_for_display (sal.symtab));
/* Find within range of stated line. */
if (args && *args)
static CORE_ADDR start, stop;
char *tmp;
- if (current_trace_status ()->running && !current_trace_status ()->from_file)
+ if (current_trace_status ()->running
+ && current_trace_status ()->filename == NULL)
error (_("May not look at trace frames while trace is running."));
if (args == 0 || *args == 0)
if (0 != (tmp = strchr (args, ',')))
{
*tmp++ = '\0'; /* Terminate start address. */
- while (isspace ((int) *tmp))
- tmp++;
+ tmp = skip_spaces (tmp);
start = parse_and_eval_address (args);
stop = parse_and_eval_address (tmp);
}
CORE_ADDR start, stop;
char *tmp;
- if (current_trace_status ()->running && !current_trace_status ()->from_file)
+ if (current_trace_status ()->running
+ && current_trace_status ()->filename == NULL)
error (_("May not look at trace frames while trace is running."));
if (args == 0 || *args == 0)
if (0 != (tmp = strchr (args, ',')))
{
*tmp++ = '\0'; /* Terminate start address. */
- while (isspace ((int) *tmp))
- tmp++;
+ tmp = skip_spaces (tmp);
start = parse_and_eval_address (args);
stop = parse_and_eval_address (tmp);
}
struct block *block;
const char *symname;
char *save_args = args;
- struct dict_iterator iter;
+ struct block_iterator iter;
int j, count = 0;
struct gdbarch *gdbarch;
int regno;
gdbarch = get_objfile_arch (SYMBOL_SYMTAB (sym)->objfile);
printf_filtered ("Symbol %s is ", symname);
- switch (SYMBOL_CLASS (sym))
+
+ if (SYMBOL_COMPUTED_OPS (sym) != NULL)
+ SYMBOL_COMPUTED_OPS (sym)->describe_location (sym,
+ BLOCK_START (block),
+ gdb_stdout);
+ else
{
- default:
- case LOC_UNDEF: /* Messed up symbol? */
- printf_filtered ("a bogus symbol, class %d.\n",
- SYMBOL_CLASS (sym));
- count--; /* Don't count this one. */
- continue;
- case LOC_CONST:
- printf_filtered ("a constant with value %ld (0x%lx)",
- SYMBOL_VALUE (sym), SYMBOL_VALUE (sym));
- break;
- case LOC_CONST_BYTES:
- printf_filtered ("constant bytes: ");
- if (SYMBOL_TYPE (sym))
- for (j = 0; j < TYPE_LENGTH (SYMBOL_TYPE (sym)); j++)
- fprintf_filtered (gdb_stdout, " %02x",
- (unsigned) SYMBOL_VALUE_BYTES (sym)[j]);
- break;
- case LOC_STATIC:
- printf_filtered ("in static storage at address ");
- printf_filtered ("%s", paddress (gdbarch,
- SYMBOL_VALUE_ADDRESS (sym)));
- break;
- case LOC_REGISTER:
- /* GDBARCH is the architecture associated with the objfile
- the symbol is defined in; the target architecture may be
- different, and may provide additional registers. However,
- we do not know the target architecture at this point.
- We assume the objfile architecture will contain all the
- standard registers that occur in debug info in that
- objfile. */
- regno = SYMBOL_REGISTER_OPS (sym)->register_number (sym,
- gdbarch);
-
- if (SYMBOL_IS_ARGUMENT (sym))
- printf_filtered ("an argument in register $%s",
- gdbarch_register_name (gdbarch, regno));
- else
- printf_filtered ("a local variable in register $%s",
- gdbarch_register_name (gdbarch, regno));
- break;
- case LOC_ARG:
- printf_filtered ("an argument at stack/frame offset %ld",
- SYMBOL_VALUE (sym));
- break;
- case LOC_LOCAL:
- printf_filtered ("a local variable at frame offset %ld",
- SYMBOL_VALUE (sym));
- break;
- case LOC_REF_ARG:
- printf_filtered ("a reference argument at offset %ld",
- SYMBOL_VALUE (sym));
- break;
- case LOC_REGPARM_ADDR:
- /* Note comment at LOC_REGISTER. */
- regno = SYMBOL_REGISTER_OPS (sym)->register_number (sym,
- gdbarch);
- printf_filtered ("the address of an argument, in register $%s",
- gdbarch_register_name (gdbarch, regno));
- break;
- case LOC_TYPEDEF:
- printf_filtered ("a typedef.\n");
- continue;
- case LOC_LABEL:
- printf_filtered ("a label at address ");
- printf_filtered ("%s", paddress (gdbarch,
- SYMBOL_VALUE_ADDRESS (sym)));
- break;
- case LOC_BLOCK:
- printf_filtered ("a function at address ");
- printf_filtered ("%s",
- paddress (gdbarch, BLOCK_START (SYMBOL_BLOCK_VALUE (sym))));
- break;
- case LOC_UNRESOLVED:
- msym = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (sym),
- NULL, NULL);
- if (msym == NULL)
- printf_filtered ("Unresolved Static");
- else
+ switch (SYMBOL_CLASS (sym))
{
- printf_filtered ("static storage at address ");
+ default:
+ case LOC_UNDEF: /* Messed up symbol? */
+ printf_filtered ("a bogus symbol, class %d.\n",
+ SYMBOL_CLASS (sym));
+ count--; /* Don't count this one. */
+ continue;
+ case LOC_CONST:
+ printf_filtered ("a constant with value %s (%s)",
+ plongest (SYMBOL_VALUE (sym)),
+ hex_string (SYMBOL_VALUE (sym)));
+ break;
+ case LOC_CONST_BYTES:
+ printf_filtered ("constant bytes: ");
+ if (SYMBOL_TYPE (sym))
+ for (j = 0; j < TYPE_LENGTH (SYMBOL_TYPE (sym)); j++)
+ fprintf_filtered (gdb_stdout, " %02x",
+ (unsigned) SYMBOL_VALUE_BYTES (sym)[j]);
+ break;
+ case LOC_STATIC:
+ printf_filtered ("in static storage at address ");
+ printf_filtered ("%s", paddress (gdbarch,
+ SYMBOL_VALUE_ADDRESS (sym)));
+ break;
+ case LOC_REGISTER:
+ /* GDBARCH is the architecture associated with the objfile
+ the symbol is defined in; the target architecture may be
+ different, and may provide additional registers. However,
+ we do not know the target architecture at this point.
+ We assume the objfile architecture will contain all the
+ standard registers that occur in debug info in that
+ objfile. */
+ regno = SYMBOL_REGISTER_OPS (sym)->register_number (sym,
+ gdbarch);
+
+ if (SYMBOL_IS_ARGUMENT (sym))
+ printf_filtered ("an argument in register $%s",
+ gdbarch_register_name (gdbarch, regno));
+ else
+ printf_filtered ("a local variable in register $%s",
+ gdbarch_register_name (gdbarch, regno));
+ break;
+ case LOC_ARG:
+ printf_filtered ("an argument at stack/frame offset %s",
+ plongest (SYMBOL_VALUE (sym)));
+ break;
+ case LOC_LOCAL:
+ printf_filtered ("a local variable at frame offset %s",
+ plongest (SYMBOL_VALUE (sym)));
+ break;
+ case LOC_REF_ARG:
+ printf_filtered ("a reference argument at offset %s",
+ plongest (SYMBOL_VALUE (sym)));
+ break;
+ case LOC_REGPARM_ADDR:
+ /* Note comment at LOC_REGISTER. */
+ regno = SYMBOL_REGISTER_OPS (sym)->register_number (sym,
+ gdbarch);
+ printf_filtered ("the address of an argument, in register $%s",
+ gdbarch_register_name (gdbarch, regno));
+ break;
+ case LOC_TYPEDEF:
+ printf_filtered ("a typedef.\n");
+ continue;
+ case LOC_LABEL:
+ printf_filtered ("a label at address ");
+ printf_filtered ("%s", paddress (gdbarch,
+ SYMBOL_VALUE_ADDRESS (sym)));
+ break;
+ case LOC_BLOCK:
+ printf_filtered ("a function at address ");
printf_filtered ("%s",
- paddress (gdbarch, SYMBOL_VALUE_ADDRESS (msym)));
+ paddress (gdbarch, BLOCK_START (SYMBOL_BLOCK_VALUE (sym))));
+ break;
+ case LOC_UNRESOLVED:
+ msym = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (sym),
+ NULL, NULL);
+ if (msym == NULL)
+ printf_filtered ("Unresolved Static");
+ else
+ {
+ printf_filtered ("static storage at address ");
+ printf_filtered ("%s",
+ paddress (gdbarch,
+ SYMBOL_VALUE_ADDRESS (msym)));
+ }
+ break;
+ case LOC_OPTIMIZED_OUT:
+ printf_filtered ("optimized out.\n");
+ continue;
+ case LOC_COMPUTED:
+ gdb_assert_not_reached (_("LOC_COMPUTED variable missing a method"));
}
- break;
- case LOC_OPTIMIZED_OUT:
- printf_filtered ("optimized out.\n");
- continue;
- case LOC_COMPUTED:
- SYMBOL_COMPUTED_OPS (sym)->describe_location (sym,
- BLOCK_START (block),
- gdb_stdout);
- break;
}
if (SYMBOL_TYPE (sym))
printf_filtered (", length %d.\n",
save_args);
}
-/* worker function (cleanup) */
-static void
-replace_comma (void *data)
-{
- char *comma = data;
- *comma = ',';
-}
-
-
/* Helper for trace_dump_command. Dump the action list starting at
ACTION. STEPPING_ACTIONS is true if we're iterating over the
actions of the body of a while-stepping action. STEPPING_FRAME is
int stepping_actions, int stepping_frame,
int from_tty)
{
- char *action_exp, *next_comma;
+ const char *action_exp, *next_comma;
for (; action != NULL; action = action->next)
{
QUIT; /* Allow user to bail out with ^C. */
action_exp = action->line;
- while (isspace ((int) *action_exp))
- action_exp++;
+ action_exp = skip_spaces_const (action_exp);
/* The collection actions to be done while stepping are
bracketed by the commands "while-stepping" and "end". */
STEPPING_ACTIONS should be equal. */
if (stepping_frame == stepping_actions)
{
+ char *cmd = NULL;
+ struct cleanup *old_chain
+ = make_cleanup (free_current_contents, &cmd);
+ int trace_string = 0;
+
if (*action_exp == '/')
- action_exp = decode_agent_options (action_exp);
+ action_exp = decode_agent_options (action_exp, &trace_string);
do
{ /* Repeat over a comma-separated list. */
QUIT; /* Allow user to bail out with ^C. */
if (*action_exp == ',')
action_exp++;
- while (isspace ((int) *action_exp))
- action_exp++;
+ action_exp = skip_spaces_const (action_exp);
next_comma = strchr (action_exp, ',');
args_info (NULL, from_tty);
else
{ /* variable */
- if (next_comma)
+ if (next_comma != NULL)
+ {
+ size_t len = next_comma - action_exp;
+
+ cmd = xrealloc (cmd, len + 1);
+ memcpy (cmd, action_exp, len);
+ cmd[len] = 0;
+ }
+ else
{
- make_cleanup (replace_comma, next_comma);
- *next_comma = '\0';
+ size_t len = strlen (action_exp);
+
+ cmd = xrealloc (cmd, len + 1);
+ memcpy (cmd, action_exp, len + 1);
}
- printf_filtered ("%s = ", action_exp);
- output_command (action_exp, from_tty);
+
+ printf_filtered ("%s = ", cmd);
+ output_command_const (cmd, from_tty);
printf_filtered ("\n");
}
- if (next_comma)
- *next_comma = ',';
action_exp = next_comma;
}
while (action_exp && *action_exp == ',');
+
+ do_cleanups (old_chain);
}
}
}
struct tracepoint *t;
int stepping_frame = 0;
struct bp_location *loc;
- char *line, *default_collect_line = NULL;
+ char *default_collect_line = NULL;
struct command_line *actions, *default_collect_action = NULL;
struct cleanup *old_chain = NULL;
{
default_collect_line = xstrprintf ("collect %s", default_collect);
old_chain = make_cleanup (xfree, default_collect_line);
- line = default_collect_line;
- validate_actionline (&line, &t->base);
+ validate_actionline (default_collect_line, &t->base);
default_collect_action = xmalloc (sizeof (struct command_line));
make_cleanup (xfree, default_collect_action);
default_collect_action->next = actions;
- default_collect_action->line = line;
+ default_collect_action->line = default_collect_line;
actions = default_collect_action;
}
return -1;
}
-extern int trace_regblock_size;
+/* Free trace file writer. */
+
+static void
+trace_file_writer_xfree (void *arg)
+{
+ struct trace_file_writer *writer = arg;
+
+ writer->ops->dtor (writer);
+ xfree (writer);
+}
-/* 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. */
+/* TFILE trace writer. */
-void
-trace_save (const char *filename, int target_does_save)
+struct tfile_trace_file_writer
{
- struct cleanup *cleanup;
+ struct trace_file_writer base;
+
+ /* File pointer to tfile trace file. */
+ FILE *fp;
+ /* Path name of the tfile trace file. */
char *pathname;
+};
+
+/* This is the implementation of trace_file_write_ops method
+ target_save. We just call the generic target
+ target_save_trace_data to do target-side saving. */
+
+static int
+tfile_target_save (struct trace_file_writer *self,
+ const char *filename)
+{
+ int err = target_save_trace_data (filename);
+
+ return (err >= 0);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ dtor. */
+
+static void
+tfile_dtor (struct trace_file_writer *self)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ xfree (writer->pathname);
+
+ if (writer->fp != NULL)
+ fclose (writer->fp);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ start. It creates the trace file FILENAME and registers some
+ cleanups. */
+
+static void
+tfile_start (struct trace_file_writer *self, const char *filename)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ writer->pathname = tilde_expand (filename);
+ writer->fp = fopen (writer->pathname, "wb");
+ if (writer->fp == NULL)
+ error (_("Unable to open file '%s' for saving trace data (%s)"),
+ filename, safe_strerror (errno));
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_header. Write the TFILE header. */
+
+static void
+tfile_write_header (struct trace_file_writer *self)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+ int written;
+
+ /* 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, writer->fp);
+ if (written < 1)
+ perror_with_name (writer->pathname);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_regblock_type. Write the size of register block. */
+
+static void
+tfile_write_regblock_type (struct trace_file_writer *self, int size)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ fprintf (writer->fp, "R %x\n", size);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_status. */
+
+static void
+tfile_write_status (struct trace_file_writer *self,
+ struct trace_status *ts)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ fprintf (writer->fp, "status %c;%s",
+ (ts->running ? '1' : '0'), stop_reason_names[ts->stop_reason]);
+ if (ts->stop_reason == tracepoint_error
+ || ts->stop_reason == tstop_command)
+ {
+ char *buf = (char *) alloca (strlen (ts->stop_desc) * 2 + 1);
+
+ bin2hex ((gdb_byte *) ts->stop_desc, buf, 0);
+ fprintf (writer->fp, ":%s", buf);
+ }
+ fprintf (writer->fp, ":%x", ts->stopping_tracepoint);
+ if (ts->traceframe_count >= 0)
+ fprintf (writer->fp, ";tframes:%x", ts->traceframe_count);
+ if (ts->traceframes_created >= 0)
+ fprintf (writer->fp, ";tcreated:%x", ts->traceframes_created);
+ if (ts->buffer_free >= 0)
+ fprintf (writer->fp, ";tfree:%x", ts->buffer_free);
+ if (ts->buffer_size >= 0)
+ fprintf (writer->fp, ";tsize:%x", ts->buffer_size);
+ if (ts->disconnected_tracing)
+ fprintf (writer->fp, ";disconn:%x", ts->disconnected_tracing);
+ if (ts->circular_buffer)
+ fprintf (writer->fp, ";circular:%x", ts->circular_buffer);
+ if (ts->notes != NULL)
+ {
+ char *buf = (char *) alloca (strlen (ts->notes) * 2 + 1);
+
+ bin2hex ((gdb_byte *) ts->notes, buf, 0);
+ fprintf (writer->fp, ";notes:%s", buf);
+ }
+ if (ts->user_name != NULL)
+ {
+ char *buf = (char *) alloca (strlen (ts->user_name) * 2 + 1);
+
+ bin2hex ((gdb_byte *) ts->user_name, buf, 0);
+ fprintf (writer->fp, ";username:%s", buf);
+ }
+ fprintf (writer->fp, "\n");
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_uploaded_tsv. */
+
+static void
+tfile_write_uploaded_tsv (struct trace_file_writer *self,
+ struct uploaded_tsv *utsv)
+{
+ char *buf = "";
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ if (utsv->name)
+ {
+ buf = (char *) xmalloc (strlen (utsv->name) * 2 + 1);
+ bin2hex ((gdb_byte *) (utsv->name), buf, 0);
+ }
+
+ fprintf (writer->fp, "tsv %x:%s:%x:%s\n",
+ utsv->number, phex_nz (utsv->initial_value, 8),
+ utsv->builtin, buf);
+
+ if (utsv->name)
+ xfree (buf);
+}
+
+#define MAX_TRACE_UPLOAD 2000
+
+/* This is the implementation of trace_file_write_ops method
+ write_uploaded_tp. */
+
+static void
+tfile_write_uploaded_tp (struct trace_file_writer *self,
+ struct uploaded_tp *utp)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+ int a;
+ char *act;
+ gdb_byte buf[MAX_TRACE_UPLOAD];
+
+ fprintf (writer->fp, "tp T%x:%s:%c:%x:%x",
+ utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
+ (utp->enabled ? 'E' : 'D'), utp->step, utp->pass);
+ if (utp->type == bp_fast_tracepoint)
+ fprintf (writer->fp, ":F%x", utp->orig_size);
+ if (utp->cond)
+ fprintf (writer->fp,
+ ":X%x,%s", (unsigned int) strlen (utp->cond) / 2,
+ utp->cond);
+ fprintf (writer->fp, "\n");
+ for (a = 0; VEC_iterate (char_ptr, utp->actions, a, act); ++a)
+ fprintf (writer->fp, "tp A%x:%s:%s\n",
+ utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
+ for (a = 0; VEC_iterate (char_ptr, utp->step_actions, a, act); ++a)
+ fprintf (writer->fp, "tp S%x:%s:%s\n",
+ utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
+ if (utp->at_string)
+ {
+ encode_source_string (utp->number, utp->addr,
+ "at", utp->at_string, buf, MAX_TRACE_UPLOAD);
+ fprintf (writer->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 (writer->fp, "tp Z%s\n", buf);
+ }
+ for (a = 0; VEC_iterate (char_ptr, utp->cmd_strings, a, act); ++a)
+ {
+ encode_source_string (utp->number, utp->addr, "cmd", act,
+ buf, MAX_TRACE_UPLOAD);
+ fprintf (writer->fp, "tp Z%s\n", buf);
+ }
+ fprintf (writer->fp, "tp V%x:%s:%x:%s\n",
+ utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
+ utp->hit_count,
+ phex_nz (utp->traceframe_usage,
+ sizeof (utp->traceframe_usage)));
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_definition_end. */
+
+static void
+tfile_write_definition_end (struct trace_file_writer *self)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ fprintf (writer->fp, "\n");
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_raw_data. */
+
+static void
+tfile_write_raw_data (struct trace_file_writer *self, gdb_byte *buf,
+ LONGEST len)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ if (fwrite (buf, len, 1, writer->fp) < 1)
+ perror_with_name (writer->pathname);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ end. */
+
+static void
+tfile_end (struct trace_file_writer *self)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+ uint32_t gotten = 0;
+
+ /* Mark the end of trace data. */
+ if (fwrite (&gotten, 4, 1, writer->fp) < 1)
+ perror_with_name (writer->pathname);
+}
+
+/* Operations to write trace buffers into TFILE format. */
+
+static const struct trace_file_write_ops tfile_write_ops =
+{
+ tfile_dtor,
+ tfile_target_save,
+ tfile_start,
+ tfile_write_header,
+ tfile_write_regblock_type,
+ tfile_write_status,
+ tfile_write_uploaded_tsv,
+ tfile_write_uploaded_tp,
+ tfile_write_definition_end,
+ tfile_write_raw_data,
+ NULL,
+ tfile_end,
+};
+
+/* Helper macros. */
+
+#define TRACE_WRITE_R_BLOCK(writer, buf, size) \
+ writer->ops->frame_ops->write_r_block ((writer), (buf), (size))
+#define TRACE_WRITE_M_BLOCK_HEADER(writer, addr, size) \
+ writer->ops->frame_ops->write_m_block_header ((writer), (addr), \
+ (size))
+#define TRACE_WRITE_M_BLOCK_MEMORY(writer, buf, size) \
+ writer->ops->frame_ops->write_m_block_memory ((writer), (buf), \
+ (size))
+#define TRACE_WRITE_V_BLOCK(writer, num, val) \
+ writer->ops->frame_ops->write_v_block ((writer), (num), (val))
+
+/* Save tracepoint data to file named FILENAME through WRITER. WRITER
+ determines the trace file format. If TARGET_DOES_SAVE is non-zero,
+ the save is performed on the target, otherwise GDB obtains all trace
+ data and saves it locally. */
+
+static void
+trace_save (const char *filename, struct trace_file_writer *writer,
+ int target_does_save)
+{
struct trace_status *ts = current_trace_status ();
- int err, status;
- FILE *fp;
+ int status;
struct uploaded_tp *uploaded_tps = NULL, *utp;
struct uploaded_tsv *uploaded_tsvs = NULL, *utsv;
- int a;
- char *act;
- LONGEST gotten = 0;
+
ULONGEST offset = 0;
-#define MAX_TRACE_UPLOAD 2000
gdb_byte buf[MAX_TRACE_UPLOAD];
int written;
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
/* 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)
{
- err = target_save_trace_data (filename);
- if (err < 0)
+ if (!writer->ops->target_save (writer, filename))
error (_("Target failed to save trace data to '%s'."),
filename);
return;
target is losing, we can get out without touching files. */
status = target_get_trace_status (ts);
- pathname = tilde_expand (filename);
- cleanup = make_cleanup (xfree, pathname);
-
- fp = fopen (pathname, "wb");
- if (!fp)
- error (_("Unable to open file '%s' for saving trace data (%s)"),
- filename, safe_strerror (errno));
- make_cleanup_fclose (fp);
+ writer->ops->start (writer, filename);
- /* 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 < 1)
- perror_with_name (pathname);
+ writer->ops->write_header (writer);
/* Write descriptive info. */
/* Write out the size of a register block. */
- fprintf (fp, "R %x\n", trace_regblock_size);
+ writer->ops->write_regblock_type (writer, trace_regblock_size);
/* Write out status of the tracing run (aka "tstatus" info). */
- 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->stop_desc) * 2 + 1);
-
- bin2hex ((gdb_byte *) ts->stop_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);
- if (ts->disconnected_tracing)
- fprintf (fp, ";disconn:%x", ts->disconnected_tracing);
- if (ts->circular_buffer)
- fprintf (fp, ";circular:%x", ts->circular_buffer);
- fprintf (fp, "\n");
+ writer->ops->write_status (writer, ts);
/* Note that we want to upload tracepoints and save those, rather
than simply writing out the local ones, because the user may have
target_upload_trace_state_variables (&uploaded_tsvs);
for (utsv = uploaded_tsvs; utsv; utsv = utsv->next)
- {
- char *buf = "";
-
- if (utsv->name)
- {
- buf = (char *) xmalloc (strlen (utsv->name) * 2 + 1);
- bin2hex ((gdb_byte *) (utsv->name), buf, 0);
- }
-
- fprintf (fp, "tsv %x:%s:%x:%s\n",
- utsv->number, phex_nz (utsv->initial_value, 8),
- utsv->builtin, buf);
-
- if (utsv->name)
- xfree (buf);
- }
+ writer->ops->write_uploaded_tsv (writer, utsv);
free_uploaded_tsvs (&uploaded_tsvs);
target_get_tracepoint_status (NULL, utp);
for (utp = uploaded_tps; utp; utp = utp->next)
+ writer->ops->write_uploaded_tp (writer, utp);
+
+ free_uploaded_tps (&uploaded_tps);
+
+ /* Mark the end of the definition section. */
+ writer->ops->write_definition_end (writer);
+
+ /* Get and write the trace data proper. */
+ while (1)
{
- fprintf (fp, "tp T%x:%s:%c:%x:%x",
- utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
- (utp->enabled ? 'E' : 'D'), utp->step, utp->pass);
- if (utp->type == bp_fast_tracepoint)
- fprintf (fp, ":F%x", utp->orig_size);
- if (utp->cond)
- fprintf (fp, ":X%x,%s", (unsigned int) strlen (utp->cond) / 2,
- utp->cond);
- fprintf (fp, "\n");
- for (a = 0; VEC_iterate (char_ptr, utp->actions, a, act); ++a)
- fprintf (fp, "tp A%x:%s:%s\n",
- utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
- for (a = 0; VEC_iterate (char_ptr, utp->step_actions, a, act); ++a)
- fprintf (fp, "tp S%x:%s:%s\n",
- utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
- 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)
+ LONGEST gotten = 0;
+
+ /* The writer supports writing the contents of trace buffer
+ directly to trace file. Don't parse the contents of trace
+ buffer. */
+ if (writer->ops->write_trace_buffer != NULL)
{
- encode_source_string (utp->number, utp->addr,
- "cond", utp->cond_string,
- buf, MAX_TRACE_UPLOAD);
- fprintf (fp, "tp Z%s\n", buf);
+ /* We ask for big blocks, in the hopes of efficiency, but
+ will take less if the target has packet size limitations
+ or some such. */
+ gotten = target_get_raw_trace_data (buf, offset,
+ MAX_TRACE_UPLOAD);
+ if (gotten < 0)
+ error (_("Failure to get requested trace buffer data"));
+ /* No more data is forthcoming, we're done. */
+ if (gotten == 0)
+ break;
+
+ writer->ops->write_trace_buffer (writer, buf, gotten);
+
+ offset += gotten;
}
- for (a = 0; VEC_iterate (char_ptr, utp->cmd_strings, a, act); ++a)
+ else
{
- encode_source_string (utp->number, utp->addr, "cmd", act,
- buf, MAX_TRACE_UPLOAD);
- fprintf (fp, "tp Z%s\n", buf);
+ uint16_t tp_num;
+ uint32_t tf_size;
+ /* Parse the trace buffers according to how data are stored
+ in trace buffer in GDBserver. */
+
+ gotten = target_get_raw_trace_data (buf, offset, 6);
+
+ if (gotten == 0)
+ break;
+
+ /* Read the first six bytes in, which is the tracepoint
+ number and trace frame size. */
+ tp_num = (uint16_t)
+ extract_unsigned_integer (&buf[0], 2, byte_order);
+
+ tf_size = (uint32_t)
+ extract_unsigned_integer (&buf[2], 4, byte_order);
+
+ writer->ops->frame_ops->start (writer, tp_num);
+ gotten = 6;
+
+ if (tf_size > 0)
+ {
+ unsigned int block;
+
+ offset += 6;
+
+ for (block = 0; block < tf_size; )
+ {
+ gdb_byte block_type;
+
+ /* We'll fetch one block each time, in order to
+ handle the extremely large 'M' block. We first
+ fetch one byte to get the type of the block. */
+ gotten = target_get_raw_trace_data (buf, offset, 1);
+ if (gotten < 1)
+ error (_("Failure to get requested trace buffer data"));
+
+ gotten = 1;
+ block += 1;
+ offset += 1;
+
+ block_type = buf[0];
+ switch (block_type)
+ {
+ case 'R':
+ gotten
+ = target_get_raw_trace_data (buf, offset,
+ trace_regblock_size);
+ if (gotten < trace_regblock_size)
+ error (_("Failure to get requested trace"
+ " buffer data"));
+
+ TRACE_WRITE_R_BLOCK (writer, buf,
+ trace_regblock_size);
+ break;
+ case 'M':
+ {
+ unsigned short mlen;
+ ULONGEST addr;
+ LONGEST t;
+ int j;
+
+ t = target_get_raw_trace_data (buf,offset, 10);
+ if (t < 10)
+ error (_("Failure to get requested trace"
+ " buffer data"));
+
+ offset += 10;
+ block += 10;
+
+ gotten = 0;
+ addr = (ULONGEST)
+ extract_unsigned_integer (buf, 8,
+ byte_order);
+ mlen = (unsigned short)
+ extract_unsigned_integer (&buf[8], 2,
+ byte_order);
+
+ TRACE_WRITE_M_BLOCK_HEADER (writer, addr,
+ mlen);
+
+ /* The memory contents in 'M' block may be
+ very large. Fetch the data from the target
+ and write them into file one by one. */
+ for (j = 0; j < mlen; )
+ {
+ unsigned int read_length;
+
+ if (mlen - j > MAX_TRACE_UPLOAD)
+ read_length = MAX_TRACE_UPLOAD;
+ else
+ read_length = mlen - j;
+
+ t = target_get_raw_trace_data (buf,
+ offset + j,
+ read_length);
+ if (t < read_length)
+ error (_("Failure to get requested"
+ " trace buffer data"));
+
+ TRACE_WRITE_M_BLOCK_MEMORY (writer, buf,
+ read_length);
+
+ j += read_length;
+ gotten += read_length;
+ }
+
+ break;
+ }
+ case 'V':
+ {
+ int vnum;
+ LONGEST val;
+
+ gotten
+ = target_get_raw_trace_data (buf, offset,
+ 12);
+ if (gotten < 12)
+ error (_("Failure to get requested"
+ " trace buffer data"));
+
+ vnum = (int) extract_signed_integer (buf,
+ 4,
+ byte_order);
+ val
+ = extract_signed_integer (&buf[4], 8,
+ byte_order);
+
+ TRACE_WRITE_V_BLOCK (writer, vnum, val);
+ }
+ break;
+ default:
+ error (_("Unknown block type '%c' (0x%x) in"
+ " trace frame"),
+ block_type, block_type);
+ }
+
+ block += gotten;
+ offset += gotten;
+ }
+ }
+ else
+ offset += gotten;
+
+ writer->ops->frame_ops->end (writer);
}
- fprintf (fp, "tp V%x:%s:%x:%s\n",
- utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
- utp->hit_count,
- phex_nz (utp->traceframe_usage,
- sizeof (utp->traceframe_usage)));
}
- free_uploaded_tps (&uploaded_tps);
+ writer->ops->end (writer);
+}
- /* Mark the end of the definition section. */
- fprintf (fp, "\n");
+/* Return a trace writer for TFILE format. */
- /* Get and write the trace data proper. We ask for big blocks, in
- the hopes of efficiency, but will take less if the target has
- packet size limitations or some such. */
- while (1)
- {
- gotten = target_get_raw_trace_data (buf, offset, MAX_TRACE_UPLOAD);
- if (gotten < 0)
- error (_("Failure to get requested trace buffer data"));
- /* No more data is forthcoming, we're done. */
- if (gotten == 0)
- break;
- written = fwrite (buf, gotten, 1, fp);
- if (written < 1)
- perror_with_name (pathname);
- offset += gotten;
- }
+static struct trace_file_writer *
+tfile_trace_file_writer_new (void)
+{
+ struct tfile_trace_file_writer *writer
+ = xmalloc (sizeof (struct tfile_trace_file_writer));
- /* Mark the end of trace data. (We know that gotten is 0 at this point.) */
- written = fwrite (&gotten, 4, 1, fp);
- if (written < 1)
- perror_with_name (pathname);
+ writer->base.ops = &tfile_write_ops;
+ writer->fp = NULL;
+ writer->pathname = NULL;
- do_cleanups (cleanup);
+ return (struct trace_file_writer *) writer;
}
static void
char **argv;
char *filename = NULL;
struct cleanup *back_to;
+ int generate_ctf = 0;
+ struct trace_file_writer *writer = NULL;
if (args == NULL)
error_no_arg (_("file in which to save trace data"));
{
if (strcmp (*argv, "-r") == 0)
target_does_save = 1;
+ if (strcmp (*argv, "-ctf") == 0)
+ generate_ctf = 1;
else if (**argv == '-')
error (_("unknown option `%s'"), *argv);
else
if (!filename)
error_no_arg (_("file in which to save trace data"));
- trace_save (filename, target_does_save);
+ if (generate_ctf)
+ writer = ctf_trace_file_writer_new ();
+ else
+ writer = tfile_trace_file_writer_new ();
+
+ make_cleanup (trace_file_writer_xfree, writer);
+
+ trace_save (filename, writer, target_does_save);
if (from_tty)
- printf_filtered (_("Trace data saved to file '%s'.\n"), filename);
+ printf_filtered (_("Trace data saved to %s '%s'.\n"),
+ generate_ctf ? "directory" : "file", filename);
+
+ do_cleanups (back_to);
+}
+
+/* Save the trace data to file FILENAME of tfile format. */
+
+void
+trace_save_tfile (const char *filename, int target_does_save)
+{
+ struct trace_file_writer *writer;
+ struct cleanup *back_to;
+
+ writer = tfile_trace_file_writer_new ();
+ back_to = make_cleanup (trace_file_writer_xfree, writer);
+ trace_save (filename, writer, target_does_save);
+ do_cleanups (back_to);
+}
+
+/* Save the trace data to dir DIRNAME of ctf format. */
+void
+trace_save_ctf (const char *dirname, int target_does_save)
+{
+ struct trace_file_writer *writer;
+ struct cleanup *back_to;
+
+ writer = ctf_trace_file_writer_new ();
+ back_to = make_cleanup (trace_file_writer_xfree, writer);
+
+ trace_save (dirname, writer, target_does_save);
do_cleanups (back_to);
}
target_set_circular_trace_buffer (circular_trace_buffer);
}
+static void
+set_trace_buffer_size (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ target_set_trace_buffer_size (trace_buffer_size);
+}
+
static void
set_trace_user (char *args, int from_tty,
struct cmd_list_element *c)
ret = target_set_trace_notes (trace_user, NULL, NULL);
if (!ret)
- warning ("Target does not support trace notes, user ignored");
+ warning (_("Target does not support trace notes, user ignored"));
}
static void
ret = target_set_trace_notes (NULL, trace_notes, NULL);
if (!ret)
- warning ("Target does not support trace notes, note ignored");
+ warning (_("Target does not support trace notes, note ignored"));
}
static void
ret = target_set_trace_notes (NULL, NULL, trace_stop_notes);
if (!ret)
- warning ("Target does not support trace notes, stop note ignored");
+ warning (_("Target does not support trace notes, stop note ignored"));
}
/* Convert the memory pointed to by mem into hex, placing result in buf.
return traceframe_number;
}
+int
+get_tracepoint_number (void)
+{
+ return tracepoint_number;
+}
+
/* Make the traceframe NUM be the current trace frame. Does nothing
if NUM is already current. */
if (newnum != num)
warning (_("could not change traceframe"));
- traceframe_number = newnum;
+ set_traceframe_num (newnum);
/* Changing the traceframe changes our view of registers and of the
frame chain. */
toggle that freely, and may have done so in anticipation of the
next trace run. Return the location of matched tracepoint. */
-struct bp_location *
+static struct bp_location *
find_matching_tracepoint_location (struct uploaded_tp *utp)
{
VEC(breakpoint_p) *tp_vec = all_tracepoints ();
merge_uploaded_tracepoints (struct uploaded_tp **uploaded_tps)
{
struct uploaded_tp *utp;
+ /* A set of tracepoints which are modified. */
+ VEC(breakpoint_p) *modified_tp = NULL;
+ int ix;
+ struct breakpoint *b;
/* Look for GDB tracepoints that match up with our uploaded versions. */
for (utp = *uploaded_tps; utp; utp = utp->next)
loc = find_matching_tracepoint_location (utp);
if (loc)
{
+ int found = 0;
+
/* Mark this location as already inserted. */
loc->inserted = 1;
t = (struct tracepoint *) loc->owner;
"as target's tracepoint %d at %s.\n"),
loc->owner->number, utp->number,
paddress (loc->gdbarch, utp->addr));
+
+ /* The tracepoint LOC->owner was modified (the location LOC
+ was marked as inserted in the target). Save it in
+ MODIFIED_TP if not there yet. The 'breakpoint-modified'
+ observers will be notified later once for each tracepoint
+ saved in MODIFIED_TP. */
+ for (ix = 0;
+ VEC_iterate (breakpoint_p, modified_tp, ix, b);
+ ix++)
+ if (b == loc->owner)
+ {
+ found = 1;
+ break;
+ }
+ if (!found)
+ VEC_safe_push (breakpoint_p, modified_tp, loc->owner);
}
else
{
t->number_on_target = utp->number;
}
+ /* Notify 'breakpoint-modified' observer that at least one of B's
+ locations was changed. */
+ for (ix = 0; VEC_iterate (breakpoint_p, modified_tp, ix, b); ix++)
+ observer_notify_breakpoint_modified (b);
+
+ VEC_free (breakpoint_p, modified_tp);
free_uploaded_tps (uploaded_tps);
}
/* Trace state variables don't have much to identify them beyond their
name, so just use that to detect matches. */
-struct trace_state_variable *
+static struct trace_state_variable *
find_matching_tsv (struct uploaded_tsv *utsv)
{
if (!utsv->name)
return find_trace_state_variable (utsv->name);
}
-struct trace_state_variable *
+static struct trace_state_variable *
create_tsv_from_upload (struct uploaded_tsv *utsv)
{
const char *namebase;
tsv->initial_value = utsv->initial_value;
tsv->builtin = utsv->builtin;
+ observer_notify_tsv_created (tsv);
+
do_cleanups (old_chain);
return tsv;
/* target tfile command */
-struct target_ops tfile_ops;
+static struct target_ops tfile_ops;
/* Fill in tfile_ops with its defined operations and properties. */
#define TRACE_HEADER_SIZE 8
-char *trace_filename;
-int trace_fd = -1;
-off_t trace_frames_offset;
-off_t cur_offset;
-int cur_traceframe_number;
-int cur_data_size;
+static char *trace_filename;
+static int trace_fd = -1;
+static off_t trace_frames_offset;
+static off_t cur_offset;
+static int cur_data_size;
int trace_regblock_size;
static void tfile_interp_line (char *line,
trace_regblock_size = 0;
ts = current_trace_status ();
- /* We know we're working with a file. */
- ts->from_file = 1;
+ /* We know we're working with a file. Record its name. */
+ ts->filename = trace_filename;
/* Set defaults in case there is no status line. */
ts->running_known = 0;
ts->stop_reason = trace_stop_reason_unknown;
ts->disconnected_tracing = 0;
ts->circular_buffer = 0;
- cur_traceframe_number = -1;
-
TRY_CATCH (ex, RETURN_MASK_ALL)
{
/* Read through a section of newline-terminated lines that
/* Close the trace file and generally clean up. */
static void
-tfile_close (int quitting)
+tfile_close (void)
{
int pid;
static void
tfile_files_info (struct target_ops *t)
{
- /* (it would be useful to mention the name of the file). */
- printf_filtered ("Looking at a trace file.\n");
+ printf_filtered ("\t`%s'\n", trace_filename);
}
/* The trace status for a file is that tracing can never be run. */
value of a collected PC register, but if not available, we
improvise. */
-static ULONGEST
+static CORE_ADDR
tfile_get_traceframe_address (off_t tframe_offset)
{
- ULONGEST addr = 0;
+ CORE_ADDR addr = 0;
short tpnum;
struct tracepoint *tp;
off_t saved_offset = cur_offset;
tfile_read ((gdb_byte *) &tpnum, 2);
tpnum = (short) extract_signed_integer ((gdb_byte *) &tpnum, 2,
gdbarch_byte_order
- (target_gdbarch));
+ (target_gdbarch ()));
tp = get_tracepoint_by_number_on_target (tpnum);
/* FIXME this is a poor heuristic if multiple locations. */
return addr;
}
-/* Make tfile's selected traceframe match GDB's selected
- traceframe. */
-
-static void
-set_tfile_traceframe (void)
-{
- int newnum;
-
- if (cur_traceframe_number == get_traceframe_number ())
- return;
-
- /* Avoid recursion, tfile_trace_find calls us again. */
- cur_traceframe_number = get_traceframe_number ();
-
- newnum = target_trace_find (tfind_number,
- get_traceframe_number (), 0, 0, NULL);
-
- /* Should not happen. If it does, all bets are off. */
- if (newnum != get_traceframe_number ())
- warning (_("could not set tfile's traceframe"));
-}
-
/* Given a type of search and some parameters, scan the collection of
traceframes in the file looking for a match. When found, return
both the traceframe and tracepoint number, otherwise -1 for
static int
tfile_trace_find (enum trace_find_type type, int num,
- ULONGEST addr1, ULONGEST addr2, int *tpp)
+ CORE_ADDR addr1, CORE_ADDR addr2, int *tpp)
{
short tpnum;
int tfnum = 0, found = 0;
unsigned int data_size;
struct tracepoint *tp;
off_t offset, tframe_offset;
- ULONGEST tfaddr;
-
- /* Lookups other than by absolute frame number depend on the current
- trace selected, so make sure it is correct on the tfile end
- first. */
- if (type != tfind_number)
- set_tfile_traceframe ();
- else if (num == -1)
+ CORE_ADDR tfaddr;
+
+ if (num == -1)
{
if (tpp)
*tpp = -1;
tfile_read ((gdb_byte *) &tpnum, 2);
tpnum = (short) extract_signed_integer ((gdb_byte *) &tpnum, 2,
gdbarch_byte_order
- (target_gdbarch));
+ (target_gdbarch ()));
offset += 2;
if (tpnum == 0)
break;
tfile_read ((gdb_byte *) &data_size, 4);
data_size = (unsigned int) extract_unsigned_integer
((gdb_byte *) &data_size, 4,
- gdbarch_byte_order (target_gdbarch));
+ gdbarch_byte_order (target_gdbarch ()));
offset += 4;
- switch (type)
+
+ if (type == tfind_number)
{
- case tfind_number:
+ /* Looking for a specific trace frame. */
if (tfnum == num)
found = 1;
- break;
- case tfind_pc:
- tfaddr = tfile_get_traceframe_address (tframe_offset);
- if (tfaddr == addr1)
- found = 1;
- break;
- case tfind_tp:
- tp = get_tracepoint (num);
- if (tp && tpnum == tp->number_on_target)
- found = 1;
- break;
- case tfind_range:
- tfaddr = tfile_get_traceframe_address (tframe_offset);
- if (addr1 <= tfaddr && tfaddr <= addr2)
- found = 1;
- break;
- case tfind_outside:
- tfaddr = tfile_get_traceframe_address (tframe_offset);
- if (!(addr1 <= tfaddr && tfaddr <= addr2))
- found = 1;
- break;
- default:
- internal_error (__FILE__, __LINE__, _("unknown tfind type"));
}
+ else
+ {
+ /* Start from the _next_ trace frame. */
+ if (tfnum > traceframe_number)
+ {
+ switch (type)
+ {
+ case tfind_pc:
+ tfaddr = tfile_get_traceframe_address (tframe_offset);
+ if (tfaddr == addr1)
+ found = 1;
+ break;
+ case tfind_tp:
+ tp = get_tracepoint (num);
+ if (tp && tpnum == tp->number_on_target)
+ found = 1;
+ break;
+ case tfind_range:
+ tfaddr = tfile_get_traceframe_address (tframe_offset);
+ if (addr1 <= tfaddr && tfaddr <= addr2)
+ found = 1;
+ break;
+ case tfind_outside:
+ tfaddr = tfile_get_traceframe_address (tframe_offset);
+ if (!(addr1 <= tfaddr && tfaddr <= addr2))
+ found = 1;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, _("unknown tfind type"));
+ }
+ }
+ }
+
if (found)
{
if (tpp)
*tpp = tpnum;
cur_offset = offset;
cur_data_size = data_size;
- cur_traceframe_number = tfnum;
+
return tfnum;
}
/* Skip past the traceframe's data. */
mlen = (unsigned short)
extract_unsigned_integer ((gdb_byte *) &mlen, 2,
gdbarch_byte_order
- (target_gdbarch));
+ (target_gdbarch ()));
lseek (trace_fd, mlen, SEEK_CUR);
pos += (8 + 2 + mlen);
break;
struct regcache *regcache, int regno)
{
struct gdbarch *gdbarch = get_regcache_arch (regcache);
- char block_type;
- int pos, offset, regn, regsize, pc_regno;
- unsigned short mlen;
+ int offset, regn, regsize, pc_regno;
char *regs;
/* An uninitialized reg size says we're not going to be
if (!trace_regblock_size)
return;
- set_tfile_traceframe ();
-
regs = alloca (trace_regblock_size);
if (traceframe_find_block_type ('R', 0) >= 0)
if (readbuf == NULL)
error (_("tfile_xfer_partial: trace file is read-only"));
- set_tfile_traceframe ();
-
if (traceframe_number != -1)
{
int pos = 0;
{
ULONGEST maddr, amt;
unsigned short mlen;
- enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
tfile_read ((gdb_byte *) &maddr, 8);
maddr = extract_unsigned_integer ((gdb_byte *) &maddr, 8,
if (amt > len)
amt = len;
+ if (maddr != offset)
+ lseek (trace_fd, offset - maddr, SEEK_CUR);
tfile_read (readbuf, amt);
return amt;
}
tfile_get_trace_state_variable_value (int tsvnum, LONGEST *val)
{
int pos;
+ int found = 0;
- set_tfile_traceframe ();
-
+ /* Iterate over blocks in current frame and find the last 'V'
+ block in which tsv number is TSVNUM. In one trace frame, there
+ may be multiple 'V' blocks created for a given trace variable,
+ and the last matched 'V' block contains the updated value. */
pos = 0;
while ((pos = traceframe_find_block_type ('V', pos)) >= 0)
{
tfile_read ((gdb_byte *) &vnum, 4);
vnum = (int) extract_signed_integer ((gdb_byte *) &vnum, 4,
gdbarch_byte_order
- (target_gdbarch));
+ (target_gdbarch ()));
if (tsvnum == vnum)
{
tfile_read ((gdb_byte *) val, 8);
*val = extract_signed_integer ((gdb_byte *) val, 8,
gdbarch_byte_order
- (target_gdbarch));
- return 1;
+ (target_gdbarch ()));
+ found = 1;
}
pos += (4 + 8);
}
- /* Didn't find anything. */
- return 0;
+ return found;
}
static int
unsigned short mlen;
tfile_read ((gdb_byte *) &maddr, 8);
+ maddr = extract_unsigned_integer ((gdb_byte *) &maddr, 8,
+ gdbarch_byte_order
+ (target_gdbarch ()));
tfile_read ((gdb_byte *) &mlen, 2);
+ mlen = (unsigned short)
+ extract_unsigned_integer ((gdb_byte *) &mlen,
+ 2, gdbarch_byte_order
+ (target_gdbarch ()));
r = VEC_safe_push (mem_range_s, info->memory, NULL);
tfile_ops.to_magic = OPS_MAGIC;
}
+void
+free_current_marker (void *arg)
+{
+ struct static_tracepoint_marker **marker_p = arg;
+
+ if (*marker_p != NULL)
+ {
+ release_static_tracepoint_marker (*marker_p);
+ xfree (*marker_p);
+ }
+ else
+ *marker_p = NULL;
+}
+
/* Given a line of text defining a static tracepoint marker, parse it
into a "static tracepoint marker" object. Throws an error is
parsing fails. If PP is non-null, it points to one past the end of
p = unpack_varlen_hex (p, &addr);
p++; /* skip a colon */
- marker->gdbarch = target_gdbarch;
+ marker->gdbarch = target_gdbarch ();
marker->address = (CORE_ADDR) addr;
endp = strchr (p, ':');
char wrap_indent[80];
char extra_field_indent[80];
struct ui_out *uiout = current_uiout;
- struct ui_stream *stb = ui_out_stream_new (uiout);
- struct cleanup *old_chain = make_cleanup_ui_out_stream_delete (stb);
struct cleanup *bkpt_chain;
VEC(breakpoint_p) *tracepoints;
if (sal.symtab != NULL)
{
- ui_out_field_string (uiout, "file", sal.symtab->filename);
+ ui_out_field_string (uiout, "file",
+ symtab_to_filename_for_display (sal.symtab));
ui_out_text (uiout, ":");
if (ui_out_is_mi_like_p (uiout))
{
- char *fullname = symtab_to_fullname (sal.symtab);
+ const char *fullname = symtab_to_fullname (sal.symtab);
- if (fullname)
- ui_out_field_string (uiout, "fullname", fullname);
+ ui_out_field_string (uiout, "fullname", fullname);
}
else
ui_out_field_skip (uiout, "fullname");
VEC_free (breakpoint_p, tracepoints);
do_cleanups (bkpt_chain);
- do_cleanups (old_chain);
}
static void
struct ui_out *uiout = current_uiout;
int i;
+ /* We don't have to check target_can_use_agent and agent's capability on
+ static tracepoint here, in order to be compatible with older GDBserver.
+ We don't check USE_AGENT is true or not, because static tracepoints
+ don't work without in-process agent, so we don't bother users to type
+ `set agent on' when to use static tracepoint. */
+
old_chain
= make_cleanup_ui_out_table_begin_end (uiout, 5, -1,
"StaticTracepointMarkersTable");
ui_out_table_header (uiout, 40, ui_left, "marker-id", "ID");
ui_out_table_header (uiout, 3, ui_left, "enabled", "Enb");
- if (gdbarch_addr_bit (target_gdbarch) <= 32)
+ if (gdbarch_addr_bit (target_gdbarch ()) <= 32)
ui_out_table_header (uiout, 10, ui_left, "addr", "Address");
else
ui_out_table_header (uiout, 18, ui_left, "addr", "Address");
available. */
static struct value *
-sdata_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+sdata_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+ void *ignore)
{
LONGEST size;
gdb_byte *buf;
This is where we avoid re-fetching the object from the target if we
already have it cached. */
-struct traceframe_info *
+static struct traceframe_info *
get_traceframe_info (void)
{
if (traceframe_info == NULL)
return 0;
}
+/* Implementation of `sdata' variable. */
+
+static const struct internalvar_funcs sdata_funcs =
+{
+ sdata_make_value,
+ NULL,
+ NULL
+};
+
/* module initialization */
void
_initialize_tracepoint (void)
value with a void typed value, and when we get here, gdbarch
isn't initialized yet. At this point, we're quite sure there
isn't another convenience variable of the same name. */
- create_internalvar_type_lazy ("_sdata", sdata_make_value);
+ create_internalvar_type_lazy ("_sdata", &sdata_funcs, NULL);
traceframe_number = -1;
tracepoint_number = -1;
add_com ("tsave", class_trace, trace_save_command, _("\
Save the trace data to a file.\n\
+Use the '-ctf' option to save the data to CTF format.\n\
Use the '-r' option to direct the target to save directly to the file,\n\
using its own filesystem."));
&tfindlist);
add_cmd ("end", class_trace, trace_find_end_command, _("\
-Synonym for 'none'.\n\
De-select any trace frame and resume 'live' debugging."),
&tfindlist);
- add_cmd ("none", class_trace, trace_find_none_command,
- _("De-select any trace frame and resume 'live' debugging."),
- &tfindlist);
+ add_alias_cmd ("none", "end", class_trace, 0, &tfindlist);
add_cmd ("start", class_trace, trace_find_start_command,
_("Select the first trace frame in the trace buffer."),
&setlist,
&showlist);
+ add_setshow_zuinteger_unlimited_cmd ("trace-buffer-size", no_class,
+ &trace_buffer_size, _("\
+Set requested size of trace buffer."), _("\
+Show requested size of trace buffer."), _("\
+Use this to choose a size for the trace buffer. Some targets\n\
+may have fixed or limited buffer sizes. A value of -1 disables\n\
+any attempt to set the buffer size and lets the target choose."),
+ set_trace_buffer_size, NULL,
+ &setlist, &showlist);
+
add_setshow_string_cmd ("trace-user", class_trace,
&trace_user, _("\
Set the user name to use for current and future trace runs"), _("\
init_tfile_ops ();
- add_target (&tfile_ops);
+ add_target_with_completer (&tfile_ops, filename_completer);
}