| 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);
|
| }
|
|
|