Index: gdb/tracepoint.c |
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c |
index 0fc4ea4bae25587149096916f6e0980a86139b77..f30282bad50ef025fe14ce930bd30c1cff923e55 100644 |
--- a/gdb/tracepoint.c |
+++ b/gdb/tracepoint.c |
@@ -1,6 +1,6 @@ |
/* 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. |
@@ -26,8 +26,9 @@ |
#include "gdbcmd.h" |
#include "value.h" |
#include "target.h" |
+#include "target-dcache.h" |
#include "language.h" |
-#include "gdb_string.h" |
+#include <string.h> |
#include "inferior.h" |
#include "breakpoint.h" |
#include "tracepoint.h" |
@@ -53,6 +54,9 @@ |
#include "exceptions.h" |
#include "cli/cli-utils.h" |
#include "probe.h" |
+#include "ctf.h" |
+#include "completer.h" |
+#include "filestuff.h" |
/* readline include files */ |
#include "readline/readline.h" |
@@ -61,17 +65,12 @@ |
/* readline defines this. */ |
#undef savestring |
-#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
-#endif |
#ifndef O_LARGEFILE |
#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 |
@@ -82,22 +81,11 @@ extern int bin2hex (const gdb_byte *bin, char *hex, int count); |
large. (400 - 31)/2 == 184 */ |
#define MAX_AGENT_EXPR_LEN 184 |
-#define TFILE_PID (1) |
- |
/* A hook used to notify the UI of tracepoint operations. */ |
void (*deprecated_trace_find_hook) (char *arg, int from_tty); |
void (*deprecated_trace_start_stop_hook) (int start, int from_tty); |
-extern void (*deprecated_readline_begin_hook) (char *, ...); |
-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: |
@@ -133,14 +121,6 @@ extern void output_command (char *, int); |
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. */ |
@@ -153,12 +133,6 @@ static int traceframe_number; |
/* Tracepoint for last traceframe collected. */ |
static int tracepoint_number; |
-/* Symbol for function for last traceframe collected. */ |
-static struct symbol *traceframe_fun; |
- |
-/* Symtab and line for last traceframe collected. */ |
-static struct symtab_and_line traceframe_sal; |
- |
/* The traceframe info of the current traceframe. NULL if we haven't |
yet attempted to fetch it, or if the target does not support |
fetching this object, or if we're not inspecting a traceframe |
@@ -178,6 +152,11 @@ static int disconnected_tracing; |
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; |
@@ -214,6 +193,8 @@ static void add_register (struct collection_list *collection, |
static void free_uploaded_tps (struct uploaded_tp **utpp); |
static void free_uploaded_tsvs (struct uploaded_tsv **utsvp); |
+static struct command_line * |
+ all_tracepoint_actions_and_cleanup (struct breakpoint *t); |
extern void _initialize_tracepoint (void); |
@@ -243,6 +224,7 @@ free_traceframe_info (struct traceframe_info *info) |
if (info != NULL) |
{ |
VEC_free (mem_range_s, info->memory); |
+ VEC_free (int, info->tvars); |
xfree (info); |
} |
@@ -281,6 +263,8 @@ static void |
set_traceframe_context (struct frame_info *trace_frame) |
{ |
CORE_ADDR trace_pc; |
+ struct symbol *traceframe_fun; |
+ struct symtab_and_line traceframe_sal; |
/* Save as globals for internal use. */ |
if (trace_frame != NULL |
@@ -312,12 +296,11 @@ set_traceframe_context (struct frame_info *trace_frame) |
/* 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. */ |
@@ -348,6 +331,22 @@ find_trace_state_variable (const char *name) |
return NULL; |
} |
+/* Look for a trace state variable of the given number. Return NULL if |
+ not found. */ |
+ |
+struct trace_state_variable * |
+find_trace_state_variable_by_number (int number) |
+{ |
+ struct trace_state_variable *tsv; |
+ int ix; |
+ |
+ for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix) |
+ if (tsv->number == number) |
+ return tsv; |
+ |
+ return NULL; |
+} |
+ |
static void |
delete_trace_state_variable (const char *name) |
{ |
@@ -357,61 +356,85 @@ delete_trace_state_variable (const char *name) |
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. */ |
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)); |
@@ -420,9 +443,11 @@ trace_variable_command (char *args, int from_tty) |
} |
/* 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)); |
@@ -442,6 +467,7 @@ delete_trace_variable_command (char *args, int from_tty) |
if (query (_("Delete all trace state variables? "))) |
VEC_free (tsv_s, tvariables); |
dont_repeat (); |
+ observer_notify_tsv_deleted (NULL); |
return; |
} |
@@ -561,13 +587,13 @@ save_trace_state_variables (struct ui_file *fp) |
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.")); |
@@ -587,11 +613,13 @@ teval_pseudocommand (char *args, int from_tty) |
/* 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; |
@@ -607,10 +635,10 @@ decode_agent_options (char *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++; |
} |
@@ -620,7 +648,7 @@ decode_agent_options (char *exp) |
else |
error (_("Undefined collection format \"%c\"."), *exp); |
- exp = skip_spaces (exp); |
+ exp = skip_spaces_const (exp); |
return exp; |
} |
@@ -677,22 +705,22 @@ report_agent_reqs_errors (struct agent_expr *aexpr) |
/* 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. */ |
@@ -707,15 +735,15 @@ validate_actionline (char **line, struct breakpoint *b) |
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. */ |
{ |
@@ -759,7 +787,7 @@ validate_actionline (char **line, struct breakpoint *b) |
/* 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) |
@@ -780,13 +808,13 @@ validate_actionline (char **line, struct breakpoint *b) |
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, loc->address, |
block_for_pc (loc->address), 1); |
@@ -812,51 +840,26 @@ validate_actionline (char **line, struct breakpoint *b) |
else if (cmd_cfunc_eq (c, while_stepping_pseudocommand)) |
{ |
- char *steparg; /* In case warning is necessary. */ |
- |
- while (isspace ((int) *p)) |
- p++; |
- steparg = p; |
+ char *endp; |
- 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 { |
memrange_absolute = -1 |
}; |
-struct memrange |
-{ |
- int type; /* memrange_absolute for absolute memory range, |
- else basereg number. */ |
- bfd_signed_vma start; |
- bfd_signed_vma end; |
-}; |
- |
-struct collection_list |
- { |
- unsigned char regs_mask[32]; /* room for up to 256 regs */ |
- long listsize; |
- long next_memrange; |
- struct memrange *list; |
- long aexpr_listsize; /* size of array pointed to by expr_list elt */ |
- long next_aexpr_elt; |
- struct agent_expr **aexpr_list; |
- |
- /* True is the user requested a collection of "$_sdata", "static |
- tracepoint data". */ |
- int strace_data; |
- } |
-tracepoint_list, stepping_list; |
- |
/* MEMRANGE functions: */ |
static int memrange_cmp (const void *, const void *); |
@@ -967,7 +970,8 @@ collect_symbol (struct collection_list *collect, |
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; |
@@ -1078,7 +1082,7 @@ collect_symbol (struct collection_list *collect, |
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 |
@@ -1131,6 +1135,7 @@ struct add_local_symbols_data |
long frame_regno; |
long frame_offset; |
int count; |
+ int trace_string; |
}; |
/* The callback for the locals and args iterators. */ |
@@ -1143,15 +1148,19 @@ do_collect_symbol (const char *print_name, |
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++; |
+ |
+ VEC_safe_push (char_ptr, p->collect->wholly_collected, |
+ xstrdup (print_name)); |
} |
/* Add all locals (or args) symbols to collection list. */ |
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; |
@@ -1162,6 +1171,7 @@ add_local_symbols (struct collection_list *collect, |
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') |
{ |
@@ -1216,11 +1226,43 @@ clear_collection_list (struct collection_list *list) |
list->next_aexpr_elt = 0; |
memset (list->regs_mask, 0, sizeof (list->regs_mask)); |
list->strace_data = 0; |
+ |
+ xfree (list->aexpr_list); |
+ xfree (list->list); |
+ |
+ VEC_free (char_ptr, list->wholly_collected); |
+ VEC_free (char_ptr, list->computed); |
+} |
+ |
+/* A cleanup wrapper for function clear_collection_list. */ |
+ |
+static void |
+do_clear_collection_list (void *list) |
+{ |
+ struct collection_list *l = list; |
+ |
+ clear_collection_list (l); |
+} |
+ |
+/* Initialize collection_list CLIST. */ |
+ |
+static void |
+init_collection_list (struct collection_list *clist) |
+{ |
+ memset (clist, 0, sizeof *clist); |
+ |
+ clist->listsize = 128; |
+ clist->list = xcalloc (clist->listsize, |
+ sizeof (struct memrange)); |
+ |
+ clist->aexpr_listsize = 128; |
+ clist->aexpr_list = xcalloc (clist->aexpr_listsize, |
+ sizeof (struct agent_expr *)); |
} |
/* Reduce a collection list to string form (for gdb protocol). */ |
static char ** |
-stringify_collection_list (struct collection_list *list, char *string) |
+stringify_collection_list (struct collection_list *list) |
{ |
char temp_buf[2048]; |
char tmp2[40]; |
@@ -1340,17 +1382,31 @@ stringify_collection_list (struct collection_list *list, char *string) |
return *str_list; |
} |
+/* Add the printed expression EXP to *LIST. */ |
+ |
+static void |
+append_exp (struct expression *exp, VEC(char_ptr) **list) |
+{ |
+ struct ui_file *tmp_stream = mem_fileopen (); |
+ char *text; |
+ |
+ print_expression (exp, tmp_stream); |
+ |
+ text = ui_file_xstrdup (tmp_stream, NULL); |
+ |
+ VEC_safe_push (char_ptr, *list, text); |
+ ui_file_delete (tmp_stream); |
+} |
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) |
{ |
- char *action_exp; |
+ const char *action_exp; |
struct expression *exp = NULL; |
int i; |
struct value *tempval; |
@@ -1361,8 +1417,7 @@ encode_actions_1 (struct command_line *action, |
{ |
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) |
@@ -1370,15 +1425,15 @@ encode_actions_1 (struct command_line *action, |
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)) |
{ |
@@ -1393,7 +1448,8 @@ encode_actions_1 (struct command_line *action, |
tloc->address, |
frame_reg, |
frame_offset, |
- 'A'); |
+ 'A', |
+ trace_string); |
action_exp = strchr (action_exp, ','); /* more? */ |
} |
else if (0 == strncasecmp ("$loc", action_exp, 4)) |
@@ -1403,7 +1459,8 @@ encode_actions_1 (struct command_line *action, |
tloc->address, |
frame_reg, |
frame_offset, |
- 'L'); |
+ 'L', |
+ trace_string); |
action_exp = strchr (action_exp, ','); /* more? */ |
} |
else if (0 == strncasecmp ("$_ret", action_exp, 5)) |
@@ -1411,7 +1468,8 @@ encode_actions_1 (struct command_line *action, |
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); |
@@ -1450,7 +1508,7 @@ encode_actions_1 (struct command_line *action, |
} |
else |
{ |
- unsigned long addr, len; |
+ unsigned long addr; |
struct cleanup *old_chain = NULL; |
struct cleanup *old_chain1 = NULL; |
@@ -1480,21 +1538,34 @@ encode_actions_1 (struct command_line *action, |
/* 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)); |
+ append_exp (exp, &collect->computed); |
break; |
case OP_VAR_VALUE: |
- collect_symbol (collect, |
- exp->elts[2].symbol, |
- tloc->gdbarch, |
- frame_reg, |
- frame_offset, |
- tloc->address); |
+ { |
+ struct symbol *sym = exp->elts[2].symbol; |
+ char_ptr name = (char_ptr) SYMBOL_NATURAL_NAME (sym); |
+ |
+ collect_symbol (collect, |
+ exp->elts[2].symbol, |
+ tloc->gdbarch, |
+ frame_reg, |
+ frame_offset, |
+ tloc->address, |
+ trace_string); |
+ VEC_safe_push (char_ptr, |
+ collect->wholly_collected, |
+ name); |
+ } |
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); |
@@ -1525,6 +1596,8 @@ encode_actions_1 (struct command_line *action, |
} |
} |
} |
+ |
+ append_exp (exp, &collect->computed); |
break; |
} /* switch */ |
do_cleanups (old_chain); |
@@ -1537,8 +1610,7 @@ encode_actions_1 (struct command_line *action, |
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; |
@@ -1571,7 +1643,7 @@ encode_actions_1 (struct command_line *action, |
here. */ |
gdb_assert (stepping_list); |
- encode_actions_1 (action->body_list[0], t, tloc, frame_reg, |
+ encode_actions_1 (action->body_list[0], tloc, frame_reg, |
frame_offset, stepping_list, NULL); |
} |
else |
@@ -1579,66 +1651,64 @@ encode_actions_1 (struct command_line *action, |
} /* for */ |
} |
-/* Render all actions into gdb protocol. */ |
+/* Encode actions of tracepoint TLOC->owner and fill TRACEPOINT_LIST |
+ and STEPPING_LIST. Return a cleanup pointer to clean up both |
+ TRACEPOINT_LIST and STEPPING_LIST. */ |
-void |
-encode_actions (struct breakpoint *t, struct bp_location *tloc, |
- char ***tdp_actions, char ***stepping_actions) |
+struct cleanup * |
+encode_actions_and_make_cleanup (struct bp_location *tloc, |
+ struct collection_list *tracepoint_list, |
+ struct collection_list *stepping_list) |
{ |
- 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); |
+ struct cleanup *back_to, *return_chain; |
- clear_collection_list (&tracepoint_list); |
- clear_collection_list (&stepping_list); |
+ return_chain = make_cleanup (null_cleanup, NULL); |
+ init_collection_list (tracepoint_list); |
+ init_collection_list (stepping_list); |
- *tdp_actions = NULL; |
- *stepping_actions = NULL; |
+ make_cleanup (do_clear_collection_list, tracepoint_list); |
+ make_cleanup (do_clear_collection_list, stepping_list); |
+ back_to = make_cleanup (null_cleanup, NULL); |
gdbarch_virtual_frame_pointer (tloc->gdbarch, |
tloc->address, &frame_reg, &frame_offset); |
- actions = breakpoint_commands (t); |
+ actions = all_tracepoint_actions_and_cleanup (tloc->owner); |
- /* 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; |
+ encode_actions_1 (actions, tloc, frame_reg, frame_offset, |
+ tracepoint_list, stepping_list); |
- default_collect_line = xstrprintf ("collect %s", default_collect); |
- make_cleanup (xfree, default_collect_line); |
+ memrange_sortmerge (tracepoint_list); |
+ memrange_sortmerge (stepping_list); |
- line = default_collect_line; |
- validate_actionline (&line, t); |
+ do_cleanups (back_to); |
+ return return_chain; |
+} |
- default_collect_action = xmalloc (sizeof (struct command_line)); |
- make_cleanup (xfree, default_collect_action); |
- default_collect_action->next = actions; |
- default_collect_action->line = line; |
- actions = default_collect_action; |
- } |
- encode_actions_1 (actions, t, tloc, frame_reg, frame_offset, |
- &tracepoint_list, &stepping_list); |
+/* Render all actions into gdb protocol. */ |
+ |
+void |
+encode_actions_rsp (struct bp_location *tloc, char ***tdp_actions, |
+ char ***stepping_actions) |
+{ |
+ struct collection_list tracepoint_list, stepping_list; |
+ struct cleanup *cleanup; |
- memrange_sortmerge (&tracepoint_list); |
- memrange_sortmerge (&stepping_list); |
+ *tdp_actions = NULL; |
+ *stepping_actions = NULL; |
- *tdp_actions = stringify_collection_list (&tracepoint_list, |
- tdp_buff); |
- *stepping_actions = stringify_collection_list (&stepping_list, |
- step_buff); |
+ cleanup = encode_actions_and_make_cleanup (tloc, &tracepoint_list, |
+ &stepping_list); |
- do_cleanups (back_to); |
+ *tdp_actions = stringify_collection_list (&tracepoint_list); |
+ *stepping_actions = stringify_collection_list (&stepping_list); |
+ |
+ do_cleanups (cleanup); |
} |
static void |
@@ -1697,6 +1767,16 @@ process_tracepoint_on_disconnect (void) |
" GDB is disconnected\n")); |
} |
+/* Reset local state of tracing. */ |
+ |
+void |
+trace_reset_local_state (void) |
+{ |
+ set_traceframe_num (-1); |
+ set_tracepoint_num (-1); |
+ set_traceframe_context (NULL); |
+ clear_traceframe_info (); |
+} |
void |
start_tracing (char *notes) |
@@ -1759,6 +1839,7 @@ start_tracing (char *notes) |
{ |
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) |
@@ -1780,6 +1861,7 @@ start_tracing (char *notes) |
target_download_tracepoint (loc); |
loc->inserted = 1; |
+ bp_location_downloaded = 1; |
} |
t->number_on_target = b->number; |
@@ -1787,6 +1869,9 @@ start_tracing (char *notes) |
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); |
@@ -1801,6 +1886,7 @@ start_tracing (char *notes) |
/* 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; |
@@ -1813,11 +1899,8 @@ start_tracing (char *notes) |
target_trace_start (); |
/* Reset our local state. */ |
- set_traceframe_num (-1); |
- set_tracepoint_num (-1); |
- set_traceframe_context (NULL); |
+ trace_reset_local_state (); |
current_trace_status()->running = 1; |
- clear_traceframe_info (); |
} |
/* The tstart command requests the target to start a new trace run. |
@@ -1912,7 +1995,7 @@ trace_status_command (char *args, int from_tty) |
if (status == -1) |
{ |
- if (ts->from_file) |
+ if (ts->filename != NULL) |
printf_filtered (_("Using a trace file.\n")); |
else |
{ |
@@ -2033,20 +2116,20 @@ trace_status_command (char *args, int from_tty) |
/* Reporting a run time is more readable than two long numbers. */ |
printf_filtered (_("Trace started at %ld.%06ld secs, stopped %ld.%06ld secs later.\n"), |
- (long int) ts->start_time / 1000000, |
- (long int) ts->start_time % 1000000, |
- (long int) run_time / 1000000, |
- (long int) run_time % 1000000); |
+ (long int) (ts->start_time / 1000000), |
+ (long int) (ts->start_time % 1000000), |
+ (long int) (run_time / 1000000), |
+ (long int) (run_time % 1000000)); |
} |
else |
printf_filtered (_("Trace started at %ld.%06ld secs.\n"), |
- (long int) ts->start_time / 1000000, |
- (long int) ts->start_time % 1000000); |
+ (long int) (ts->start_time / 1000000), |
+ (long int) (ts->start_time % 1000000)); |
} |
else if (ts->stop_time) |
printf_filtered (_("Trace stopped at %ld.%06ld secs.\n"), |
- (long int) ts->stop_time / 1000000, |
- (long int) ts->stop_time % 1000000); |
+ (long int) (ts->stop_time / 1000000), |
+ (long int) (ts->stop_time % 1000000)); |
/* Now report any per-tracepoint status available. */ |
tp_vec = all_tracepoints (); |
@@ -2072,17 +2155,20 @@ trace_status_mi (int on_stop) |
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) |
@@ -2161,22 +2247,25 @@ trace_status_mi (int on_stop) |
char buf[100]; |
xsnprintf (buf, sizeof buf, "%ld.%06ld", |
- (long int) ts->start_time / 1000000, |
- (long int) ts->start_time % 1000000); |
+ (long int) (ts->start_time / 1000000), |
+ (long int) (ts->start_time % 1000000)); |
ui_out_field_string (uiout, "start-time", buf); |
xsnprintf (buf, sizeof buf, "%ld.%06ld", |
- (long int) ts->stop_time / 1000000, |
- (long int) ts->stop_time % 1000000); |
+ (long int) (ts->stop_time / 1000000), |
+ (long int) (ts->stop_time % 1000000)); |
ui_out_field_string (uiout, "stop-time", buf); |
} |
} |
-/* This function handles the details of what to do about an ongoing |
- tracing run if the user has asked to detach or otherwise disconnect |
- from the target. */ |
+/* Check if a trace run is ongoing. If so, and FROM_TTY, query the |
+ user if she really wants to detach. */ |
+ |
void |
-disconnect_tracing (int from_tty) |
+query_if_trace_running (int from_tty) |
{ |
+ if (!from_tty) |
+ return; |
+ |
/* It can happen that the target that was tracing went away on its |
own, and we didn't notice. Get a status update, and if the |
current target doesn't even do tracing, then assume it's not |
@@ -2189,7 +2278,7 @@ disconnect_tracing (int from_tty) |
just going to disconnect and let the target deal with it, |
according to how it's been instructed previously via |
disconnected-tracing. */ |
- if (current_trace_status ()->running && from_tty) |
+ if (current_trace_status ()->running) |
{ |
process_tracepoint_on_disconnect (); |
@@ -2206,19 +2295,26 @@ disconnect_tracing (int from_tty) |
error (_("Not confirmed.")); |
} |
} |
+} |
+/* This function handles the details of what to do about an ongoing |
+ tracing run if the user has asked to detach or otherwise disconnect |
+ from the target. */ |
+ |
+void |
+disconnect_tracing (void) |
+{ |
/* 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_current_traceframe (-1); |
- set_traceframe_context (NULL); |
+ trace_reset_local_state (); |
} |
/* 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; |
@@ -2285,11 +2381,15 @@ tfind_1 (enum trace_find_type type, int num, |
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 |
@@ -2341,7 +2441,7 @@ tfind_1 (enum trace_find_type type, int num, |
else |
print_what = SRC_AND_LOC; |
- print_stack_frame (get_selected_frame (NULL), 1, print_what); |
+ print_stack_frame (get_selected_frame (NULL), 1, print_what, 1); |
do_displays (); |
} |
} |
@@ -2366,7 +2466,8 @@ trace_find_command (char *args, int from_tty) |
{ /* 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) |
@@ -2404,13 +2505,6 @@ trace_find_end_command (char *args, int from_tty) |
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) |
@@ -2424,7 +2518,8 @@ trace_find_pc_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) |
@@ -2442,7 +2537,8 @@ trace_find_tracepoint_command (char *args, int from_tty) |
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) |
@@ -2481,7 +2577,8 @@ trace_find_line_command (char *args, int from_tty) |
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) |
@@ -2507,7 +2604,8 @@ trace_find_line_command (char *args, int from_tty) |
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); |
@@ -2528,7 +2626,7 @@ trace_find_line_command (char *args, int from_tty) |
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) |
@@ -2545,7 +2643,8 @@ trace_find_range_command (char *args, int from_tty) |
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) |
@@ -2557,8 +2656,7 @@ trace_find_range_command (char *args, int from_tty) |
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); |
} |
@@ -2578,7 +2676,8 @@ trace_find_outside_command (char *args, int from_tty) |
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) |
@@ -2590,8 +2689,7 @@ trace_find_outside_command (char *args, int from_tty) |
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); |
} |
@@ -2648,101 +2746,107 @@ scope_info (char *args, int from_tty) |
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 %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, 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", |
@@ -2758,15 +2862,6 @@ scope_info (char *args, int from_tty) |
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 |
@@ -2778,7 +2873,7 @@ trace_dump_actions (struct command_line *action, |
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) |
{ |
@@ -2786,8 +2881,7 @@ trace_dump_actions (struct command_line *action, |
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". */ |
@@ -2817,16 +2911,20 @@ trace_dump_actions (struct command_line *action, |
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, ','); |
@@ -2840,43 +2938,49 @@ trace_dump_actions (struct command_line *action, |
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); |
} |
} |
} |
} |
-/* The tdump command. */ |
+/* Return bp_location of the tracepoint associated with the current |
+ traceframe. Set *STEPPING_FRAME_P to 1 if the current traceframe |
+ is a stepping traceframe. */ |
-static void |
-trace_dump_command (char *args, int from_tty) |
+struct bp_location * |
+get_traceframe_location (int *stepping_frame_p) |
{ |
- struct regcache *regcache; |
struct tracepoint *t; |
- int stepping_frame = 0; |
- struct bp_location *loc; |
- char *line, *default_collect_line = NULL; |
- struct command_line *actions, *default_collect_action = NULL; |
- struct cleanup *old_chain = NULL; |
+ struct bp_location *tloc; |
+ struct regcache *regcache; |
if (tracepoint_number == -1) |
- { |
- warning (_("No current trace frame.")); |
- return; |
- } |
+ error (_("No current trace frame.")); |
t = get_tracepoint (tracepoint_number); |
@@ -2884,52 +2988,96 @@ trace_dump_command (char *args, int from_tty) |
error (_("No known tracepoint matches 'current' tracepoint #%d."), |
tracepoint_number); |
- printf_filtered ("Data collected at tracepoint %d, trace frame %d:\n", |
- tracepoint_number, traceframe_number); |
- |
- /* The current frame is a trap frame if the frame PC is equal |
- to the tracepoint PC. If not, then the current frame was |
- collected during single-stepping. */ |
- |
+ /* The current frame is a trap frame if the frame PC is equal to the |
+ tracepoint PC. If not, then the current frame was collected |
+ during single-stepping. */ |
regcache = get_current_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->base.loc; loc; loc = loc->next) |
- if (loc->address == regcache_read_pc (regcache)) |
- stepping_frame = 0; |
+ for (tloc = t->base.loc; tloc; tloc = tloc->next) |
+ if (tloc->address == regcache_read_pc (regcache)) |
+ { |
+ *stepping_frame_p = 0; |
+ return tloc; |
+ } |
+ |
+ /* If this is a stepping frame, we don't know which location |
+ triggered. The first is as good (or bad) a guess as any... */ |
+ *stepping_frame_p = 1; |
+ return t->base.loc; |
+} |
+ |
+/* Return all the actions, including default collect, of a tracepoint |
+ T. It constructs cleanups into the chain, and leaves the caller to |
+ handle them (call do_cleanups). */ |
+ |
+static struct command_line * |
+all_tracepoint_actions_and_cleanup (struct breakpoint *t) |
+{ |
+ struct command_line *actions; |
- actions = breakpoint_commands (&t->base); |
+ actions = breakpoint_commands (t); |
- /* If there is a default-collect list, make up a collect command, |
- prepend to the tracepoint's commands, and pass the whole mess to |
- the trace dump scanner. We need to validate because |
- default-collect might have been junked since the trace run. */ |
+ /* 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) |
{ |
+ struct command_line *default_collect_action; |
+ char *default_collect_line; |
+ |
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); |
+ make_cleanup (xfree, default_collect_line); |
+ |
+ 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; |
} |
- trace_dump_actions (actions, 0, stepping_frame, from_tty); |
- |
- if (*default_collect) |
- do_cleanups (old_chain); |
+ return actions; |
} |
-/* 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 |
+/* The tdump command. */ |
+ |
+static void |
+trace_dump_command (char *args, int from_tty) |
+{ |
+ int stepping_frame = 0; |
+ struct bp_location *loc; |
+ struct cleanup *old_chain; |
+ struct command_line *actions; |
+ |
+ /* This throws an error is not inspecting a trace frame. */ |
+ loc = get_traceframe_location (&stepping_frame); |
+ |
+ printf_filtered ("Data collected at tracepoint %d, trace frame %d:\n", |
+ tracepoint_number, traceframe_number); |
+ |
+ old_chain = make_cleanup (null_cleanup, NULL); |
+ |
+ /* This command only makes sense for the current frame, not the |
+ selected frame. */ |
+ make_cleanup_restore_current_thread (); |
+ select_frame (get_current_frame ()); |
+ |
+ actions = all_tracepoint_actions_and_cleanup (loc->owner); |
+ |
+ trace_dump_actions (actions, 0, stepping_frame, from_tty); |
+ |
+ do_cleanups (old_chain); |
+} |
+ |
+/* 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 |
@@ -2943,40 +3091,347 @@ encode_source_string (int tpnum, ULONGEST 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); |
+ bin2hex ((gdb_byte *) src, buf + strlen (buf), 0); |
return -1; |
} |
-extern int trace_regblock_size; |
+/* Free trace file 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. */ |
+static void |
+trace_file_writer_xfree (void *arg) |
+{ |
+ struct trace_file_writer *writer = arg; |
-void |
-trace_save (const char *filename, int target_does_save) |
+ writer->ops->dtor (writer); |
+ xfree (writer); |
+} |
+ |
+/* TFILE trace writer. */ |
+ |
+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 = gdb_fopen_cloexec (writer->pathname, "wb"); |
+ if (writer->fp == NULL) |
+ error (_("Unable to open file '%s' for saving trace data (%s)"), |
+ writer->pathname, 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->start_time) |
+ { |
+ fprintf (writer->fp, ";starttime:%s", |
+ phex_nz (ts->start_time, sizeof (ts->start_time))); |
+ } |
+ if (ts->stop_time) |
+ { |
+ fprintf (writer->fp, ";stoptime:%s", |
+ phex_nz (ts->stop_time, sizeof (ts->stop_time))); |
+ } |
+ 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; |
+ char 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]; |
+#define MAX_TRACE_UPLOAD 2000 |
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; |
@@ -2986,51 +3441,17 @@ trace_save (const char *filename, int target_does_save) |
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 |
@@ -3045,22 +3466,7 @@ trace_save (const char *filename, int target_does_save) |
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); |
@@ -3070,76 +3476,205 @@ trace_save (const char *filename, int target_does_save) |
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 |
@@ -3149,6 +3684,8 @@ trace_save_command (char *args, int from_tty) |
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")); |
@@ -3160,6 +3697,8 @@ trace_save_command (char *args, int from_tty) |
{ |
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 |
@@ -3169,14 +3708,51 @@ trace_save_command (char *args, int from_tty) |
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); |
+} |
+ |
/* Tell the target what to do with an ongoing tracing run if GDB |
disconnects for some reason. */ |
@@ -3195,6 +3771,13 @@ set_circular_trace_buffer (char *args, int from_tty, |
} |
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) |
{ |
@@ -3261,6 +3844,12 @@ get_traceframe_number (void) |
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. */ |
@@ -3280,7 +3869,7 @@ set_current_traceframe (int num) |
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. */ |
@@ -3379,7 +3968,7 @@ free_uploaded_tps (struct uploaded_tp **utpp) |
/* Given a number and address, return an uploaded tracepoint with that |
number, creating if necessary. */ |
-static struct uploaded_tsv * |
+struct uploaded_tsv * |
get_uploaded_tsv (int num, struct uploaded_tsv **utsvp) |
{ |
struct uploaded_tsv *utsv; |
@@ -3464,6 +4053,10 @@ void |
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) |
@@ -3474,6 +4067,8 @@ merge_uploaded_tracepoints (struct uploaded_tp **uploaded_tps) |
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; |
@@ -3481,6 +4076,22 @@ merge_uploaded_tracepoints (struct uploaded_tp **uploaded_tps) |
"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 |
{ |
@@ -3503,6 +4114,12 @@ merge_uploaded_tracepoints (struct uploaded_tp **uploaded_tps) |
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); |
} |
@@ -3553,6 +4170,8 @@ create_tsv_from_upload (struct uploaded_tsv *utsv) |
tsv->initial_value = utsv->initial_value; |
tsv->builtin = utsv->builtin; |
+ observer_notify_tsv_created (tsv); |
+ |
do_cleanups (old_chain); |
return tsv; |
@@ -3613,18 +4232,17 @@ merge_uploaded_trace_state_variables (struct uploaded_tsv **uploaded_tsvs) |
/* 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, |
@@ -3659,7 +4277,7 @@ tfile_open (char *filename, int from_tty) |
int scratch_chan; |
char header[TRACE_HEADER_SIZE]; |
char linebuf[1000]; /* Should be max remote packet size or so. */ |
- char byte; |
+ gdb_byte byte; |
int bytes, i; |
struct trace_status *ts; |
struct uploaded_tp *uploaded_tps = NULL; |
@@ -3681,7 +4299,7 @@ tfile_open (char *filename, int from_tty) |
flags = O_BINARY | O_LARGEFILE; |
flags |= O_RDONLY; |
- scratch_chan = open (filename, flags, 0); |
+ scratch_chan = gdb_open_cloexec (filename, flags, 0); |
if (scratch_chan < 0) |
perror_with_name (filename); |
@@ -3706,8 +4324,8 @@ tfile_open (char *filename, int from_tty) |
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; |
@@ -3716,8 +4334,6 @@ tfile_open (char *filename, int from_tty) |
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 |
@@ -3753,15 +4369,11 @@ tfile_open (char *filename, int from_tty) |
} |
if (ex.reason < 0) |
{ |
- /* Pop the partially set up target. */ |
- pop_target (); |
+ /* Remove the partially set up target. */ |
+ unpush_target (&tfile_ops); |
throw_exception (ex); |
} |
- inferior_appeared (current_inferior (), TFILE_PID); |
- inferior_ptid = pid_to_ptid (TFILE_PID); |
- add_thread_silent (inferior_ptid); |
- |
if (ts->traceframe_count <= 0) |
warning (_("No traceframes present in this file.")); |
@@ -3772,16 +4384,14 @@ tfile_open (char *filename, int from_tty) |
merge_uploaded_trace_state_variables (&uploaded_tsvs); |
merge_uploaded_tracepoints (&uploaded_tps); |
- |
- post_create_inferior (&tfile_ops, from_tty); |
} |
/* Interpret the given line from the definitions part of the trace |
file. */ |
static void |
-tfile_interp_line (char *line, |
- struct uploaded_tp **utpp, struct uploaded_tsv **utsvp) |
+tfile_interp_line (char *line, struct uploaded_tp **utpp, |
+ struct uploaded_tsv **utsvp) |
{ |
char *p = line; |
@@ -3873,7 +4483,7 @@ Status line: '%s'\n"), p, line); |
else if (p2 != p1) |
{ |
ts->stop_desc = xmalloc (strlen (line)); |
- end = hex2bin (p1, ts->stop_desc, (p2 - p1) / 2); |
+ end = hex2bin (p1, (gdb_byte *) ts->stop_desc, (p2 - p1) / 2); |
ts->stop_desc[end] = '\0'; |
} |
else |
@@ -3893,7 +4503,7 @@ Status line: '%s'\n"), p, line); |
if (p2 != p1) |
{ |
ts->stop_desc = xmalloc ((p2 - p1) / 2 + 1); |
- end = hex2bin (p1, ts->stop_desc, (p2 - p1) / 2); |
+ end = hex2bin (p1, (gdb_byte *) ts->stop_desc, (p2 - p1) / 2); |
ts->stop_desc[end] = '\0'; |
} |
else |
@@ -3947,7 +4557,7 @@ Status line: '%s'\n"), p, line); |
{ |
++p1; |
ts->user_name = xmalloc (strlen (p) / 2); |
- end = hex2bin (p1, ts->user_name, (p3 - p1) / 2); |
+ end = hex2bin (p1, (gdb_byte *) ts->user_name, (p3 - p1) / 2); |
ts->user_name[end] = '\0'; |
p = p3; |
} |
@@ -3955,7 +4565,7 @@ Status line: '%s'\n"), p, line); |
{ |
++p1; |
ts->notes = xmalloc (strlen (p) / 2); |
- end = hex2bin (p1, ts->notes, (p3 - p1) / 2); |
+ end = hex2bin (p1, (gdb_byte *) ts->notes, (p3 - p1) / 2); |
ts->notes[end] = '\0'; |
p = p3; |
} |
@@ -4139,28 +4749,25 @@ parse_tsv_definition (char *line, struct uploaded_tsv **utsvp) |
/* Close the trace file and generally clean up. */ |
static void |
-tfile_close (int quitting) |
+tfile_close (void) |
{ |
int pid; |
if (trace_fd < 0) |
return; |
- pid = ptid_get_pid (inferior_ptid); |
- inferior_ptid = null_ptid; /* Avoid confusion from thread stuff. */ |
- exit_inferior_silent (pid); |
- |
close (trace_fd); |
trace_fd = -1; |
xfree (trace_filename); |
trace_filename = NULL; |
+ |
+ trace_reset_local_state (); |
} |
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. */ |
@@ -4186,10 +4793,10 @@ tfile_get_tracepoint_status (struct breakpoint *tp, struct uploaded_tp *utp) |
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; |
@@ -4201,7 +4808,7 @@ tfile_get_traceframe_address (off_t tframe_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. */ |
@@ -4214,28 +4821,6 @@ tfile_get_traceframe_address (off_t tframe_offset) |
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 |
@@ -4243,21 +4828,16 @@ set_tfile_traceframe (void) |
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; |
@@ -4272,51 +4852,62 @@ tfile_trace_find (enum trace_find_type type, int num, |
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. */ |
@@ -4368,7 +4959,7 @@ traceframe_walk_blocks (walk_blocks_callback_func callback, |
unsigned short mlen; |
char block_type; |
- tfile_read (&block_type, 1); |
+ tfile_read ((gdb_byte *) &block_type, 1); |
++pos; |
@@ -4387,7 +4978,7 @@ traceframe_walk_blocks (walk_blocks_callback_func callback, |
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; |
@@ -4424,15 +5015,13 @@ tfile_fetch_registers (struct target_ops *ops, |
{ |
struct gdbarch *gdbarch = get_regcache_arch (regcache); |
int offset, regn, regsize, pc_regno; |
- char *regs; |
+ gdb_byte *regs; |
/* An uninitialized reg size says we're not going to be |
successful at getting register blocks. */ |
if (!trace_regblock_size) |
return; |
- set_tfile_traceframe (); |
- |
regs = alloca (trace_regblock_size); |
if (traceframe_find_block_type ('R', 0) >= 0) |
@@ -4516,8 +5105,6 @@ tfile_xfer_partial (struct target_ops *ops, enum target_object object, |
if (readbuf == NULL) |
error (_("tfile_xfer_partial: trace file is read-only")); |
- set_tfile_traceframe (); |
- |
if (traceframe_number != -1) |
{ |
int pos = 0; |
@@ -4528,7 +5115,7 @@ tfile_xfer_partial (struct target_ops *ops, enum target_object object, |
{ |
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, |
@@ -4602,9 +5189,12 @@ static int |
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) |
{ |
@@ -4613,20 +5203,19 @@ tfile_get_trace_state_variable_value (int tsvnum, LONGEST *val) |
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 |
@@ -4653,12 +5242,6 @@ tfile_has_registers (struct target_ops *ops) |
return traceframe_number != -1; |
} |
-static int |
-tfile_thread_alive (struct target_ops *ops, ptid_t ptid) |
-{ |
- return 1; |
-} |
- |
/* Callback for traceframe_walk_blocks. Builds a traceframe_info |
object for the tfile target's current traceframe. */ |
@@ -4676,7 +5259,14 @@ build_traceframe_info (char blocktype, void *data) |
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); |
@@ -4685,6 +5275,12 @@ build_traceframe_info (char blocktype, void *data) |
break; |
} |
case 'V': |
+ { |
+ int vnum; |
+ |
+ tfile_read ((gdb_byte *) &vnum, 4); |
+ VEC_safe_push (int, info->tvars, vnum); |
+ } |
case 'R': |
case 'S': |
{ |
@@ -4732,7 +5328,6 @@ init_tfile_ops (void) |
tfile_ops.to_has_stack = tfile_has_stack; |
tfile_ops.to_has_registers = tfile_has_registers; |
tfile_ops.to_traceframe_info = tfile_traceframe_info; |
- tfile_ops.to_thread_alive = tfile_thread_alive; |
tfile_ops.to_magic = OPS_MAGIC; |
} |
@@ -4767,7 +5362,7 @@ parse_static_tracepoint_marker_definition (char *line, char **pp, |
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, ':'); |
@@ -4861,15 +5456,15 @@ print_one_static_tracepoint_marker (int count, |
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"); |
@@ -4944,7 +5539,7 @@ info_static_tracepoint_markers_command (char *arg, int from_tty) |
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"); |
@@ -5043,6 +5638,21 @@ traceframe_info_start_memory (struct gdb_xml_parser *parser, |
r->length = *length_p; |
} |
+/* Handle the start of a <tvar> element. */ |
+ |
+static void |
+traceframe_info_start_tvar (struct gdb_xml_parser *parser, |
+ const struct gdb_xml_element *element, |
+ void *user_data, |
+ VEC(gdb_xml_value_s) *attributes) |
+{ |
+ struct traceframe_info *info = user_data; |
+ const char *id_attrib = xml_find_attribute (attributes, "id")->value; |
+ int id = gdb_xml_parse_ulongest (parser, id_attrib); |
+ |
+ VEC_safe_push (int, info->tvars, id); |
+} |
+ |
/* Discard the constructed trace frame info (if an error occurs). */ |
static void |
@@ -5061,10 +5671,18 @@ static const struct gdb_xml_attribute memory_attributes[] = { |
{ NULL, GDB_XML_AF_NONE, NULL, NULL } |
}; |
+static const struct gdb_xml_attribute tvar_attributes[] = { |
+ { "id", GDB_XML_AF_NONE, NULL, NULL }, |
+ { NULL, GDB_XML_AF_NONE, NULL, NULL } |
+}; |
+ |
static const struct gdb_xml_element traceframe_info_children[] = { |
{ "memory", memory_attributes, NULL, |
GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL, |
traceframe_info_start_memory, NULL }, |
+ { "tvar", tvar_attributes, NULL, |
+ GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL, |
+ traceframe_info_start_tvar, NULL }, |
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } |
}; |
@@ -5105,7 +5723,7 @@ parse_traceframe_info (const char *tframe_info) |
This is where we avoid re-fetching the object from the target if we |
already have it cached. */ |
-static struct traceframe_info * |
+struct traceframe_info * |
get_traceframe_info (void) |
{ |
if (traceframe_info == NULL) |
@@ -5182,33 +5800,6 @@ _initialize_tracepoint (void) |
traceframe_number = -1; |
tracepoint_number = -1; |
- if (tracepoint_list.list == NULL) |
- { |
- tracepoint_list.listsize = 128; |
- tracepoint_list.list = xmalloc |
- (tracepoint_list.listsize * sizeof (struct memrange)); |
- } |
- if (tracepoint_list.aexpr_list == NULL) |
- { |
- tracepoint_list.aexpr_listsize = 128; |
- tracepoint_list.aexpr_list = xmalloc |
- (tracepoint_list.aexpr_listsize * sizeof (struct agent_expr *)); |
- } |
- |
- if (stepping_list.list == NULL) |
- { |
- stepping_list.listsize = 128; |
- stepping_list.list = xmalloc |
- (stepping_list.listsize * sizeof (struct memrange)); |
- } |
- |
- if (stepping_list.aexpr_list == NULL) |
- { |
- stepping_list.aexpr_listsize = 128; |
- stepping_list.aexpr_list = xmalloc |
- (stepping_list.aexpr_listsize * sizeof (struct agent_expr *)); |
- } |
- |
add_info ("scope", scope_info, |
_("List the variables local to a scope")); |
@@ -5221,6 +5812,7 @@ _initialize_tracepoint (void) |
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.")); |
@@ -5279,13 +5871,10 @@ Default is the current PC, or the PC of the current trace frame."), |
&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."), |
@@ -5379,6 +5968,16 @@ up and stopping the trace run."), |
&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. Specifying \"unlimited\" or -1\n\ |
+disables 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"), _("\ |
@@ -5402,5 +6001,5 @@ Show the notes string to use for future tstop commands"), NULL, |
init_tfile_ops (); |
- add_target (&tfile_ops); |
+ add_target_with_completer (&tfile_ops, filename_completer); |
} |