gas: mips: fix segfault with invalid default cpu strings
[deliverable/binutils-gdb.git] / gdb / tracepoint.c
index bf328fd98ff1587ca8dd81d03a84e50788d8761f..b4269c620068a87e82f5b551b4d9ad9cac2a7863 100644 (file)
@@ -1,7 +1,6 @@
 /* Tracing functionality for remote targets in custom GDB protocol
 
-   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
-   2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-2012 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "gdbthread.h"
 #include "stack.h"
 #include "gdbcore.h"
-
+#include "remote.h"
+#include "source.h"
 #include "ax.h"
 #include "ax-gdb.h"
+#include "memrange.h"
+#include "exceptions.h"
+#include "cli/cli-utils.h"
+#include "probe.h"
 
 /* readline include files */
 #include "readline/readline.h"
@@ -68,8 +72,6 @@
 extern int hex2bin (const char *hex, gdb_byte *bin, int count);
 extern int bin2hex (const gdb_byte *bin, char *hex, int count);
 
-extern void stop_tracing ();
-
 /* 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
@@ -80,6 +82,8 @@ extern void stop_tracing ();
    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);
@@ -129,6 +133,14 @@ 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.  */
@@ -141,13 +153,19 @@ static int traceframe_number;
 /* Tracepoint for last traceframe collected.  */
 static int tracepoint_number;
 
-/* Symbol for function for last traceframe collected */
+/* Symbol for function for last traceframe collected */
 static struct symbol *traceframe_fun;
 
-/* Symtab and line for last traceframe collected */
+/* Symtab and line for last traceframe collected */
 static struct symtab_and_line traceframe_sal;
 
-/* Tracing command lists */
+/* 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
+   presently.  */
+static struct traceframe_info *traceframe_info;
+
+/* Tracing command lists.  */
 static struct cmd_list_element *tfindlist;
 
 /* List of expressions to collect by default at each tracepoint hit.  */
@@ -160,6 +178,18 @@ static int disconnected_tracing;
 
 static int circular_trace_buffer;
 
+/* Textual notes applying to the current and/or future trace runs.  */
+
+char *trace_user = NULL;
+
+/* Textual notes applying to the current and/or future trace runs.  */
+
+char *trace_notes = NULL;
+
+/* Textual notes applying to the stopping of a trace.  */
+
+char *trace_stop_notes = NULL;
+
 /* ======= Important command functions: ======= */
 static void trace_actions_command (char *, int);
 static void trace_start_command (char *, int);
@@ -181,8 +211,6 @@ static char *mem2hex (gdb_byte *, char *, int);
 static void add_register (struct collection_list *collection,
                          unsigned int regno);
 
-extern void send_disconnected_tracing_value (int value);
-
 static void free_uploaded_tps (struct uploaded_tp **utpp);
 static void free_uploaded_tsvs (struct uploaded_tsv **utsvp);
 
@@ -202,11 +230,34 @@ char *stop_reason_names[] = {
 };
 
 struct trace_status *
-current_trace_status ()
+current_trace_status (void)
 {
   return &trace_status;
 }
 
+/* Destroy INFO.  */
+
+static void
+free_traceframe_info (struct traceframe_info *info)
+{
+  if (info != NULL)
+    {
+      VEC_free (mem_range_s, info->memory);
+
+      xfree (info);
+    }
+}
+
+/* Free and clear the traceframe info cache of the current
+   traceframe.  */
+
+static void
+clear_traceframe_info (void)
+{
+  free_traceframe_info (traceframe_info);
+  traceframe_info = NULL;
+}
+
 /* Set traceframe number to NUM.  */
 static void
 set_traceframe_num (int num)
@@ -224,34 +275,32 @@ set_tracepoint_num (int num)
 }
 
 /* Set externally visible debug variables for querying/printing
-   the traceframe context (line, function, file) */
+   the traceframe context (line, function, file) */
 
 static void
 set_traceframe_context (struct frame_info *trace_frame)
 {
   CORE_ADDR trace_pc;
 
-  if (trace_frame == NULL)             /* Cease debugging any trace buffers.  */
+  /* Save as globals for internal use.  */
+  if (trace_frame != NULL
+      && get_frame_pc_if_available (trace_frame, &trace_pc))
+    {
+      traceframe_sal = find_pc_line (trace_pc, 0);
+      traceframe_fun = find_pc_function (trace_pc);
+
+      /* Save linenumber as "$trace_line", a debugger variable visible to
+        users.  */
+      set_internalvar_integer (lookup_internalvar ("trace_line"),
+                              traceframe_sal.line);
+    }
+  else
     {
-      traceframe_fun = 0;
-      traceframe_sal.pc = traceframe_sal.line = 0;
-      traceframe_sal.symtab = NULL;
-      clear_internalvar (lookup_internalvar ("trace_func"));
-      clear_internalvar (lookup_internalvar ("trace_file"));
+      init_sal (&traceframe_sal);
+      traceframe_fun = NULL;
       set_internalvar_integer (lookup_internalvar ("trace_line"), -1);
-      return;
     }
 
-  /* Save as globals for internal use.  */
-  trace_pc = get_frame_pc (trace_frame);
-  traceframe_sal = find_pc_line (trace_pc, 0);
-  traceframe_fun = find_pc_function (trace_pc);
-
-  /* Save linenumber as "$trace_line", a debugger variable visible to
-     users.  */
-  set_internalvar_integer (lookup_internalvar ("trace_line"),
-                          traceframe_sal.line);
-
   /* Save func name as "$trace_func", a debugger variable visible to
      users.  */
   if (traceframe_fun == NULL
@@ -299,7 +348,7 @@ find_trace_state_variable (const char *name)
   return NULL;
 }
 
-void
+static void
 delete_trace_state_variable (const char *name)
 {
   struct trace_state_variable *tsv;
@@ -319,7 +368,7 @@ delete_trace_state_variable (const char *name)
 /* The 'tvariable' command collects a name and optional expression to
    evaluate into an initial value.  */
 
-void
+static void
 trace_variable_command (char *args, int from_tty)
 {
   struct expression *expr;
@@ -363,8 +412,10 @@ trace_variable_command (char *args, int from_tty)
   if (tsv)
     {
       tsv->initial_value = initval;
-      printf_filtered (_("Trace state variable $%s now has initial value %s.\n"),
+      printf_filtered (_("Trace state variable $%s "
+                        "now has initial value %s.\n"),
                       tsv->name, plongest (tsv->initial_value));
+      do_cleanups (old_chain);
       return;
     }
 
@@ -372,19 +423,19 @@ trace_variable_command (char *args, int from_tty)
   tsv = create_trace_state_variable (internalvar_name (intvar));
   tsv->initial_value = initval;
 
-  printf_filtered (_("Trace state variable $%s created, with initial value %s.\n"),
+  printf_filtered (_("Trace state variable $%s "
+                    "created, with initial value %s.\n"),
                   tsv->name, plongest (tsv->initial_value));
 
   do_cleanups (old_chain);
 }
 
-void
+static void
 delete_trace_variable_command (char *args, int from_tty)
 {
-  int i, ix;
+  int ix;
   char **argv;
   struct cleanup *back_to;
-  struct trace_state_variable *tsv;
 
   if (args == NULL)
     {
@@ -397,12 +448,12 @@ delete_trace_variable_command (char *args, int from_tty)
   argv = gdb_buildargv (args);
   back_to = make_cleanup_freeargv (argv);
 
-  for (i = 0; argv[i] != NULL; i++)
+  for (ix = 0; argv[ix] != NULL; ix++)
     {
-      if (*argv[i] == '$')
-       delete_trace_state_variable (argv[i] + 1);
+      if (*argv[ix] == '$')
+       delete_trace_state_variable (argv[ix] + 1);
       else
-       warning (_("Name \"%s\" not prefixed with '$', ignoring"), argv[i]);
+       warning (_("Name \"%s\" not prefixed with '$', ignoring"), argv[ix]);
     }
 
   do_cleanups (back_to);
@@ -417,6 +468,7 @@ tvariables_info_1 (void)
   int ix;
   int count = 0;
   struct cleanup *back_to;
+  struct ui_out *uiout = current_uiout;
 
   if (VEC_length (tsv_s, tvariables) == 0 && !ui_out_is_mi_like_p (uiout))
     {
@@ -445,7 +497,7 @@ tvariables_info_1 (void)
 
       back_to2 = make_cleanup_ui_out_tuple_begin_end (uiout, "variable");
 
-      name = concat ("$", tsv->name, NULL);
+      name = concat ("$", tsv->name, (char *) NULL);
       make_cleanup (xfree, name);
       ui_out_field_string (uiout, "name", name);
       ui_out_field_string (uiout, "initial", plongest (tsv->initial_value));
@@ -533,24 +585,65 @@ teval_pseudocommand (char *args, int from_tty)
   error (_("This command can only be used in a tracepoint actions list."));
 }
 
+/* Parse any collection options, such as /s for strings.  */
+
+char *
+decode_agent_options (char *exp)
+{
+  struct value_print_options opts;
+
+  if (*exp != '/')
+    return exp;
+
+  /* Call this to borrow the print elements default for collection
+     size.  */
+  get_user_print_options (&opts);
+
+  exp++;
+  if (*exp == 's')
+    {
+      if (target_supports_string_tracing ())
+       {
+         /* 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;
+         exp++;
+         if (*exp >= '0' && *exp <= '9')
+           trace_string_kludge = atoi (exp);
+         while (*exp >= '0' && *exp <= '9')
+           exp++;
+       }
+      else
+       error (_("Target does not support \"/s\" option for string tracing."));
+    }
+  else
+    error (_("Undefined collection format \"%c\"."), *exp);
+
+  exp = skip_spaces (exp);
+
+  return exp;
+}
+
 /* Enter a list of actions for a tracepoint.  */
 static void
 trace_actions_command (char *args, int from_tty)
 {
-  struct breakpoint *t;
+  struct tracepoint *t;
   struct command_line *l;
 
-  t = get_tracepoint_by_number (&args, 0, 1);
+  t = get_tracepoint_by_number (&args, NULL, 1);
   if (t)
     {
       char *tmpbuf =
        xstrprintf ("Enter actions for tracepoint %d, one per line.",
-                   t->number);
+                   t->base.number);
       struct cleanup *cleanups = make_cleanup (xfree, tmpbuf);
 
-      l = read_command_lines (tmpbuf, from_tty, 1, check_tracepoint_command, t);
+      l = read_command_lines (tmpbuf, from_tty, 1,
+                             check_tracepoint_command, t);
       do_cleanups (cleanups);
-      breakpoint_set_commands (t, l);
+      breakpoint_set_commands (&t->base, l);
     }
   /* else just return */
 }
@@ -559,16 +652,16 @@ trace_actions_command (char *args, int from_tty)
    internal errors.  */
 
 static void
-report_agent_reqs_errors (struct agent_expr *aexpr, struct agent_reqs *areqs)
+report_agent_reqs_errors (struct agent_expr *aexpr)
 {
   /* All of the "flaws" are serious bytecode generation issues that
      should never occur.  */
-  if (areqs->flaw != agent_flaw_none)
+  if (aexpr->flaw != agent_flaw_none)
     internal_error (__FILE__, __LINE__, _("expression is malformed"));
 
   /* If analysis shows a stack underflow, GDB must have done something
      badly wrong in its bytecode generation.  */
-  if (areqs->min_height < 0)
+  if (aexpr->min_height < 0)
     internal_error (__FILE__, __LINE__,
                    _("expression has min height < 0"));
 
@@ -578,13 +671,13 @@ report_agent_reqs_errors (struct agent_expr *aexpr, struct agent_reqs *areqs)
      depth roughly corresponds to parenthesization, so a limit of 20
      amounts to 20 levels of expression nesting, which is actually
      a pretty big hairy expression.  */
-  if (areqs->max_height > 20)
+  if (aexpr->max_height > 20)
     error (_("Expression is too complicated."));
 }
 
 /* worker function */
 void
-validate_actionline (char **line, struct breakpoint *t)
+validate_actionline (char **line, struct breakpoint *b)
 {
   struct cmd_list_element *c;
   struct expression *exp = NULL;
@@ -592,9 +685,9 @@ validate_actionline (char **line, struct breakpoint *t)
   char *p, *tmp_p;
   struct bp_location *loc;
   struct agent_expr *aexpr;
-  struct agent_reqs areqs;
+  struct tracepoint *t = (struct tracepoint *) b;
 
-  /* if EOF is typed, *line is NULL */
+  /* If EOF is typed, *line is NULL.  */
   if (*line == NULL)
     return;
 
@@ -614,17 +707,23 @@ validate_actionline (char **line, struct breakpoint *t)
 
   if (cmd_cfunc_eq (c, collect_pseudocommand))
     {
+      trace_string_kludge = 0;
+      if (*p == '/')
+       p = decode_agent_options (p);
+
       do
-       {                       /* repeat over a comma-separated list */
-         QUIT;                 /* allow user to bail out with ^C */
+       {                       /* Repeat over a comma-separated list.  */
+         QUIT;                 /* Allow user to bail out with ^C.  */
          while (isspace ((int) *p))
            p++;
 
-         if (*p == '$')        /* look for special pseudo-symbols */
+         if (*p == '$')        /* Look for special pseudo-symbols.  */
            {
-             if ((0 == strncasecmp ("reg", p + 1, 3)) ||
-                 (0 == strncasecmp ("arg", p + 1, 3)) ||
-                 (0 == strncasecmp ("loc", p + 1, 3)))
+             if (0 == strncasecmp ("reg", p + 1, 3)
+                 || 0 == strncasecmp ("arg", p + 1, 3)
+                 || 0 == strncasecmp ("loc", p + 1, 3)
+                 || 0 == strncasecmp ("_ret", p + 1, 4)
+                 || 0 == strncasecmp ("_sdata", p + 1, 6))
                {
                  p = strchr (p, ',');
                  continue;
@@ -632,7 +731,7 @@ validate_actionline (char **line, struct breakpoint *t)
              /* else fall thru, treat p as an expression and parse it!  */
            }
          tmp_p = p;
-         for (loc = t->loc; loc; loc = loc->next)
+         for (loc = t->base.loc; loc; loc = loc->next)
            {
              p = tmp_p;
              exp = parse_exp_1 (&p, block_for_pc (loc->address), 1);
@@ -642,13 +741,16 @@ validate_actionline (char **line, struct breakpoint *t)
                {
                  if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_CONST)
                    {
-                     error (_("constant `%s' (value %ld) will not be collected."),
+                     error (_("constant `%s' (value %s) "
+                              "will not be collected."),
                             SYMBOL_PRINT_NAME (exp->elts[2].symbol),
-                            SYMBOL_VALUE (exp->elts[2].symbol));
+                            plongest (SYMBOL_VALUE (exp->elts[2].symbol)));
                    }
-                 else if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_OPTIMIZED_OUT)
+                 else if (SYMBOL_CLASS (exp->elts[2].symbol)
+                          == LOC_OPTIMIZED_OUT)
                    {
-                     error (_("`%s' is optimized away and cannot be collected."),
+                     error (_("`%s' is optimized away "
+                              "and cannot be collected."),
                             SYMBOL_PRINT_NAME (exp->elts[2].symbol));
                    }
                }
@@ -662,10 +764,9 @@ validate_actionline (char **line, struct breakpoint *t)
              if (aexpr->len > MAX_AGENT_EXPR_LEN)
                error (_("Expression is too complicated."));
 
-             ax_reqs (aexpr, &areqs);
-             (void) make_cleanup (xfree, areqs.reg_mask);
+             ax_reqs (aexpr);
 
-             report_agent_reqs_errors (aexpr, &areqs);
+             report_agent_reqs_errors (aexpr);
 
              do_cleanups (old_chain);
            }
@@ -676,13 +777,13 @@ validate_actionline (char **line, struct breakpoint *t)
   else if (cmd_cfunc_eq (c, teval_pseudocommand))
     {
       do
-       {                       /* repeat over a comma-separated list */
-         QUIT;                 /* allow user to bail out with ^C */
+       {                       /* Repeat over a comma-separated list.  */
+         QUIT;                 /* Allow user to bail out with ^C.  */
          while (isspace ((int) *p))
            p++;
 
          tmp_p = p;
-         for (loc = t->loc; loc; loc = loc->next)
+         for (loc = t->base.loc; loc; loc = loc->next)
            {
              p = tmp_p;
              /* Only expressions are allowed for this action.  */
@@ -698,10 +799,8 @@ validate_actionline (char **line, struct breakpoint *t)
              if (aexpr->len > MAX_AGENT_EXPR_LEN)
                error (_("Expression is too complicated."));
 
-             ax_reqs (aexpr, &areqs);
-             (void) make_cleanup (xfree, areqs.reg_mask);
-
-             report_agent_reqs_errors (aexpr, &areqs);
+             ax_reqs (aexpr);
+             report_agent_reqs_errors (aexpr);
 
              do_cleanups (old_chain);
            }
@@ -711,7 +810,7 @@ validate_actionline (char **line, struct breakpoint *t)
 
   else if (cmd_cfunc_eq (c, while_stepping_pseudocommand))
     {
-      char *steparg;           /* in case warning is necessary */
+      char *steparg;           /* In case warning is necessary.  */
 
       while (isspace ((int) *p))
        p++;
@@ -735,7 +834,7 @@ enum {
 struct memrange
 {
   int type;            /* memrange_absolute for absolute memory range,
-                           else basereg number */
+                           else basereg number */
   bfd_signed_vma start;
   bfd_signed_vma end;
 };
@@ -750,6 +849,9 @@ struct collection_list
     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;
 
@@ -757,7 +859,7 @@ tracepoint_list, stepping_list;
 
 static int memrange_cmp (const void *, const void *);
 
-/* compare memranges for qsort */
+/* Compare memranges for qsort.  */
 static int
 memrange_cmp (const void *va, const void *vb)
 {
@@ -796,11 +898,11 @@ memrange_sortmerge (struct collection_list *memranges)
     {
       for (a = 0, b = 1; b < memranges->next_memrange; b++)
        {
-         if (memranges->list[a].type == memranges->list[b].type &&
-             memranges->list[b].start - memranges->list[a].end <=
-             MAX_REGISTER_SIZE)
+         /* If memrange b overlaps or is adjacent to memrange a,
+            merge them.  */
+         if (memranges->list[a].type == memranges->list[b].type
+             && memranges->list[b].start <= memranges->list[a].end)
            {
-             /* memrange b starts before memrange a ends; merge them.  */
              if (memranges->list[b].end > memranges->list[a].end)
                memranges->list[a].end = memranges->list[b].end;
              continue;         /* next b, same a */
@@ -826,7 +928,7 @@ add_register (struct collection_list *collection, unsigned int regno)
   collection->regs_mask[regno / 8] |= 1 << (regno % 8);
 }
 
-/* Add a memrange to a collection list */
+/* Add a memrange to a collection list */
 static void
 add_memrange (struct collection_list *memranges, 
              int type, bfd_signed_vma base,
@@ -853,7 +955,7 @@ add_memrange (struct collection_list *memranges,
                                  memranges->listsize);
     }
 
-  if (type != memrange_absolute)               /* Better collect the base register!  */
+  if (type != memrange_absolute)    /* Better collect the base register!  */
     add_register (memranges, type);
 }
 
@@ -879,8 +981,8 @@ collect_symbol (struct collection_list *collect,
                       SYMBOL_CLASS (sym));
       break;
     case LOC_CONST:
-      printf_filtered ("constant %s (value %ld) will not be collected.\n",
-                      SYMBOL_PRINT_NAME (sym), SYMBOL_VALUE (sym));
+      printf_filtered ("constant %s (value %s) will not be collected.\n",
+                      SYMBOL_PRINT_NAME (sym), plongest (SYMBOL_VALUE (sym)));
       break;
     case LOC_STATIC:
       offset = SYMBOL_VALUE_ADDRESS (sym);
@@ -973,7 +1075,6 @@ collect_symbol (struct collection_list *collect,
     {
       struct agent_expr *aexpr;
       struct cleanup *old_chain1 = NULL;
-      struct agent_reqs areqs;
 
       aexpr = gen_trace_for_var (scope, gdbarch, sym);
 
@@ -989,27 +1090,27 @@ collect_symbol (struct collection_list *collect,
 
       old_chain1 = make_cleanup_free_agent_expr (aexpr);
 
-      ax_reqs (aexpr, &areqs);
+      ax_reqs (aexpr);
 
-      report_agent_reqs_errors (aexpr, &areqs);
+      report_agent_reqs_errors (aexpr);
 
       discard_cleanups (old_chain1);
       add_aexpr (collect, aexpr);
 
-      /* take care of the registers */
-      if (areqs.reg_mask_len > 0)
+      /* Take care of the registers.  */
+      if (aexpr->reg_mask_len > 0)
        {
          int ndx1, ndx2;
 
-         for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++)
+         for (ndx1 = 0; ndx1 < aexpr->reg_mask_len; ndx1++)
            {
-             QUIT;     /* allow user to bail out with ^C */
-             if (areqs.reg_mask[ndx1] != 0)
+             QUIT;     /* Allow user to bail out with ^C.  */
+             if (aexpr->reg_mask[ndx1] != 0)
                {
-                 /* assume chars have 8 bits */
+                 /* Assume chars have 8 bits.  */
                  for (ndx2 = 0; ndx2 < 8; ndx2++)
-                   if (areqs.reg_mask[ndx1] & (1 << ndx2))
-                     /* it's used -- record it */
+                   if (aexpr->reg_mask[ndx1] & (1 << ndx2))
+                     /* It's used -- record it.  */
                      add_register (collect, ndx1 * 8 + ndx2);
                }
            }
@@ -1030,7 +1131,7 @@ struct add_local_symbols_data
   int count;
 };
 
-/* The callback for the locals and args iterators  */
+/* The callback for the locals and args iterators.  */
 
 static void
 do_collect_symbol (const char *print_name,
@@ -1044,7 +1145,7 @@ do_collect_symbol (const char *print_name,
   p->count++;
 }
 
-/* Add all locals (or args) symbols to collection list */
+/* Add all locals (or args) symbols to collection list */
 static void
 add_local_symbols (struct collection_list *collect,
                   struct gdbarch *gdbarch, CORE_ADDR pc,
@@ -1080,7 +1181,7 @@ add_local_symbols (struct collection_list *collect,
       block = block_for_pc (pc);
       if (block == NULL)
        {
-         warning (_("Can't collect args; no symbol table info available.\n"));
+         warning (_("Can't collect args; no symbol table info available."));
          return;
        }
 
@@ -1090,6 +1191,14 @@ add_local_symbols (struct collection_list *collect,
     }
 }
 
+static void
+add_static_trace_data (struct collection_list *collection)
+{
+  if (info_verbose)
+    printf_filtered ("collect static trace data\n");
+  collection->strace_data = 1;
+}
+
 /* worker function */
 static void
 clear_collection_list (struct collection_list *list)
@@ -1104,9 +1213,10 @@ 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;
 }
 
-/* reduce a collection list to string form (for gdb protocol) */
+/* Reduce a collection list to string form (for gdb protocol).  */
 static char **
 stringify_collection_list (struct collection_list *list, char *string)
 {
@@ -1118,13 +1228,23 @@ stringify_collection_list (struct collection_list *list, char *string)
   char *end;
   long i;
 
-  count = 1 + list->next_memrange + list->next_aexpr_elt + 1;
+  count = 1 + 1 + list->next_memrange + list->next_aexpr_elt + 1;
   str_list = (char *(*)[]) xmalloc (count * sizeof (char *));
 
+  if (list->strace_data)
+    {
+      if (info_verbose)
+       printf_filtered ("\nCollecting static trace data\n");
+      end = temp_buf;
+      *end++ = 'L';
+      (*str_list)[ndx] = savestring (temp_buf, end - temp_buf);
+      ndx++;
+    }
+
   for (i = sizeof (list->regs_mask) - 1; i > 0; i--)
-    if (list->regs_mask[i] != 0)       /* skip leading zeroes in regs_mask */
+    if (list->regs_mask[i] != 0)    /* Skip leading zeroes in regs_mask.  */
       break;
-  if (list->regs_mask[i] != 0) /* prepare to send regs_mask to the stub */
+  if (list->regs_mask[i] != 0) /* Prepare to send regs_mask to the stub.  */
     {
       if (info_verbose)
        printf_filtered ("\nCollecting registers (mask): 0x");
@@ -1132,7 +1252,7 @@ stringify_collection_list (struct collection_list *list, char *string)
       *end++ = 'R';
       for (; i >= 0; i--)
        {
-         QUIT;                 /* allow user to bail out with ^C */
+         QUIT;                 /* Allow user to bail out with ^C.  */
          if (info_verbose)
            printf_filtered ("%02X", list->regs_mask[i]);
          sprintf (end, "%02X", list->regs_mask[i]);
@@ -1147,7 +1267,7 @@ stringify_collection_list (struct collection_list *list, char *string)
     printf_filtered ("Collecting memranges: \n");
   for (i = 0, count = 0, end = temp_buf; i < list->next_memrange; i++)
     {
-      QUIT;                    /* allow user to bail out with ^C */
+      QUIT;                    /* Allow user to bail out with ^C.  */
       sprintf_vma (tmp2, list->list[i].start);
       if (info_verbose)
        {
@@ -1183,7 +1303,7 @@ stringify_collection_list (struct collection_list *list, char *string)
 
   for (i = 0; i < list->next_aexpr_elt; i++)
     {
-      QUIT;                    /* allow user to bail out with ^C */
+      QUIT;                    /* Allow user to bail out with ^C.  */
       if ((count + 10 + 2 * list->aexpr_list[i]->len) > MAX_AGENT_EXPR_LEN)
        {
          (*str_list)[ndx] = savestring (temp_buf, count);
@@ -1230,7 +1350,6 @@ encode_actions_1 (struct command_line *action,
 {
   char *action_exp;
   struct expression *exp = NULL;
-  struct command_line *actions;
   int i;
   struct value *tempval;
   struct cmd_list_element *cmd;
@@ -1238,7 +1357,7 @@ encode_actions_1 (struct command_line *action,
 
   for (; action; action = action->next)
     {
-      QUIT;                    /* allow user to bail out with ^C */
+      QUIT;                    /* Allow user to bail out with ^C.  */
       action_exp = action->line;
       while (isspace ((int) *action_exp))
        action_exp++;
@@ -1249,22 +1368,26 @@ encode_actions_1 (struct command_line *action,
 
       if (cmd_cfunc_eq (cmd, collect_pseudocommand))
        {
+         trace_string_kludge = 0;
+         if (*action_exp == '/')
+           action_exp = decode_agent_options (action_exp);
+
          do
-           {                   /* repeat over a comma-separated list */
-             QUIT;             /* allow user to bail out with ^C */
+           {                   /* Repeat over a comma-separated list.  */
+             QUIT;             /* Allow user to bail out with ^C.  */
              while (isspace ((int) *action_exp))
                action_exp++;
 
              if (0 == strncasecmp ("$reg", action_exp, 4))
                {
-                 for (i = 0; i < gdbarch_num_regs (t->gdbarch); i++)
+                 for (i = 0; i < gdbarch_num_regs (tloc->gdbarch); i++)
                    add_register (collect, i);
                  action_exp = strchr (action_exp, ',');        /* more? */
                }
              else if (0 == strncasecmp ("$arg", action_exp, 4))
                {
                  add_local_symbols (collect,
-                                    t->gdbarch,
+                                    tloc->gdbarch,
                                     tloc->address,
                                     frame_reg,
                                     frame_offset,
@@ -1274,19 +1397,60 @@ encode_actions_1 (struct command_line *action,
              else if (0 == strncasecmp ("$loc", action_exp, 4))
                {
                  add_local_symbols (collect,
-                                    t->gdbarch,
+                                    tloc->gdbarch,
                                     tloc->address,
                                     frame_reg,
                                     frame_offset,
                                     'L');
                  action_exp = strchr (action_exp, ',');        /* more? */
                }
+             else if (0 == strncasecmp ("$_ret", action_exp, 5))
+               {
+                 struct cleanup *old_chain1 = NULL;
+
+                 aexpr = gen_trace_for_return_address (tloc->address,
+                                                       tloc->gdbarch);
+
+                 old_chain1 = make_cleanup_free_agent_expr (aexpr);
+
+                 ax_reqs (aexpr);
+                 report_agent_reqs_errors (aexpr);
+
+                 discard_cleanups (old_chain1);
+                 add_aexpr (collect, aexpr);
+
+                 /* take care of the registers */
+                 if (aexpr->reg_mask_len > 0)
+                   {
+                     int ndx1, ndx2;
+
+                     for (ndx1 = 0; ndx1 < aexpr->reg_mask_len; ndx1++)
+                       {
+                         QUIT; /* allow user to bail out with ^C */
+                         if (aexpr->reg_mask[ndx1] != 0)
+                           {
+                             /* assume chars have 8 bits */
+                             for (ndx2 = 0; ndx2 < 8; ndx2++)
+                               if (aexpr->reg_mask[ndx1] & (1 << ndx2))
+                                 /* it's used -- record it */
+                                 add_register (collect, 
+                                               ndx1 * 8 + ndx2);
+                           }
+                       }
+                   }
+
+                 action_exp = strchr (action_exp, ',');        /* more? */
+               }
+             else if (0 == strncasecmp ("$_sdata", action_exp, 7))
+               {
+                 add_static_trace_data (collect);
+                 action_exp = strchr (action_exp, ',');        /* more? */
+               }
              else
                {
                  unsigned long addr, len;
                  struct cleanup *old_chain = NULL;
                  struct cleanup *old_chain1 = NULL;
-                 struct agent_reqs areqs;
 
                  exp = parse_exp_1 (&action_exp, 
                                     block_for_pc (tloc->address), 1);
@@ -1298,7 +1462,7 @@ encode_actions_1 (struct command_line *action,
                      {
                        const char *name = &exp->elts[2].string;
 
-                       i = user_reg_map_name_to_regnum (t->gdbarch,
+                       i = user_reg_map_name_to_regnum (tloc->gdbarch,
                                                         name, strlen (name));
                        if (i == -1)
                          internal_error (__FILE__, __LINE__,
@@ -1311,7 +1475,7 @@ encode_actions_1 (struct command_line *action,
                      }
 
                    case UNOP_MEMVAL:
-                     /* safe because we know it's a simple expression */
+                     /* 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));
@@ -1321,39 +1485,39 @@ encode_actions_1 (struct command_line *action,
                    case OP_VAR_VALUE:
                      collect_symbol (collect,
                                      exp->elts[2].symbol,
-                                     t->gdbarch,
+                                     tloc->gdbarch,
                                      frame_reg,
                                      frame_offset,
                                      tloc->address);
                      break;
 
-                   default:    /* full-fledged expression */
+                   default:    /* Full-fledged expression.  */
                      aexpr = gen_trace_for_expr (tloc->address, exp);
 
                      old_chain1 = make_cleanup_free_agent_expr (aexpr);
 
-                     ax_reqs (aexpr, &areqs);
+                     ax_reqs (aexpr);
 
-                     report_agent_reqs_errors (aexpr, &areqs);
+                     report_agent_reqs_errors (aexpr);
 
                      discard_cleanups (old_chain1);
                      add_aexpr (collect, aexpr);
 
-                     /* take care of the registers */
-                     if (areqs.reg_mask_len > 0)
+                     /* Take care of the registers.  */
+                     if (aexpr->reg_mask_len > 0)
                        {
                          int ndx1;
                          int ndx2;
 
-                         for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++)
+                         for (ndx1 = 0; ndx1 < aexpr->reg_mask_len; ndx1++)
                            {
-                             QUIT;     /* allow user to bail out with ^C */
-                             if (areqs.reg_mask[ndx1] != 0)
+                             QUIT;     /* Allow user to bail out with ^C.  */
+                             if (aexpr->reg_mask[ndx1] != 0)
                                {
-                                 /* assume chars have 8 bits */
+                                 /* Assume chars have 8 bits.  */
                                  for (ndx2 = 0; ndx2 < 8; ndx2++)
-                                   if (areqs.reg_mask[ndx1] & (1 << ndx2))
-                                     /* it's used -- record it */
+                                   if (aexpr->reg_mask[ndx1] & (1 << ndx2))
+                                     /* It's used -- record it.  */
                                      add_register (collect, 
                                                    ndx1 * 8 + ndx2);
                                }
@@ -1369,16 +1533,14 @@ encode_actions_1 (struct command_line *action,
       else if (cmd_cfunc_eq (cmd, teval_pseudocommand))
        {
          do
-           {                   /* repeat over a comma-separated list */
-             QUIT;             /* allow user to bail out with ^C */
+           {                   /* Repeat over a comma-separated list.  */
+             QUIT;             /* Allow user to bail out with ^C.  */
              while (isspace ((int) *action_exp))
                action_exp++;
 
                {
-                 unsigned long addr, len;
                  struct cleanup *old_chain = NULL;
                  struct cleanup *old_chain1 = NULL;
-                 struct agent_reqs areqs;
 
                  exp = parse_exp_1 (&action_exp, 
                                     block_for_pc (tloc->address), 1);
@@ -1387,9 +1549,8 @@ encode_actions_1 (struct command_line *action,
                  aexpr = gen_eval_for_expr (tloc->address, exp);
                  old_chain1 = make_cleanup_free_agent_expr (aexpr);
 
-                 ax_reqs (aexpr, &areqs);
-
-                 report_agent_reqs_errors (aexpr, &areqs);
+                 ax_reqs (aexpr);
+                 report_agent_reqs_errors (aexpr);
 
                  discard_cleanups (old_chain1);
                  /* Even though we're not officially collecting, add
@@ -1408,8 +1569,8 @@ encode_actions_1 (struct command_line *action,
             here.  */
          gdb_assert (stepping_list);
 
-         encode_actions_1 (action->body_list[0], t, tloc, frame_reg, frame_offset,
-                           stepping_list, NULL);
+         encode_actions_1 (action->body_list[0], t, tloc, frame_reg,
+                           frame_offset, stepping_list, NULL);
        }
       else
        error (_("Invalid tracepoint command '%s'"), action->line);
@@ -1417,7 +1578,8 @@ encode_actions_1 (struct command_line *action,
 }
 
 /* Render all actions into gdb protocol.  */
-/*static*/ void
+
+void
 encode_actions (struct breakpoint *t, struct bp_location *tloc,
                char ***tdp_actions, char ***stepping_actions)
 {
@@ -1437,8 +1599,8 @@ encode_actions (struct breakpoint *t, struct bp_location *tloc,
   *tdp_actions = NULL;
   *stepping_actions = NULL;
 
-  gdbarch_virtual_frame_pointer (t->gdbarch,
-                                t->loc->address, &frame_reg, &frame_offset);
+  gdbarch_virtual_frame_pointer (tloc->gdbarch,
+                                tloc->address, &frame_reg, &frame_offset);
 
   actions = breakpoint_commands (t);
 
@@ -1484,56 +1646,145 @@ add_aexpr (struct collection_list *collect, struct agent_expr *aexpr)
     {
       collect->aexpr_list =
        xrealloc (collect->aexpr_list,
-               2 * collect->aexpr_listsize * sizeof (struct agent_expr *));
+                 2 * collect->aexpr_listsize * sizeof (struct agent_expr *));
       collect->aexpr_listsize *= 2;
     }
   collect->aexpr_list[collect->next_aexpr_elt] = aexpr;
   collect->next_aexpr_elt++;
 }
 
+static void
+process_tracepoint_on_disconnect (void)
+{
+  VEC(breakpoint_p) *tp_vec = NULL;
+  int ix;
+  struct breakpoint *b;
+  int has_pending_p = 0;
+
+  /* Check whether we still have pending tracepoint.  If we have, warn the
+     user that pending tracepoint will no longer work.  */
+  tp_vec = all_tracepoints ();
+  for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, b); ix++)
+    {
+      if (b->loc == NULL)
+       {
+         has_pending_p = 1;
+         break;
+       }
+      else
+       {
+         struct bp_location *loc1;
+
+         for (loc1 = b->loc; loc1; loc1 = loc1->next)
+           {
+             if (loc1->shlib_disabled)
+               {
+                 has_pending_p = 1;
+                 break;
+               }
+           }
+
+         if (has_pending_p)
+           break;
+       }
+    }
+  VEC_free (breakpoint_p, tp_vec);
+
+  if (has_pending_p)
+    warning (_("Pending tracepoints will not be resolved while"
+              " GDB is disconnected\n"));
+}
+
 
 void
-start_tracing (void)
+start_tracing (char *notes)
 {
-  char buf[2048];
   VEC(breakpoint_p) *tp_vec = NULL;
   int ix;
-  struct breakpoint *t;
+  struct breakpoint *b;
   struct trace_state_variable *tsv;
-  int any_enabled = 0;
-  
+  int any_enabled = 0, num_to_download = 0;
+  int ret;
+
   tp_vec = all_tracepoints ();
 
-  /* No point in tracing without any tracepoints... */
+  /* No point in tracing without any tracepoints...  */
   if (VEC_length (breakpoint_p, tp_vec) == 0)
     {
       VEC_free (breakpoint_p, tp_vec);
       error (_("No tracepoints defined, not starting trace"));
     }
 
-  for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
+  for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, b); ix++)
+    {
+      struct tracepoint *t = (struct tracepoint *) b;
+      struct bp_location *loc;
+
+      if (b->enable_state == bp_enabled)
+       any_enabled = 1;
+
+      if ((b->type == bp_fast_tracepoint
+          ? may_insert_fast_tracepoints
+          : may_insert_tracepoints))
+       ++num_to_download;
+      else
+       warning (_("May not insert %stracepoints, skipping tracepoint %d"),
+                (b->type == bp_fast_tracepoint ? "fast " : ""), b->number);
+    }
+
+  if (!any_enabled)
     {
-      if (t->enable_state == bp_enabled)
+      if (target_supports_enable_disable_tracepoint ())
+       warning (_("No tracepoints enabled"));
+      else
        {
-         any_enabled = 1;
-         break;
+         /* No point in tracing with only disabled tracepoints that
+            cannot be re-enabled.  */
+         VEC_free (breakpoint_p, tp_vec);
+         error (_("No tracepoints enabled, not starting trace"));
        }
     }
 
-  /* No point in tracing with only disabled tracepoints.  */
-  if (!any_enabled)
+  if (num_to_download <= 0)
     {
       VEC_free (breakpoint_p, tp_vec);
-      error (_("No tracepoints enabled, not starting trace"));
+      error (_("No tracepoints that may be downloaded, not starting trace"));
     }
 
   target_trace_init ();
 
-  for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
+  for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, b); ix++)
     {
+      struct tracepoint *t = (struct tracepoint *) b;
+      struct bp_location *loc;
+
+      /* Clear `inserted' flag.  */
+      for (loc = b->loc; loc; loc = loc->next)
+       loc->inserted = 0;
+
+      if ((b->type == bp_fast_tracepoint
+          ? !may_insert_fast_tracepoints
+          : !may_insert_tracepoints))
+       continue;
+
       t->number_on_target = 0;
-      target_download_tracepoint (t);
-      t->number_on_target = t->number;
+
+      for (loc = b->loc; loc; loc = loc->next)
+       {
+         /* Since tracepoint locations are never duplicated, `inserted'
+            flag should be zero.  */
+         gdb_assert (!loc->inserted);
+
+         target_download_tracepoint (loc);
+
+         loc->inserted = 1;
+       }
+
+      t->number_on_target = b->number;
+
+      for (loc = b->loc; loc; loc = loc->next)
+       if (loc->probe != NULL)
+         loc->probe->pops->set_semaphore (loc->probe, loc->gdbarch);
     }
   VEC_free (breakpoint_p, tp_vec);
 
@@ -1549,6 +1800,13 @@ start_tracing (void)
   target_set_disconnected_tracing (disconnected_tracing);
   target_set_circular_trace_buffer (circular_trace_buffer);
 
+  if (!notes)
+    notes = trace_notes;
+  ret = target_set_trace_notes (trace_user, notes, NULL);
+
+  if (!ret && (trace_user || notes))
+    warning ("Target does not support trace user/notes, info ignored");
+
   /* Now insert traps and begin collecting data.  */
   target_trace_start ();
 
@@ -1557,14 +1815,14 @@ start_tracing (void)
   set_tracepoint_num (-1);
   set_traceframe_context (NULL);
   current_trace_status()->running = 1;
+  clear_traceframe_info ();
 }
 
-/* tstart command:
-
-   Tell target to clear any previous trace experiment.
-   Walk the list of tracepoints, and send them (and their actions)
-   to the target.  If no errors,
-   Tell target to start a new trace experiment.  */
+/* The tstart command requests the target to start a new trace run.
+   The command passes any arguments it has to the target verbatim, as
+   an optional "trace note".  This is useful as for instance a warning
+   to other users if the trace runs disconnected, and you don't want
+   anybody else messing with the target.  */
 
 static void
 trace_start_command (char *args, int from_tty)
@@ -1578,24 +1836,64 @@ trace_start_command (char *args, int from_tty)
        error (_("New trace run not started."));
     }
 
-  start_tracing ();
+  start_tracing (args);
 }
 
-/* tstop command */
+/* The tstop command stops the tracing run.  The command passes any
+   supplied arguments to the target verbatim as a "stop note"; if the
+   target supports trace notes, then it will be reported back as part
+   of the trace run's status.  */
+
 static void
 trace_stop_command (char *args, int from_tty)
 {
   if (!current_trace_status ()->running)
     error (_("Trace is not running."));
 
-  stop_tracing ();
+  stop_tracing (args);
 }
 
 void
-stop_tracing (void)
+stop_tracing (char *note)
 {
+  int ret;
+  VEC(breakpoint_p) *tp_vec = NULL;
+  int ix;
+  struct breakpoint *t;
+
   target_trace_stop ();
-  /* should change in response to reply? */
+
+  tp_vec = all_tracepoints ();
+  for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
+    {
+      struct bp_location *loc;
+
+      if ((t->type == bp_fast_tracepoint
+          ? !may_insert_fast_tracepoints
+          : !may_insert_tracepoints))
+       continue;
+
+      for (loc = t->loc; loc; loc = loc->next)
+       {
+         /* GDB can be totally absent in some disconnected trace scenarios,
+            but we don't really care if this semaphore goes out of sync.
+            That's why we are decrementing it here, but not taking care
+            in other places.  */
+         if (loc->probe != NULL)
+           loc->probe->pops->clear_semaphore (loc->probe, loc->gdbarch);
+       }
+    }
+
+  VEC_free (breakpoint_p, tp_vec);
+
+  if (!note)
+    note = trace_stop_notes;
+  ret = target_set_trace_notes (NULL, NULL, note);
+
+  if (!ret && note)
+    warning ("Target does not support trace notes, note ignored");
+
+  /* Should change in response to reply?  */
   current_trace_status ()->running = 0;
 }
 
@@ -1604,7 +1902,9 @@ static void
 trace_status_command (char *args, int from_tty)
 {
   struct trace_status *ts = current_trace_status ();
-  int status;
+  int status, ix;
+  VEC(breakpoint_p) *tp_vec = NULL;
+  struct breakpoint *t;
   
   status = target_get_trace_status (ts);
 
@@ -1635,7 +1935,11 @@ trace_status_command (char *args, int from_tty)
          printf_filtered (_("No trace has been run on the target.\n"));
          break;
        case tstop_command:
-         printf_filtered (_("Trace stopped by a tstop command.\n"));
+         if (ts->stop_desc)
+           printf_filtered (_("Trace stopped by a tstop command (%s).\n"),
+                            ts->stop_desc);
+         else
+           printf_filtered (_("Trace stopped by a tstop command.\n"));
          break;
        case trace_buffer_full:
          printf_filtered (_("Trace stopped because the buffer was full.\n"));
@@ -1649,11 +1953,12 @@ trace_status_command (char *args, int from_tty)
          break;
        case tracepoint_error:
          if (ts->stopping_tracepoint)
-           printf_filtered (_("Trace stopped by an error (%s, tracepoint %d).\n"),
-                            ts->error_desc, ts->stopping_tracepoint);
+           printf_filtered (_("Trace stopped by an "
+                              "error (%s, tracepoint %d).\n"),
+                            ts->stop_desc, ts->stopping_tracepoint);
          else
            printf_filtered (_("Trace stopped by an error (%s).\n"),
-                            ts->error_desc);
+                            ts->stop_desc);
          break;
        case trace_stop_reason_unknown:
          printf_filtered (_("Trace stopped for an unknown reason.\n"));
@@ -1668,7 +1973,8 @@ trace_status_command (char *args, int from_tty)
   if (ts->traceframes_created >= 0
       && ts->traceframe_count != ts->traceframes_created)
     {
-      printf_filtered (_("Buffer contains %d trace frames (of %d created total).\n"),
+      printf_filtered (_("Buffer contains %d trace "
+                        "frames (of %d created total).\n"),
                       ts->traceframe_count, ts->traceframes_created);
     }
   else if (ts->traceframe_count >= 0)
@@ -1703,12 +2009,50 @@ trace_status_command (char *args, int from_tty)
   if (ts->circular_buffer)
     printf_filtered (_("Trace buffer is circular.\n"));
 
+  if (ts->user_name && strlen (ts->user_name) > 0)
+    printf_filtered (_("Trace user is %s.\n"), ts->user_name);
+
+  if (ts->notes && strlen (ts->notes) > 0)
+    printf_filtered (_("Trace notes: %s.\n"), ts->notes);
+
   /* Now report on what we're doing with tfind.  */
   if (traceframe_number >= 0)
     printf_filtered (_("Looking at trace frame %d, tracepoint %d.\n"),
                     traceframe_number, tracepoint_number);
   else
     printf_filtered (_("Not looking at any trace frame.\n"));
+
+  /* Report start/stop times if supplied.  */
+  if (ts->start_time)
+    {
+      if (ts->stop_time)
+       {
+         LONGEST run_time = ts->stop_time - ts->start_time;
+
+         /* 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);
+       }
+      else
+       printf_filtered (_("Trace started at %ld.%06ld secs.\n"),
+                        (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);
+
+  /* Now report any per-tracepoint status available.  */
+  tp_vec = all_tracepoints ();
+
+  for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
+    target_get_tracepoint_status (t, NULL);
+
+  VEC_free (breakpoint_p, tp_vec);
 }
 
 /* Report the trace status to uiout, in a way suitable for MI, and not
@@ -1720,9 +2064,9 @@ trace_status_command (char *args, int from_tty)
 void
 trace_status_mi (int on_stop)
 {
+  struct ui_out *uiout = current_uiout;
   struct trace_status *ts = current_trace_status ();
   int status;
-  char *string_status;
 
   status = target_get_trace_status (ts);
 
@@ -1791,7 +2135,7 @@ trace_status_mi (int on_stop)
                                  stopping_tracepoint);
              if (ts->stop_reason == tracepoint_error)
                ui_out_field_string (uiout, "error-description",
-                                    ts->error_desc);
+                                    ts->stop_desc);
            }
        }
     }
@@ -1807,6 +2151,22 @@ trace_status_mi (int on_stop)
 
   ui_out_field_int (uiout, "disconnected",  ts->disconnected_tracing);
   ui_out_field_int (uiout, "circular",  ts->circular_buffer);
+
+  ui_out_field_string (uiout, "user-name", ts->user_name);
+  ui_out_field_string (uiout, "notes", ts->notes);
+
+  {
+    char buf[100];
+
+    xsnprintf (buf, sizeof buf, "%ld.%06ld",
+              (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);
+    ui_out_field_string (uiout, "stop-time", buf);
+  }
 }
 
 /* This function handles the details of what to do about an ongoing
@@ -1829,14 +2189,18 @@ disconnect_tracing (int from_tty)
      disconnected-tracing.  */
   if (current_trace_status ()->running && from_tty)
     {
+      process_tracepoint_on_disconnect ();
+
       if (current_trace_status ()->disconnected_tracing)
        {
-         if (!query (_("Trace is running and will continue after detach; detach anyway? ")))
+         if (!query (_("Trace is running and will "
+                       "continue after detach; detach anyway? ")))
            error (_("Not confirmed."));
        }
       else
        {
-         if (!query (_("Trace is running but will stop on detach; detach anyway? ")))
+         if (!query (_("Trace is running but will "
+                       "stop on detach; detach anyway? ")))
            error (_("Not confirmed."));
        }
     }
@@ -1845,7 +2209,7 @@ disconnect_tracing (int from_tty)
      confusing upon reconnection.  Just use these calls instead of
      full tfind_1 behavior because we're in the middle of detaching,
      and there's no point to updating current stack frame etc.  */
-  set_traceframe_number (-1);
+  set_current_traceframe (-1);
   set_traceframe_context (NULL);
 }
 
@@ -1857,8 +2221,8 @@ tfind_1 (enum trace_find_type type, int num,
 {
   int target_frameno = -1, target_tracept = -1;
   struct frame_id old_frame_id = null_frame_id;
-  char *reply;
-  struct breakpoint *tp;
+  struct tracepoint *tp;
+  struct ui_out *uiout = current_uiout;
 
   /* Only try to get the current stack frame if we have a chance of
      succeeding.  In particular, if we're trying to get a first trace
@@ -1908,7 +2272,7 @@ tfind_1 (enum trace_find_type type, int num,
        {
          if (info_verbose)
            printf_filtered ("End of trace buffer.\n");
-#if 0 /* dubious now? */
+#if 0 /* dubious now?  */
          /* The following will not recurse, since it's
             special-cased.  */
          trace_find_command ("-1", from_tty);
@@ -1922,7 +2286,8 @@ tfind_1 (enum trace_find_type type, int num,
   registers_changed ();
   target_dcache_invalidate ();
   set_traceframe_num (target_frameno);
-  set_tracepoint_num (tp ? tp->number : target_tracept);
+  clear_traceframe_info ();
+  set_tracepoint_num (tp ? tp->base.number : target_tracept);
   if (target_frameno == -1)
     set_traceframe_context (NULL);
   else
@@ -1948,8 +2313,10 @@ tfind_1 (enum trace_find_type type, int num,
     {
       if (ui_out_is_mi_like_p (uiout))
        ui_out_field_string (uiout, "found", "0");
-      else
-       printf_unfiltered (_("No trace frame found"));
+      else if (type == tfind_number && num == -1)
+       printf_unfiltered (_("No longer looking at any trace frame\n"));
+      else /* This case may never occur, check.  */
+       printf_unfiltered (_("No trace frame found\n"));
     }
 
   /* If we're in nonstop mode and getting out of looking at trace
@@ -1994,16 +2361,16 @@ tfind_1 (enum trace_find_type type, int num,
 /* tfind command */
 static void
 trace_find_command (char *args, int from_tty)
-{ /* this should only be called with a numeric argument */
+{ /* This should only be called with a numeric argument.  */
   int frameno = -1;
 
   if (current_trace_status ()->running && !current_trace_status ()->from_file)
-    error ("May not look at trace frames while trace is running.");
+    error (_("May not look at trace frames while trace is running."));
   
   if (args == 0 || *args == 0)
     { /* TFIND with no args means find NEXT trace frame.  */
       if (traceframe_number == -1)
-       frameno = 0;    /* "next" is first one */
+       frameno = 0;    /* "next" is first one */
         else
        frameno = traceframe_number + 1;
     }
@@ -2054,10 +2421,9 @@ static void
 trace_find_pc_command (char *args, int from_tty)
 {
   CORE_ADDR pc;
-  char tmp[40];
 
   if (current_trace_status ()->running && !current_trace_status ()->from_file)
-    error ("May not look at trace frames while trace is running.");
+    error (_("May not look at trace frames while trace is running."));
 
   if (args == 0 || *args == 0)
     pc = regcache_read_pc (get_current_regcache ());
@@ -2072,17 +2438,17 @@ static void
 trace_find_tracepoint_command (char *args, int from_tty)
 {
   int tdp;
-  struct breakpoint *tp;
+  struct tracepoint *tp;
 
   if (current_trace_status ()->running && !current_trace_status ()->from_file)
-    error ("May not look at trace frames while trace is running.");
+    error (_("May not look at trace frames while trace is running."));
 
   if (args == 0 || *args == 0)
     {
       if (tracepoint_number == -1)
        error (_("No current tracepoint -- please supply an argument."));
       else
-       tdp = tracepoint_number;        /* default is current TDP */
+       tdp = tracepoint_number;        /* Default is current TDP.  */
     }
   else
     tdp = parse_and_eval_long (args);
@@ -2112,10 +2478,9 @@ trace_find_line_command (char *args, int from_tty)
   struct symtabs_and_lines sals;
   struct symtab_and_line sal;
   struct cleanup *old_chain;
-  char   startpc_str[40], endpc_str[40];
 
   if (current_trace_status ()->running && !current_trace_status ()->from_file)
-    error ("May not look at trace frames while trace is running.");
+    error (_("May not look at trace frames while trace is running."));
 
   if (args == 0 || *args == 0)
     {
@@ -2127,7 +2492,7 @@ trace_find_line_command (char *args, int from_tty)
     }
   else
     {
-      sals = decode_line_spec (args, 1);
+      sals = decode_line_spec (args, DECODE_LINE_FUNFIRSTLINE);
       sal = sals.sals[0];
     }
   
@@ -2176,11 +2541,10 @@ static void
 trace_find_range_command (char *args, int from_tty)
 {
   static CORE_ADDR start, stop;
-  char start_str[40], stop_str[40];
   char *tmp;
 
   if (current_trace_status ()->running && !current_trace_status ()->from_file)
-    error ("May not look at trace frames while trace is running.");
+    error (_("May not look at trace frames while trace is running."));
 
   if (args == 0 || *args == 0)
     { /* XXX FIXME: what should default behavior be?  */
@@ -2190,14 +2554,14 @@ trace_find_range_command (char *args, int from_tty)
 
   if (0 != (tmp = strchr (args, ',')))
     {
-      *tmp++ = '\0';   /* terminate start address */
+      *tmp++ = '\0';   /* Terminate start address.  */
       while (isspace ((int) *tmp))
        tmp++;
       start = parse_and_eval_address (args);
       stop = parse_and_eval_address (tmp);
     }
   else
-    {                  /* no explicit end address? */
+    {                  /* No explicit end address?  */
       start = parse_and_eval_address (args);
       stop = start + 1;        /* ??? */
     }
@@ -2210,28 +2574,27 @@ static void
 trace_find_outside_command (char *args, int from_tty)
 {
   CORE_ADDR start, stop;
-  char start_str[40], stop_str[40];
   char *tmp;
 
   if (current_trace_status ()->running && !current_trace_status ()->from_file)
-    error ("May not look at trace frames while trace is running.");
+    error (_("May not look at trace frames while trace is running."));
 
   if (args == 0 || *args == 0)
-    { /* XXX FIXME: what should default behavior be? */
+    { /* XXX FIXME: what should default behavior be?  */
       printf_filtered ("Usage: tfind outside <startaddr>,<endaddr>\n");
       return;
     }
 
   if (0 != (tmp = strchr (args, ',')))
     {
-      *tmp++ = '\0';   /* terminate start address */
+      *tmp++ = '\0';   /* Terminate start address.  */
       while (isspace ((int) *tmp))
        tmp++;
       start = parse_and_eval_address (args);
       stop = parse_and_eval_address (tmp);
     }
   else
-    {                  /* no explicit end address? */
+    {                  /* No explicit end address?  */
       start = parse_and_eval_address (args);
       stop = start + 1;        /* ??? */
     }
@@ -2247,36 +2610,38 @@ scope_info (char *args, int from_tty)
   struct symbol *sym;
   struct minimal_symbol *msym;
   struct block *block;
-  char **canonical, *symname, *save_args = args;
-  struct dict_iterator iter;
+  const char *symname;
+  char *save_args = args;
+  struct block_iterator iter;
   int j, count = 0;
   struct gdbarch *gdbarch;
   int regno;
 
   if (args == 0 || *args == 0)
-    error (_("requires an argument (function, line or *addr) to define a scope"));
+    error (_("requires an argument (function, "
+            "line or *addr) to define a scope"));
 
-  sals = decode_line_1 (&args, 1, NULL, 0, &canonical, NULL);
+  sals = decode_line_1 (&args, DECODE_LINE_FUNFIRSTLINE, NULL, 0);
   if (sals.nelts == 0)
-    return;            /* presumably decode_line_1 has already warned */
+    return;            /* Presumably decode_line_1 has already warned.  */
 
-  /* Resolve line numbers to PC */
+  /* Resolve line numbers to PC */
   resolve_sal_pc (&sals.sals[0]);
   block = block_for_pc (sals.sals[0].pc);
 
   while (block != 0)
     {
-      QUIT;                    /* allow user to bail out with ^C */
+      QUIT;                    /* Allow user to bail out with ^C.  */
       ALL_BLOCK_SYMBOLS (block, iter, sym)
        {
-         QUIT;                 /* allow user to bail out with ^C */
+         QUIT;                 /* Allow user to bail out with ^C.  */
          if (count == 0)
            printf_filtered ("Scope for %s:\n", save_args);
          count++;
 
          symname = SYMBOL_PRINT_NAME (sym);
          if (symname == NULL || *symname == '\0')
-           continue;           /* probably botched, certainly useless */
+           continue;           /* Probably botched, certainly useless.  */
 
          gdbarch = get_objfile_arch (SYMBOL_SYMTAB (sym)->objfile);
 
@@ -2284,14 +2649,15 @@ scope_info (char *args, int from_tty)
          switch (SYMBOL_CLASS (sym))
            {
            default:
-           case LOC_UNDEF:     /* messed up symbol? */
+           case LOC_UNDEF:     /* Messed up symbol?  */
              printf_filtered ("a bogus symbol, class %d.\n",
                               SYMBOL_CLASS (sym));
-             count--;          /* don't count this one */
+             count--;          /* Don't count this one.  */
              continue;
            case LOC_CONST:
-             printf_filtered ("a constant with value %ld (0x%lx)",
-                              SYMBOL_VALUE (sym), SYMBOL_VALUE (sym));
+             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: ");
@@ -2313,7 +2679,8 @@ scope_info (char *args, int from_tty)
                 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);
+             regno = SYMBOL_REGISTER_OPS (sym)->register_number (sym,
+                                                                 gdbarch);
 
              if (SYMBOL_IS_ARGUMENT (sym))
                printf_filtered ("an argument in register $%s",
@@ -2323,20 +2690,21 @@ scope_info (char *args, int from_tty)
                                 gdbarch_register_name (gdbarch, regno));
              break;
            case LOC_ARG:
-             printf_filtered ("an argument at stack/frame offset %ld",
-                              SYMBOL_VALUE (sym));
+             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 %ld",
-                              SYMBOL_VALUE (sym));
+             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 %ld",
-                              SYMBOL_VALUE (sym));
+             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);
+             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;
@@ -2369,7 +2737,9 @@ scope_info (char *args, int from_tty)
              printf_filtered ("optimized out.\n");
              continue;
            case LOC_COMPUTED:
-             SYMBOL_COMPUTED_OPS (sym)->describe_location (sym, gdb_stdout);
+             SYMBOL_COMPUTED_OPS (sym)->describe_location (sym,
+                                                           BLOCK_START (block),
+                                                           gdb_stdout);
              break;
            }
          if (SYMBOL_TYPE (sym))
@@ -2412,7 +2782,7 @@ trace_dump_actions (struct command_line *action,
     {
       struct cmd_list_element *cmd;
 
-      QUIT;                    /* allow user to bail out with ^C */
+      QUIT;                    /* Allow user to bail out with ^C.  */
       action_exp = action->line;
       while (isspace ((int) *action_exp))
        action_exp++;
@@ -2445,9 +2815,12 @@ trace_dump_actions (struct command_line *action,
             STEPPING_ACTIONS should be equal.  */
          if (stepping_frame == stepping_actions)
            {
+             if (*action_exp == '/')
+               action_exp = decode_agent_options (action_exp);
+
              do
-               {               /* repeat over a comma-separated list */
-                 QUIT;         /* allow user to bail out with ^C */
+               {               /* Repeat over a comma-separated list.  */
+                 QUIT;         /* Allow user to bail out with ^C.  */
                  if (*action_exp == ',')
                    action_exp++;
                  while (isspace ((int) *action_exp))
@@ -2457,6 +2830,8 @@ trace_dump_actions (struct command_line *action,
 
                  if (0 == strncasecmp (action_exp, "$reg", 4))
                    registers_info (NULL, from_tty);
+                 else if (0 == strncasecmp (action_exp, "$_ret", 5))
+                   ;
                  else if (0 == strncasecmp (action_exp, "$loc", 4))
                    locals_info (NULL, from_tty);
                  else if (0 == strncasecmp (action_exp, "$arg", 4))
@@ -2488,7 +2863,7 @@ static void
 trace_dump_command (char *args, int from_tty)
 {
   struct regcache *regcache;
-  struct breakpoint *t;
+  struct tracepoint *t;
   int stepping_frame = 0;
   struct bp_location *loc;
   char *line, *default_collect_line = NULL;
@@ -2521,11 +2896,11 @@ trace_dump_command (char *args, int from_tty)
      frame.  (FIXME this is not reliable, should record each frame's
      type.)  */
   stepping_frame = 1;
-  for (loc = t->loc; loc; loc = loc->next)
+  for (loc = t->base.loc; loc; loc = loc->next)
     if (loc->address == regcache_read_pc (regcache))
       stepping_frame = 0;
 
-  actions = breakpoint_commands (t);
+  actions = breakpoint_commands (&t->base);
 
   /* If there is a default-collect list, make up a collect command,
      prepend to the tracepoint's commands, and pass the whole mess to
@@ -2536,7 +2911,7 @@ trace_dump_command (char *args, int from_tty)
       default_collect_line = xstrprintf ("collect %s", default_collect);
       old_chain = make_cleanup (xfree, default_collect_line);
       line = default_collect_line;
-      validate_actionline (&line, t);
+      validate_actionline (&line, &t->base);
       default_collect_action = xmalloc (sizeof (struct command_line));
       make_cleanup (xfree, default_collect_action);
       default_collect_action->next = actions;
@@ -2562,7 +2937,8 @@ encode_source_string (int tpnum, ULONGEST addr,
   if (80 + strlen (srctype) > buf_size)
     error (_("Buffer too small for source encoding"));
   sprintf (buf, "%x:%s:%s:%x:%x:",
-          tpnum, phex_nz (addr, sizeof (addr)), srctype, 0, (int) strlen (src));
+          tpnum, phex_nz (addr, sizeof (addr)),
+          srctype, 0, (int) strlen (src));
   if (strlen (buf) + strlen (src) * 2 >= buf_size)
     error (_("Source string too long for buffer"));
   bin2hex (src, buf + strlen (buf), 0);
@@ -2611,7 +2987,7 @@ trace_save (const char *filename, int target_does_save)
   pathname = tilde_expand (filename);
   cleanup = make_cleanup (xfree, pathname);
 
-  fp = fopen (pathname, "w");
+  fp = fopen (pathname, "wb");
   if (!fp)
     error (_("Unable to open file '%s' for saving trace data (%s)"),
           filename, safe_strerror (errno));
@@ -2634,8 +3010,9 @@ trace_save (const char *filename, int target_does_save)
           (ts->running ? '1' : '0'), stop_reason_names[ts->stop_reason]);
   if (ts->stop_reason == tracepoint_error)
     {
-      char *buf = (char *) alloca (strlen (ts->error_desc) * 2 + 1);
-      bin2hex ((gdb_byte *) ts->error_desc, buf, 0);
+      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);
@@ -2687,6 +3064,9 @@ trace_save (const char *filename, int target_does_save)
 
   target_upload_tracepoints (&uploaded_tps);
 
+  for (utp = uploaded_tps; utp; utp = utp->next)
+    target_get_tracepoint_status (NULL, utp);
+
   for (utp = uploaded_tps; utp; utp = utp->next)
     {
       fprintf (fp, "tp T%x:%s:%c:%x:%x",
@@ -2701,7 +3081,7 @@ trace_save (const char *filename, int target_does_save)
       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->actions, a, act); ++a)
+      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)
@@ -2713,7 +3093,8 @@ trace_save (const char *filename, int target_does_save)
       if (utp->cond_string)
        {
          encode_source_string (utp->number, utp->addr,
-                               "cond", utp->cond_string, buf, MAX_TRACE_UPLOAD);
+                               "cond", utp->cond_string,
+                               buf, MAX_TRACE_UPLOAD);
          fprintf (fp, "tp Z%s\n", buf);
        }
       for (a = 0; VEC_iterate (char_ptr, utp->cmd_strings, a, act); ++a)
@@ -2722,6 +3103,11 @@ trace_save (const char *filename, int target_does_save)
                                buf, MAX_TRACE_UPLOAD);
          fprintf (fp, "tp Z%s\n", buf);
        }
+      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);
@@ -2784,7 +3170,7 @@ trace_save_command (char *args, int from_tty)
   trace_save (filename, target_does_save);
 
   if (from_tty)
-    printf_filtered (_("Trace data saved to file '%s'.\n"), args);
+    printf_filtered (_("Trace data saved to file '%s'.\n"), filename);
 
   do_cleanups (back_to);
 }
@@ -2792,17 +3178,11 @@ trace_save_command (char *args, int from_tty)
 /* Tell the target what to do with an ongoing tracing run if GDB
    disconnects for some reason.  */
 
-void
-send_disconnected_tracing_value (int value)
-{
-  target_set_disconnected_tracing (value);
-}
-
 static void
 set_disconnected_tracing (char *args, int from_tty,
                          struct cmd_list_element *c)
 {
-  send_disconnected_tracing_value (disconnected_tracing);
+  target_set_disconnected_tracing (disconnected_tracing);
 }
 
 static void
@@ -2812,6 +3192,42 @@ set_circular_trace_buffer (char *args, int from_tty,
   target_set_circular_trace_buffer (circular_trace_buffer);
 }
 
+static void
+set_trace_user (char *args, int from_tty,
+               struct cmd_list_element *c)
+{
+  int ret;
+
+  ret = target_set_trace_notes (trace_user, NULL, NULL);
+
+  if (!ret)
+    warning ("Target does not support trace notes, user ignored");
+}
+
+static void
+set_trace_notes (char *args, int from_tty,
+                struct cmd_list_element *c)
+{
+  int ret;
+
+  ret = target_set_trace_notes (NULL, trace_notes, NULL);
+
+  if (!ret)
+    warning ("Target does not support trace notes, note ignored");
+}
+
+static void
+set_trace_stop_notes (char *args, int from_tty,
+                     struct cmd_list_element *c)
+{
+  int ret;
+
+  ret = target_set_trace_notes (NULL, NULL, trace_stop_notes);
+
+  if (!ret)
+    warning ("Target does not support trace notes, stop note ignored");
+}
+
 /* Convert the memory pointed to by mem into hex, placing result in buf.
  * Return a pointer to the last char put in buf (null)
  * "stolen" from sparc-stub.c
@@ -2847,7 +3263,7 @@ get_traceframe_number (void)
    if NUM is already current.  */
 
 void
-set_traceframe_number (int num)
+set_current_traceframe (int num)
 {
   int newnum;
 
@@ -2867,6 +3283,17 @@ set_traceframe_number (int num)
   /* Changing the traceframe changes our view of registers and of the
      frame chain.  */
   registers_changed ();
+
+  clear_traceframe_info ();
+}
+
+/* Make the traceframe NUM be the current trace frame, and do nothing
+   more.  */
+
+void
+set_traceframe_number (int num)
+{
+  traceframe_number = num;
 }
 
 /* A cleanup used when switching away and back from tfind mode.  */
@@ -2882,7 +3309,7 @@ do_restore_current_traceframe_cleanup (void *arg)
 {
   struct current_traceframe_cleanup *old = arg;
 
-  set_traceframe_number (old->traceframe_number);
+  set_current_traceframe (old->traceframe_number);
 }
 
 static void
@@ -2905,6 +3332,12 @@ make_cleanup_restore_current_traceframe (void)
                            restore_current_traceframe_cleanup_dtor);
 }
 
+struct cleanup *
+make_cleanup_restore_traceframe_number (void)
+{
+  return make_cleanup_restore_integer (&traceframe_number);
+}
+
 /* Given a number and address, return an uploaded tracepoint with that
    number, creating if necessary.  */
 
@@ -2944,7 +3377,7 @@ free_uploaded_tps (struct uploaded_tp **utpp)
 /* Given a number and address, return an uploaded tracepoint with that
    number, creating if necessary.  */
 
-struct uploaded_tsv *
+static struct uploaded_tsv *
 get_uploaded_tsv (int num, struct uploaded_tsv **utsvp)
 {
   struct uploaded_tsv *utsv;
@@ -2973,32 +3406,48 @@ free_uploaded_tsvs (struct uploaded_tsv **utsvp)
     }
 }
 
-/* Look for an existing tracepoint that seems similar enough to the
-   uploaded one.  Enablement isn't compared, because the user can
-   toggle that freely, and may have done so in anticipation of the
-   next trace run.  */
+/* FIXME this function is heuristic and will miss the cases where the
+   conditional is semantically identical but differs in whitespace,
+   such as "x == 0" vs "x==0".  */
 
-struct breakpoint *
-find_matching_tracepoint (struct uploaded_tp *utp)
+static int
+cond_string_is_same (char *str1, char *str2)
 {
-  VEC(breakpoint_p) *tp_vec = all_tracepoints ();
+  if (str1 == NULL || str2 == NULL)
+    return (str1 == str2);
+
+  return (strcmp (str1, str2) == 0);
+}
+
+/* Look for an existing tracepoint that seems similar enough to the
+   uploaded one.  Enablement isn't compared, because the user can
+   toggle that freely, and may have done so in anticipation of the
+   next trace run.  Return the location of matched tracepoint.  */
+
+static struct bp_location *
+find_matching_tracepoint_location (struct uploaded_tp *utp)
+{
+  VEC(breakpoint_p) *tp_vec = all_tracepoints ();
   int ix;
-  struct breakpoint *t;
+  struct breakpoint *b;
   struct bp_location *loc;
 
-  for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
+  for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, b); ix++)
     {
-      if (t->type == utp->type
+      struct tracepoint *t = (struct tracepoint *) b;
+
+      if (b->type == utp->type
          && t->step_count == utp->step
          && t->pass_count == utp->pass
-         /* FIXME also test conditionals and actions */
+         && cond_string_is_same (t->base.cond_string, utp->cond_string)
+         /* FIXME also test actions.  */
          )
        {
          /* Scan the locations for an address match.  */
-         for (loc = t->loc; loc; loc = loc->next)
+         for (loc = b->loc; loc; loc = loc->next)
            {
              if (loc->address == utp->addr)
-               return t;
+               return loc;
            }
        }
     }
@@ -3013,24 +3462,37 @@ void
 merge_uploaded_tracepoints (struct uploaded_tp **uploaded_tps)
 {
   struct uploaded_tp *utp;
-  struct breakpoint *t;
 
   /* Look for GDB tracepoints that match up with our uploaded versions.  */
   for (utp = *uploaded_tps; utp; utp = utp->next)
     {
-      t = find_matching_tracepoint (utp);
-      if (t)
-       printf_filtered (_("Assuming tracepoint %d is same as target's tracepoint %d at %s.\n"),
-                        t->number, utp->number, paddress (get_current_arch (), utp->addr));
+      struct bp_location *loc;
+      struct tracepoint *t;
+
+      loc = find_matching_tracepoint_location (utp);
+      if (loc)
+       {
+         /* Mark this location as already inserted.  */
+         loc->inserted = 1;
+         t = (struct tracepoint *) loc->owner;
+         printf_filtered (_("Assuming tracepoint %d is same "
+                            "as target's tracepoint %d at %s.\n"),
+                          loc->owner->number, utp->number,
+                          paddress (loc->gdbarch, utp->addr));
+       }
       else
        {
          t = create_tracepoint_from_upload (utp);
          if (t)
-           printf_filtered (_("Created tracepoint %d for target's tracepoint %d at %s.\n"),
-                            t->number, utp->number, paddress (get_current_arch (), utp->addr));
+           printf_filtered (_("Created tracepoint %d for "
+                              "target's tracepoint %d at %s.\n"),
+                            t->base.number, utp->number,
+                            paddress (get_current_arch (), utp->addr));
          else
-           printf_filtered (_("Failed to create tracepoint for target's tracepoint %d at %s, skipping it.\n"),
-                            utp->number, paddress (get_current_arch (), utp->addr));
+           printf_filtered (_("Failed to create tracepoint for target's "
+                              "tracepoint %d at %s, skipping it.\n"),
+                            utp->number,
+                            paddress (get_current_arch (), utp->addr));
        }
       /* Whether found or created, record the number used by the
         target, to help with mapping target tracepoints back to their
@@ -3045,7 +3507,7 @@ merge_uploaded_tracepoints (struct uploaded_tp **uploaded_tps)
 /* Trace state variables don't have much to identify them beyond their
    name, so just use that to detect matches.  */
 
-struct trace_state_variable *
+static struct trace_state_variable *
 find_matching_tsv (struct uploaded_tsv *utsv)
 {
   if (!utsv->name)
@@ -3054,35 +3516,43 @@ find_matching_tsv (struct uploaded_tsv *utsv)
   return find_trace_state_variable (utsv->name);
 }
 
-struct trace_state_variable *
+static struct trace_state_variable *
 create_tsv_from_upload (struct uploaded_tsv *utsv)
 {
   const char *namebase;
-  char buf[20];
+  char *buf;
   int try_num = 0;
   struct trace_state_variable *tsv;
+  struct cleanup *old_chain;
 
   if (utsv->name)
     {
       namebase = utsv->name;
-      sprintf (buf, "%s", namebase);
+      buf = xstrprintf ("%s", namebase);
     }
   else
     {
       namebase = "__tsv";
-      sprintf (buf, "%s_%d", namebase, try_num++);
+      buf = xstrprintf ("%s_%d", namebase, try_num++);
     }
 
   /* Fish for a name that is not in use.  */
-  /* (should check against all internal vars?) */
+  /* (should check against all internal vars?)  */
   while (find_trace_state_variable (buf))
-    sprintf (buf, "%s_%d", namebase, try_num++);
+    {
+      xfree (buf);
+      buf = xstrprintf ("%s_%d", namebase, try_num++);
+    }
+
+  old_chain = make_cleanup (xfree, buf);
 
   /* We have an available name, create the variable.  */
-  tsv = create_trace_state_variable (xstrdup (buf));
+  tsv = create_trace_state_variable (buf);
   tsv->initial_value = utsv->initial_value;
   tsv->builtin = utsv->builtin;
 
+  do_cleanups (old_chain);
+
   return tsv;
 }
 
@@ -3106,13 +3576,19 @@ merge_uploaded_trace_state_variables (struct uploaded_tsv **uploaded_tsvs)
     {
       tsv = find_matching_tsv (utsv);
       if (tsv)
-       printf_filtered (_("Assuming trace state variable $%s is same as target's variable %d.\n"),
-                        tsv->name, utsv->number);
+       {
+         if (info_verbose)
+           printf_filtered (_("Assuming trace state variable $%s "
+                              "is same as target's variable %d.\n"),
+                            tsv->name, utsv->number);
+       }
       else
        {
          tsv = create_tsv_from_upload (utsv);
-         printf_filtered (_("Created trace state variable $%s for target's variable %d.\n"),
-                          tsv->name, utsv->number);
+         if (info_verbose)
+           printf_filtered (_("Created trace state variable "
+                              "$%s for target's variable %d.\n"),
+                            tsv->name, utsv->number);
        }
       /* Give precedence to numberings that come from the target.  */
       if (tsv)
@@ -3145,6 +3621,7 @@ char *trace_filename;
 int trace_fd = -1;
 off_t trace_frames_offset;
 off_t cur_offset;
+int cur_traceframe_number;
 int cur_data_size;
 int trace_regblock_size;
 
@@ -3152,17 +3629,36 @@ static void tfile_interp_line (char *line,
                               struct uploaded_tp **utpp,
                               struct uploaded_tsv **utsvp);
 
+/* Read SIZE bytes into READBUF from the trace frame, starting at
+   TRACE_FD's current position.  Note that this call `read'
+   underneath, hence it advances the file's seek position.  Throws an
+   error if the `read' syscall fails, or less than SIZE bytes are
+   read.  */
+
+static void
+tfile_read (gdb_byte *readbuf, int size)
+{
+  int gotten;
+
+  gotten = read (trace_fd, readbuf, size);
+  if (gotten < 0)
+    perror_with_name (trace_filename);
+  else if (gotten < size)
+    error (_("Premature end of file while reading trace file"));
+}
+
 static void
 tfile_open (char *filename, int from_tty)
 {
+  volatile struct gdb_exception ex;
   char *temp;
   struct cleanup *old_chain;
   int flags;
   int scratch_chan;
   char header[TRACE_HEADER_SIZE];
-  char linebuf[1000]; /* should be max remote packet size or so */
+  char linebuf[1000]; /* Should be max remote packet size or so.  */
   char byte;
-  int bytes, i, gotten;
+  int bytes, i;
   struct trace_status *ts;
   struct uploaded_tp *uploaded_tps = NULL;
   struct uploaded_tsv *uploaded_tsvs = NULL;
@@ -3174,7 +3670,7 @@ tfile_open (char *filename, int from_tty)
   filename = tilde_expand (filename);
   if (!IS_ABSOLUTE_PATH(filename))
     {
-      temp = concat (current_directory, "/", filename, (char *)NULL);
+      temp = concat (current_directory, "/", filename, (char *) NULL);
       xfree (filename);
       filename = temp;
     }
@@ -3189,27 +3685,23 @@ tfile_open (char *filename, int from_tty)
 
   /* Looks semi-reasonable.  Toss the old trace file and work on the new.  */
 
-  discard_cleanups (old_chain);        /* Don't free filename any more */
+  discard_cleanups (old_chain);        /* Don't free filename any more */
   unpush_target (&tfile_ops);
 
-  push_target (&tfile_ops);
-
   trace_filename = xstrdup (filename);
   trace_fd = scratch_chan;
 
   bytes = 0;
   /* Read the file header and test for validity.  */
-  gotten = read (trace_fd, &header, TRACE_HEADER_SIZE);
-  if (gotten < 0)
-    perror_with_name (trace_filename);
-  else if (gotten < TRACE_HEADER_SIZE)
-    error (_("Premature end of file while reading trace file"));
+  tfile_read ((gdb_byte *) &header, TRACE_HEADER_SIZE);
 
   bytes += TRACE_HEADER_SIZE;
   if (!(header[0] == 0x7f
        && (strncmp (header + 1, "TRACE0\n", 7) == 0)))
     error (_("File is not a valid trace file."));
 
+  push_target (&tfile_ops);
+
   trace_regblock_size = 0;
   ts = current_trace_status ();
   /* We know we're working with a file.  */
@@ -3222,32 +3714,54 @@ tfile_open (char *filename, int from_tty)
   ts->disconnected_tracing = 0;
   ts->circular_buffer = 0;
 
-  /* Read through a section of newline-terminated lines that
-     define things like tracepoints.  */
-  i = 0;
-  while (1)
-    {
-      gotten = read (trace_fd, &byte, 1);
-      if (gotten < 0)
-       perror_with_name (trace_filename);
-      else if (gotten < 1)
-       error (_("Premature end of file while reading trace file"));
+  cur_traceframe_number = -1;
 
-      ++bytes;
-      if (byte == '\n')
+  TRY_CATCH (ex, RETURN_MASK_ALL)
+    {
+      /* Read through a section of newline-terminated lines that
+        define things like tracepoints.  */
+      i = 0;
+      while (1)
        {
-         /* Empty line marks end of the definition section.  */
-         if (i == 0)
-           break;
-         linebuf[i] = '\0';
-         i = 0;
-         tfile_interp_line (linebuf, &uploaded_tps, &uploaded_tsvs);
+         tfile_read (&byte, 1);
+
+         ++bytes;
+         if (byte == '\n')
+           {
+             /* Empty line marks end of the definition section.  */
+             if (i == 0)
+               break;
+             linebuf[i] = '\0';
+             i = 0;
+             tfile_interp_line (linebuf, &uploaded_tps, &uploaded_tsvs);
+           }
+         else
+           linebuf[i++] = byte;
+         if (i >= 1000)
+           error (_("Excessively long lines in trace file"));
        }
-      else
-       linebuf[i++] = byte;
-      if (i >= 1000)
-       error (_("Excessively long lines in trace file"));
+
+      /* Record the starting offset of the binary trace data.  */
+      trace_frames_offset = bytes;
+
+      /* If we don't have a blocksize, we can't interpret the
+        traceframes.  */
+      if (trace_regblock_size == 0)
+       error (_("No register block size recorded in trace file"));
     }
+  if (ex.reason < 0)
+    {
+      /* Pop the partially set up target.  */
+      pop_target ();
+      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."));
 
   /* Add the file's tracepoints and variables into the current mix.  */
 
@@ -3257,30 +3771,7 @@ tfile_open (char *filename, int from_tty)
 
   merge_uploaded_tracepoints (&uploaded_tps);
 
-  /* Record the starting offset of the binary trace data.  */
-  trace_frames_offset = bytes;
-
-  /* If we don't have a blocksize, we can't interpret the
-     traceframes.  */
-  if (trace_regblock_size == 0)
-    error (_("No register block size recorded in trace file"));
-  if (ts->traceframe_count <= 0)
-    {
-      warning ("No traceframes present in this file.");
-      return;
-    }
-
-#define TFILE_PID (1)
-  inferior_appeared (current_inferior (), TFILE_PID);
-  inferior_ptid = pid_to_ptid (TFILE_PID);
-  add_thread_silent (inferior_ptid);
-
   post_create_inferior (&tfile_ops, from_tty);
-
-#if 0
-  /* FIXME this will get defined in MI patch submission */
-  tfind_1 (tfind_number, 0, 0, 0, 0);
-#endif
 }
 
 /* Interpret the given line from the definitions part of the trace
@@ -3313,31 +3804,35 @@ tfile_interp_line (char *line,
       parse_tsv_definition (p, utsvp);
     }
   else
-    warning ("Ignoring trace file definition \"%s\"", line);
+    warning (_("Ignoring trace file definition \"%s\""), line);
 }
 
 /* Parse the part of trace status syntax that is shared between
    the remote protocol and the trace file reader.  */
 
-extern char *unpack_varlen_hex (char *buff, ULONGEST *result);
-
 void
 parse_trace_status (char *line, struct trace_status *ts)
 {
-  char *p = line, *p1, *p2, *p_temp;
+  char *p = line, *p1, *p2, *p3, *p_temp;
+  int end;
   ULONGEST val;
 
   ts->running_known = 1;
   ts->running = (*p++ == '1');
   ts->stop_reason = trace_stop_reason_unknown;
-  xfree (ts->error_desc);
-  ts->error_desc = NULL;
+  xfree (ts->stop_desc);
+  ts->stop_desc = NULL;
   ts->traceframe_count = -1;
   ts->traceframes_created = -1;
   ts->buffer_free = -1;
   ts->buffer_size = -1;
   ts->disconnected_tracing = 0;
   ts->circular_buffer = 0;
+  xfree (ts->user_name);
+  ts->user_name = NULL;
+  xfree (ts->notes);
+  ts->notes = NULL;
+  ts->start_time = ts->stop_time = 0;
 
   while (*p++)
     {
@@ -3345,6 +3840,9 @@ parse_trace_status (char *line, struct trace_status *ts)
       if (p1 == NULL)
        error (_("Malformed trace status, at %s\n\
 Status line: '%s'\n"), p, line);
+      p3 = strchr (p, ';');
+      if (p3 == NULL)
+       p3 = p + strlen (p);
       if (strncmp (p, stop_reason_names[trace_buffer_full], p1 - p) == 0)
        {
          p = unpack_varlen_hex (++p1, &val);
@@ -3355,7 +3853,8 @@ Status line: '%s'\n"), p, line);
          p = unpack_varlen_hex (++p1, &val);
          ts->stop_reason = trace_never_run;
        }
-      else if (strncmp (p, stop_reason_names[tracepoint_passcount], p1 - p) == 0)
+      else if (strncmp (p, stop_reason_names[tracepoint_passcount],
+                       p1 - p) == 0)
        {
          p = unpack_varlen_hex (++p1, &val);
          ts->stop_reason = tracepoint_passcount;
@@ -3363,7 +3862,22 @@ Status line: '%s'\n"), p, line);
        }
       else if (strncmp (p, stop_reason_names[tstop_command], p1 - p) == 0)
        {
-         p = unpack_varlen_hex (++p1, &val);
+         p2 = strchr (++p1, ':');
+         if (!p2 || p2 > p3)
+           {
+             /*older style*/
+             p2 = p1;
+           }
+         else if (p2 != p1)
+           {
+             ts->stop_desc = xmalloc (strlen (line));
+             end = hex2bin (p1, ts->stop_desc, (p2 - p1) / 2);
+             ts->stop_desc[end] = '\0';
+           }
+         else
+           ts->stop_desc = xstrdup ("");
+
+         p = unpack_varlen_hex (++p2, &val);
          ts->stop_reason = tstop_command;
        }
       else if (strncmp (p, stop_reason_names[trace_disconnected], p1 - p) == 0)
@@ -3376,14 +3890,12 @@ Status line: '%s'\n"), p, line);
          p2 = strchr (++p1, ':');
          if (p2 != p1)
            {
-             int end;
-
-             ts->error_desc = xmalloc ((p2 - p1) / 2 + 1);
-             end = hex2bin (p1, ts->error_desc, (p2 - p1) / 2);
-             ts->error_desc[end] = '\0';
+             ts->stop_desc = xmalloc ((p2 - p1) / 2 + 1);
+             end = hex2bin (p1, ts->stop_desc, (p2 - p1) / 2);
+             ts->stop_desc[end] = '\0';
            }
          else
-           ts->error_desc = xstrdup ("");
+           ts->stop_desc = xstrdup ("");
 
          p = unpack_varlen_hex (++p2, &val);
          ts->stopping_tracepoint = val;
@@ -3419,6 +3931,32 @@ Status line: '%s'\n"), p, line);
          p = unpack_varlen_hex (++p1, &val);
          ts->circular_buffer = val;
        }
+      else if (strncmp (p, "starttime", p1 - p) == 0)
+       {
+         p = unpack_varlen_hex (++p1, &val);
+         ts->start_time = val;
+       }
+      else if (strncmp (p, "stoptime", p1 - p) == 0)
+       {
+         p = unpack_varlen_hex (++p1, &val);
+         ts->stop_time = val;
+       }
+      else if (strncmp (p, "username", p1 - p) == 0)
+       {
+         ++p1;
+         ts->user_name = xmalloc (strlen (p) / 2);
+         end = hex2bin (p1, ts->user_name, (p3 - p1)  / 2);
+         ts->user_name[end] = '\0';
+         p = p3;
+       }
+      else if (strncmp (p, "notes", p1 - p) == 0)
+       {
+         ++p1;
+         ts->notes = xmalloc (strlen (p) / 2);
+         end = hex2bin (p1, ts->notes, (p3 - p1) / 2);
+         ts->notes[end] = '\0';
+         p = p3;
+       }
       else
        {
          /* Silently skip unknown optional info.  */
@@ -3432,6 +3970,26 @@ Status line: '%s'\n"), p, line);
     }
 }
 
+void
+parse_tracepoint_status (char *p, struct breakpoint *bp,
+                        struct uploaded_tp *utp)
+{
+  ULONGEST uval;
+  struct tracepoint *tp = (struct tracepoint *) bp;
+
+  p = unpack_varlen_hex (p, &uval);
+  if (tp)
+    tp->base.hit_count += uval;
+  else
+    utp->hit_count += uval;
+  p = unpack_varlen_hex (p + 1, &uval);
+  if (tp)
+    tp->traceframe_usage += uval;
+  else
+    utp->traceframe_usage += uval;
+  /* Ignore any extra, allowing for future extensions.  */
+}
+
 /* Given a line of text defining a part of a tracepoint, parse it into
    an "uploaded tracepoint".  */
 
@@ -3441,9 +3999,9 @@ parse_tracepoint_definition (char *line, struct uploaded_tp **utpp)
   char *p;
   char piece;
   ULONGEST num, addr, step, pass, orig_size, xlen, start;
-  int enabled, i, end;
+  int enabled, end;
   enum bptype type;
-  char *cond, *srctype, *src, *buf;
+  char *cond, *srctype, *buf;
   struct uploaded_tp *utp = NULL;
 
   p = line;
@@ -3473,6 +4031,11 @@ parse_tracepoint_definition (char *line, struct uploaded_tp **utpp)
              p++;
              p = unpack_varlen_hex (p, &orig_size);
            }
+         else if (*p == 'S')
+           {
+             type = bp_static_tracepoint;
+             p++;
+           }
          else if (*p == 'X')
            {
              p++;
@@ -3484,7 +4047,8 @@ parse_tracepoint_definition (char *line, struct uploaded_tp **utpp)
              p += 2 * xlen;
            }
          else
-           warning (_("Unrecognized char '%c' in tracepoint definition, skipping rest"), *p);
+           warning (_("Unrecognized char '%c' in tracepoint "
+                      "definition, skipping rest"), *p);
        }
       utp = get_uploaded_tp (num, addr, utpp);
       utp->type = type;
@@ -3527,6 +4091,12 @@ parse_tracepoint_definition (char *line, struct uploaded_tp **utpp)
       else if (strncmp (srctype, "cmd:", strlen ("cmd:")) == 0)
        VEC_safe_push (char_ptr, utp->cmd_strings, xstrdup (buf));
     }
+  else if (piece == 'V')
+    {
+      utp = get_uploaded_tp (num, addr, utpp);
+
+      parse_tracepoint_status (p, NULL, utp);
+    }
   else
     {
       /* Don't error out, the target might be sending us optional
@@ -3575,19 +4145,19 @@ tfile_close (int quitting)
     return;
 
   pid = ptid_get_pid (inferior_ptid);
-  inferior_ptid = null_ptid;   /* Avoid confusion from thread stuff */
+  inferior_ptid = null_ptid;   /* Avoid confusion from thread stuff */
   exit_inferior_silent (pid);
 
   close (trace_fd);
   trace_fd = -1;
-  if (trace_filename)
-    xfree (trace_filename);
+  xfree (trace_filename);
+  trace_filename = NULL;
 }
 
 static void
 tfile_files_info (struct target_ops *t)
 {
-  /* (it would be useful to mention the name of the file) */
+  /* (it would be useful to mention the name of the file) */
   printf_filtered ("Looking at a trace file.\n");
 }
 
@@ -3602,6 +4172,13 @@ tfile_get_trace_status (struct trace_status *ts)
   return -1;
 }
 
+static void
+tfile_get_tracepoint_status (struct breakpoint *tp, struct uploaded_tp *utp)
+{
+  /* Other bits of trace status were collected as part of opening the
+     trace files, so nothing to do here.  */
+}
+
 /* Given the position of a traceframe in the file, figure out what
    address the frame was collected at.  This would normally be the
    value of a collected PC register, but if not available, we
@@ -3612,24 +4189,22 @@ tfile_get_traceframe_address (off_t tframe_offset)
 {
   ULONGEST addr = 0;
   short tpnum;
-  struct breakpoint *tp;
+  struct tracepoint *tp;
   off_t saved_offset = cur_offset;
-  int gotten;
 
-  /* FIXME dig pc out of collected registers */
+  /* FIXME dig pc out of collected registers */
 
   /* Fall back to using tracepoint address.  */
   lseek (trace_fd, tframe_offset, SEEK_SET);
-  gotten = read (trace_fd, &tpnum, 2);
-  if (gotten < 0)
-    perror_with_name (trace_filename);
-  else if (gotten < 2)
-    error (_("Premature end of file while reading trace file"));
+  tfile_read ((gdb_byte *) &tpnum, 2);
+  tpnum = (short) extract_signed_integer ((gdb_byte *) &tpnum, 2,
+                                         gdbarch_byte_order
+                                             (target_gdbarch));
 
   tp = get_tracepoint_by_number_on_target (tpnum);
-  /* FIXME this is a poor heuristic if multiple locations */
-  if (tp && tp->loc)
-    addr = tp->loc->address;
+  /* FIXME this is a poor heuristic if multiple locations */
+  if (tp && tp->base.loc)
+    addr = tp->base.loc->address;
 
   /* Restore our seek position.  */
   cur_offset = saved_offset;
@@ -3637,6 +4212,28 @@ 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
@@ -3647,30 +4244,40 @@ tfile_trace_find (enum trace_find_type type, int num,
                  ULONGEST addr1, ULONGEST addr2, int *tpp)
 {
   short tpnum;
-  int tfnum = 0, found = 0, gotten;
-  int data_size;
-  struct breakpoint *tp;
+  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)
+    {
+      if (tpp)
+        *tpp = -1;
+      return -1;
+    }
+
   lseek (trace_fd, trace_frames_offset, SEEK_SET);
   offset = trace_frames_offset;
   while (1)
     {
       tframe_offset = offset;
-      gotten = read (trace_fd, &tpnum, 2);
-      if (gotten < 0)
-       perror_with_name (trace_filename);
-      else if (gotten < 2)
-       error (_("Premature end of file while reading trace file"));
+      tfile_read ((gdb_byte *) &tpnum, 2);
+      tpnum = (short) extract_signed_integer ((gdb_byte *) &tpnum, 2,
+                                             gdbarch_byte_order
+                                                 (target_gdbarch));
       offset += 2;
       if (tpnum == 0)
        break;
-      gotten = read (trace_fd, &data_size, 4); 
-      if (gotten < 0)
-       perror_with_name (trace_filename);
-      else if (gotten < 4)
-       error (_("Premature end of file while reading trace file"));
+      tfile_read ((gdb_byte *) &data_size, 4);
+      data_size = (unsigned int) extract_unsigned_integer
+                                     ((gdb_byte *) &data_size, 4,
+                                     gdbarch_byte_order (target_gdbarch));
       offset += 4;
       switch (type)
        {
@@ -3707,6 +4314,7 @@ tfile_trace_find (enum trace_find_type type, int num,
            *tpp = tpnum;
          cur_offset = offset;
          cur_data_size = data_size;
+         cur_traceframe_number = tfnum;
          return tfnum;
        }
       /* Skip past the traceframe's data.  */
@@ -3721,6 +4329,90 @@ tfile_trace_find (enum trace_find_type type, int num,
   return -1;
 }
 
+/* Prototype of the callback passed to tframe_walk_blocks.  */
+typedef int (*walk_blocks_callback_func) (char blocktype, void *data);
+
+/* Callback for traceframe_walk_blocks, used to find a given block
+   type in a traceframe.  */
+
+static int
+match_blocktype (char blocktype, void *data)
+{
+  char *wantedp = data;
+
+  if (*wantedp == blocktype)
+    return 1;
+
+  return 0;
+}
+
+/* Walk over all traceframe block starting at POS offset from
+   CUR_OFFSET, and call CALLBACK for each block found, passing in DATA
+   unmodified.  If CALLBACK returns true, this returns the position in
+   the traceframe where the block is found, relative to the start of
+   the traceframe (cur_offset).  Returns -1 if no callback call
+   returned true, indicating that all blocks have been walked.  */
+
+static int
+traceframe_walk_blocks (walk_blocks_callback_func callback,
+                       int pos, void *data)
+{
+  /* Iterate through a traceframe's blocks, looking for a block of the
+     requested type.  */
+
+  lseek (trace_fd, cur_offset + pos, SEEK_SET);
+  while (pos < cur_data_size)
+    {
+      unsigned short mlen;
+      char block_type;
+
+      tfile_read (&block_type, 1);
+
+      ++pos;
+
+      if ((*callback) (block_type, data))
+       return pos;
+
+      switch (block_type)
+       {
+       case 'R':
+         lseek (trace_fd, cur_offset + pos + trace_regblock_size, SEEK_SET);
+         pos += trace_regblock_size;
+         break;
+       case 'M':
+         lseek (trace_fd, cur_offset + pos + 8, SEEK_SET);
+         tfile_read ((gdb_byte *) &mlen, 2);
+          mlen = (unsigned short)
+                extract_unsigned_integer ((gdb_byte *) &mlen, 2,
+                                          gdbarch_byte_order
+                                              (target_gdbarch));
+         lseek (trace_fd, mlen, SEEK_CUR);
+         pos += (8 + 2 + mlen);
+         break;
+       case 'V':
+         lseek (trace_fd, cur_offset + pos + 4 + 8, SEEK_SET);
+         pos += (4 + 8);
+         break;
+       default:
+         error (_("Unknown block type '%c' (0x%x) in trace frame"),
+                block_type, block_type);
+         break;
+       }
+    }
+
+  return -1;
+}
+
+/* Convenience wrapper around traceframe_walk_blocks.  Looks for the
+   position offset of a block of type TYPE_WANTED in the current trace
+   frame, starting at POS.  Returns -1 if no such block was found.  */
+
+static int
+traceframe_find_block_type (char type_wanted, int pos)
+{
+  return traceframe_walk_blocks (match_blocktype, pos, &type_wanted);
+}
+
 /* Look for a block of saved registers in the traceframe, and get the
    requested register from it.  */
 
@@ -3729,9 +4421,7 @@ tfile_fetch_registers (struct target_ops *ops,
                       struct regcache *regcache, int regno)
 {
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
-  char block_type;
-  int i, pos, offset, regn, regsize, gotten, pc_regno;
-  unsigned short mlen;
+  int offset, regn, regsize, pc_regno;
   char *regs;
 
   /* An uninitialized reg size says we're not going to be
@@ -3739,77 +4429,42 @@ tfile_fetch_registers (struct target_ops *ops,
   if (!trace_regblock_size)
     return;
 
+  set_tfile_traceframe ();
+
   regs = alloca (trace_regblock_size);
 
-  lseek (trace_fd, cur_offset, SEEK_SET);
-  pos = 0;
-  while (pos < cur_data_size)
+  if (traceframe_find_block_type ('R', 0) >= 0)
     {
-      gotten = read (trace_fd, &block_type, 1);
-      if (gotten < 0)
-       perror_with_name (trace_filename);
-      else if (gotten < 1)
-       error (_("Premature end of file while reading trace file"));
+      tfile_read (regs, trace_regblock_size);
 
-      ++pos;
-      switch (block_type)
+      /* Assume the block is laid out in GDB register number order,
+        each register with the size that it has in GDB.  */
+      offset = 0;
+      for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
        {
-       case 'R':
-         gotten = read (trace_fd, regs, trace_regblock_size);
-         if (gotten < 0)
-           perror_with_name (trace_filename);
-         else if (gotten < trace_regblock_size)
-           error (_("Premature end of file while reading trace file"));
-
-         /* Assume the block is laid out in GDB register number order,
-            each register with the size that it has in GDB.  */
-         offset = 0;
-         for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+         regsize = register_size (gdbarch, regn);
+         /* Make sure we stay within block bounds.  */
+         if (offset + regsize >= trace_regblock_size)
+           break;
+         if (regcache_register_status (regcache, regn) == REG_UNKNOWN)
            {
-             regsize = register_size (gdbarch, regn);
-             /* Make sure we stay within block bounds.  */
-             if (offset + regsize >= trace_regblock_size)
-               break;
-             if (!regcache_valid_p (regcache, regn))
+             if (regno == regn)
                {
-                 if (regno == regn)
-                   {
-                     regcache_raw_supply (regcache, regno, regs + offset);
-                     break;
-                   }
-                 else if (regno == -1)
-                   {
-                     regcache_raw_supply (regcache, regn, regs + offset);
-                   }
+                 regcache_raw_supply (regcache, regno, regs + offset);
+                 break;
+               }
+             else if (regno == -1)
+               {
+                 regcache_raw_supply (regcache, regn, regs + offset);
                }
-             offset += regsize;
            }
-         return;
-       case 'M':
-         lseek (trace_fd, 8, SEEK_CUR);
-         gotten = read (trace_fd, &mlen, 2);
-         if (gotten < 0)
-           perror_with_name (trace_filename);
-         else if (gotten < 2)
-           error (_("Premature end of file while reading trace file"));
-         lseek (trace_fd, mlen, SEEK_CUR);
-         pos += (8 + 2 + mlen);
-         break;
-       case 'V':
-         lseek (trace_fd, 4 + 8, SEEK_CUR);
-         pos += (4 + 8);
-         break;
-       default:
-         error ("Unknown block type '%c' (0x%x) in trace frame",
-                block_type, block_type);
-         break;
+         offset += regsize;
        }
+      return;
     }
 
-  /* We get here if no register data has been found.  Although we
-     don't like making up numbers, GDB has all manner of troubles when
-     the target says some register is not available.  Filling in with
-     zeroes is a reasonable fallback.  */
+  /* We get here if no register data has been found.  Mark registers
+     as unavailable.  */
   for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
     regcache_raw_supply (regcache, regn, NULL);
 
@@ -3818,28 +4473,30 @@ tfile_fetch_registers (struct target_ops *ops,
   pc_regno = gdbarch_pc_regnum (gdbarch);
   if (pc_regno >= 0 && (regno == -1 || regno == pc_regno))
     {
-      struct breakpoint *tp = get_tracepoint (tracepoint_number);
+      struct tracepoint *tp = get_tracepoint (tracepoint_number);
 
-      if (tp && tp->loc)
+      if (tp && tp->base.loc)
        {
          /* But don't try to guess if tracepoint is multi-location...  */
-         if (tp->loc->next)
+         if (tp->base.loc->next)
            {
-             warning ("Tracepoint %d has multiple locations, cannot infer $pc",
-                      tp->number);
+             warning (_("Tracepoint %d has multiple "
+                        "locations, cannot infer $pc"),
+                      tp->base.number);
              return;
            }
          /* ... or does while-stepping.  */
          if (tp->step_count > 0)
            {
-             warning ("Tracepoint %d does while-stepping, cannot infer $pc",
-                      tp->number);
+             warning (_("Tracepoint %d does while-stepping, "
+                        "cannot infer $pc"),
+                      tp->base.number);
              return;
            }
 
          store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
                                  gdbarch_byte_order (gdbarch),
-                                 tp->loc->address);
+                                 tp->base.loc->address);
          regcache_raw_supply (regcache, pc_regno, regs);
        }
     }
@@ -3850,106 +4507,81 @@ tfile_xfer_partial (struct target_ops *ops, enum target_object object,
                    const char *annex, gdb_byte *readbuf,
                    const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
 {
-  char block_type;
-  int pos, gotten;
-  ULONGEST maddr, amt;
-  unsigned short mlen;
-
   /* We're only doing regular memory for now.  */
   if (object != TARGET_OBJECT_MEMORY)
     return -1;
 
   if (readbuf == NULL)
-    error ("tfile_xfer_partial: trace file is read-only");
+    error (_("tfile_xfer_partial: trace file is read-only"));
 
-  lseek (trace_fd, cur_offset, SEEK_SET);
-  pos = 0;
 while (pos < cur_data_size)
+  set_tfile_traceframe ();
+
if (traceframe_number != -1)
     {
-      gotten = read (trace_fd, &block_type, 1);
-      if (gotten < 0)
-       perror_with_name (trace_filename);
-      else if (gotten < 1)
-       error (_("Premature end of file while reading trace file"));
-      ++pos;
-      switch (block_type)
+      int pos = 0;
+
+      /* Iterate through the traceframe's blocks, looking for
+        memory.  */
+      while ((pos = traceframe_find_block_type ('M', pos)) >= 0)
        {
-       case 'R':
-         lseek (trace_fd, trace_regblock_size, SEEK_CUR);
-         pos += trace_regblock_size;
-         break;
-       case 'M':
-         gotten = read (trace_fd, &maddr, 8);
-         if (gotten < 0)
-           perror_with_name (trace_filename);
-         else if (gotten < 8)
-           error (_("Premature end of file while reading trace file"));
-
-         gotten = read (trace_fd, &mlen, 2);
-         if (gotten < 0)
-           perror_with_name (trace_filename);
-         else if (gotten < 2)
-           error (_("Premature end of file while reading trace file"));
+         ULONGEST maddr, amt;
+         unsigned short mlen;
+         enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
+
+         tfile_read ((gdb_byte *) &maddr, 8);
+         maddr = extract_unsigned_integer ((gdb_byte *) &maddr, 8,
+                                           byte_order);
+         tfile_read ((gdb_byte *) &mlen, 2);
+         mlen = (unsigned short)
+           extract_unsigned_integer ((gdb_byte *) &mlen, 2, byte_order);
+
          /* If the block includes the first part of the desired
             range, return as much it has; GDB will re-request the
             remainder, which might be in a different block of this
             trace frame.  */
          if (maddr <= offset && offset < (maddr + mlen))
-           {
+           {
              amt = (maddr + mlen) - offset;
              if (amt > len)
                amt = len;
 
-             gotten = read (trace_fd, readbuf, amt);
-             if (gotten < 0)
-               perror_with_name (trace_filename);
-             /* While it's acceptable to return less than was
-                originally asked for, it's not acceptable to return
-                less than what this block claims to contain.  */
-             else if (gotten < amt)
-               error (_("Premature end of file while reading trace file"));
+             tfile_read (readbuf, amt);
              return amt;
-           }
-         lseek (trace_fd, mlen, SEEK_CUR);
+           }
+
+         /* Skip over this block.  */
          pos += (8 + 2 + mlen);
-         break;
-       case 'V':
-         lseek (trace_fd, 4 + 8, SEEK_CUR);
-         pos += (4 + 8);
-         break;
-       default:
-         error ("Unknown block type '%c' (0x%x) in traceframe",
-                block_type, block_type);
-         break;
        }
     }
 
   /* It's unduly pedantic to refuse to look at the executable for
      read-only pieces; so do the equivalent of readonly regions aka
      QTro packet.  */
-  /* FIXME account for relocation at some point */
+  /* FIXME account for relocation at some point */
   if (exec_bfd)
     {
       asection *s;
       bfd_size_type size;
-      bfd_vma lma;
+      bfd_vma vma;
 
       for (s = exec_bfd->sections; s; s = s->next)
        {
-         if ((s->flags & SEC_LOAD) == 0 ||
-             (s->flags & SEC_READONLY) == 0)
+         if ((s->flags & SEC_LOAD) == 0
+             || (s->flags & SEC_READONLY) == 0)
            continue;
 
-         lma = s->lma;
+         vma = s->vma;
          size = bfd_get_section_size (s);
-         if (lma <= offset && offset < (lma + size))
+         if (vma <= offset && offset < (vma + size))
            {
-             amt = (lma + size) - offset;
+             ULONGEST amt;
+
+             amt = (vma + size) - offset;
              if (amt > len)
                amt = len;
 
              amt = bfd_get_section_contents (exec_bfd, s,
-                                             readbuf, offset - lma, amt);
+                                             readbuf, offset - vma, amt);
              return amt;
            }
        }
@@ -3965,60 +4597,30 @@ tfile_xfer_partial (struct target_ops *ops, enum target_object object,
 static int
 tfile_get_trace_state_variable_value (int tsvnum, LONGEST *val)
 {
-  char block_type;
-  int pos, vnum, gotten;
-  unsigned short mlen;
+  int pos;
+
+  set_tfile_traceframe ();
 
-  lseek (trace_fd, cur_offset, SEEK_SET);
   pos = 0;
-  while (pos < cur_data_size)
+  while ((pos = traceframe_find_block_type ('V', pos)) >= 0)
     {
-      gotten = read (trace_fd, &block_type, 1);
-      if (gotten < 0)
-       perror_with_name (trace_filename);
-      else if (gotten < 1)
-       error (_("Premature end of file while reading trace file"));
-      ++pos;
-      switch (block_type)
+      int vnum;
+
+      tfile_read ((gdb_byte *) &vnum, 4);
+      vnum = (int) extract_signed_integer ((gdb_byte *) &vnum, 4,
+                                          gdbarch_byte_order
+                                          (target_gdbarch));
+      if (tsvnum == vnum)
        {
-       case 'R':
-         lseek (trace_fd, trace_regblock_size, SEEK_CUR);
-         pos += trace_regblock_size;
-         break;
-       case 'M':
-         lseek (trace_fd, 8, SEEK_CUR);
-         gotten = read (trace_fd, &mlen, 2);
-         if (gotten < 0)
-           perror_with_name (trace_filename);
-         else if (gotten < 2)
-           error (_("Premature end of file while reading trace file"));
-         lseek (trace_fd, mlen, SEEK_CUR);
-         pos += (8 + 2 + mlen);
-         break;
-       case 'V':
-         gotten = read (trace_fd, &vnum, 4);
-         if (gotten < 0)
-           perror_with_name (trace_filename);
-         else if (gotten < 4)
-           error (_("Premature end of file while reading trace file"));
-         if (tsvnum == vnum)
-           {
-             gotten = read (trace_fd, val, 8);
-             if (gotten < 0)
-               perror_with_name (trace_filename);
-             else if (gotten < 8)
-               error (_("Premature end of file while reading trace file"));
-             return 1;
-           }
-         lseek (trace_fd, 8, SEEK_CUR);
-         pos += (4 + 8);
-         break;
-       default:
-         error ("Unknown block type '%c' (0x%x) in traceframe",
-                block_type, block_type);
-         break;
+         tfile_read ((gdb_byte *) val, 8);
+         *val = extract_signed_integer ((gdb_byte *) val, 8,
+                                        gdbarch_byte_order
+                                        (target_gdbarch));
+         return 1;
        }
+      pos += (4 + 8);
     }
+
   /* Didn't find anything.  */
   return 0;
 }
@@ -4038,46 +4640,541 @@ tfile_has_memory (struct target_ops *ops)
 static int
 tfile_has_stack (struct target_ops *ops)
 {
-  return 1;
+  return traceframe_number != -1;
 }
 
 static int
 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.  */
+
+static int
+build_traceframe_info (char blocktype, void *data)
+{
+  struct traceframe_info *info = data;
+
+  switch (blocktype)
+    {
+    case 'M':
+      {
+       struct mem_range *r;
+       ULONGEST maddr;
+       unsigned short mlen;
+
+       tfile_read ((gdb_byte *) &maddr, 8);
+       tfile_read ((gdb_byte *) &mlen, 2);
+
+       r = VEC_safe_push (mem_range_s, info->memory, NULL);
+
+       r->start = maddr;
+       r->length = mlen;
+       break;
+      }
+    case 'V':
+    case 'R':
+    case 'S':
+      {
+       break;
+      }
+    default:
+      warning (_("Unhandled trace block type (%d) '%c ' "
+                "while building trace frame info."),
+              blocktype, blocktype);
+      break;
+    }
+
+  return 0;
+}
+
+static struct traceframe_info *
+tfile_traceframe_info (void)
+{
+  struct traceframe_info *info = XCNEW (struct traceframe_info);
+
+  traceframe_walk_blocks (build_traceframe_info, 0, info);
+  return info;
+}
+
 static void
 init_tfile_ops (void)
 {
   tfile_ops.to_shortname = "tfile";
   tfile_ops.to_longname = "Local trace dump file";
-  tfile_ops.to_doc =
-    "Use a trace file as a target.  Specify the filename of the trace file.";
+  tfile_ops.to_doc
+    "Use a trace file as a target.  Specify the filename of the trace file.";
   tfile_ops.to_open = tfile_open;
   tfile_ops.to_close = tfile_close;
   tfile_ops.to_fetch_registers = tfile_fetch_registers;
   tfile_ops.to_xfer_partial = tfile_xfer_partial;
   tfile_ops.to_files_info = tfile_files_info;
   tfile_ops.to_get_trace_status = tfile_get_trace_status;
+  tfile_ops.to_get_tracepoint_status = tfile_get_tracepoint_status;
   tfile_ops.to_trace_find = tfile_trace_find;
-  tfile_ops.to_get_trace_state_variable_value = tfile_get_trace_state_variable_value;
-  /* core_stratum might seem more logical, but GDB doesn't like having
-     more than one core_stratum vector.  */
+  tfile_ops.to_get_trace_state_variable_value
+    = tfile_get_trace_state_variable_value;
   tfile_ops.to_stratum = process_stratum;
   tfile_ops.to_has_all_memory = tfile_has_all_memory;
   tfile_ops.to_has_memory = tfile_has_memory;
   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;
 }
 
+void
+free_current_marker (void *arg)
+{
+  struct static_tracepoint_marker **marker_p = arg;
+
+  if (*marker_p != NULL)
+    {
+      release_static_tracepoint_marker (*marker_p);
+      xfree (*marker_p);
+    }
+  else
+    *marker_p = NULL;
+}
+
+/* Given a line of text defining a static tracepoint marker, parse it
+   into a "static tracepoint marker" object.  Throws an error is
+   parsing fails.  If PP is non-null, it points to one past the end of
+   the parsed marker definition.  */
+
+void
+parse_static_tracepoint_marker_definition (char *line, char **pp,
+                                          struct static_tracepoint_marker *marker)
+{
+  char *p, *endp;
+  ULONGEST addr;
+  int end;
+
+  p = line;
+  p = unpack_varlen_hex (p, &addr);
+  p++;  /* skip a colon */
+
+  marker->gdbarch = target_gdbarch;
+  marker->address = (CORE_ADDR) addr;
+
+  endp = strchr (p, ':');
+  if (endp == NULL)
+    error (_("bad marker definition: %s"), line);
+
+  marker->str_id = xmalloc (endp - p + 1);
+  end = hex2bin (p, (gdb_byte *) marker->str_id, (endp - p + 1) / 2);
+  marker->str_id[end] = '\0';
+
+  p += 2 * end;
+  p++;  /* skip a colon */
+
+  marker->extra = xmalloc (strlen (p) + 1);
+  end = hex2bin (p, (gdb_byte *) marker->extra, strlen (p) / 2);
+  marker->extra[end] = '\0';
+
+  if (pp)
+    *pp = p;
+}
+
+/* Release a static tracepoint marker's contents.  Note that the
+   object itself isn't released here.  There objects are usually on
+   the stack.  */
+
+void
+release_static_tracepoint_marker (struct static_tracepoint_marker *marker)
+{
+  xfree (marker->str_id);
+  marker->str_id = NULL;
+}
+
+/* Print MARKER to gdb_stdout.  */
+
+static void
+print_one_static_tracepoint_marker (int count,
+                                   struct static_tracepoint_marker *marker)
+{
+  struct command_line *l;
+  struct symbol *sym;
+
+  char wrap_indent[80];
+  char extra_field_indent[80];
+  struct ui_out *uiout = current_uiout;
+  struct cleanup *bkpt_chain;
+  VEC(breakpoint_p) *tracepoints;
+
+  struct symtab_and_line sal;
+
+  init_sal (&sal);
+
+  sal.pc = marker->address;
+
+  tracepoints = static_tracepoints_here (marker->address);
+
+  bkpt_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "marker");
+
+  /* A counter field to help readability.  This is not a stable
+     identifier!  */
+  ui_out_field_int (uiout, "count", count);
+
+  ui_out_field_string (uiout, "marker-id", marker->str_id);
+
+  ui_out_field_fmt (uiout, "enabled", "%c",
+                   !VEC_empty (breakpoint_p, tracepoints) ? 'y' : 'n');
+  ui_out_spaces (uiout, 2);
+
+  strcpy (wrap_indent, "                                   ");
+
+  if (gdbarch_addr_bit (marker->gdbarch) <= 32)
+    strcat (wrap_indent, "           ");
+  else
+    strcat (wrap_indent, "                   ");
+
+  strcpy (extra_field_indent, "         ");
+
+  ui_out_field_core_addr (uiout, "addr", marker->gdbarch, marker->address);
+
+  sal = find_pc_line (marker->address, 0);
+  sym = find_pc_sect_function (marker->address, NULL);
+  if (sym)
+    {
+      ui_out_text (uiout, "in ");
+      ui_out_field_string (uiout, "func",
+                          SYMBOL_PRINT_NAME (sym));
+      ui_out_wrap_hint (uiout, wrap_indent);
+      ui_out_text (uiout, " at ");
+    }
+  else
+    ui_out_field_skip (uiout, "func");
+
+  if (sal.symtab != NULL)
+    {
+      ui_out_field_string (uiout, "file", sal.symtab->filename);
+      ui_out_text (uiout, ":");
+
+      if (ui_out_is_mi_like_p (uiout))
+       {
+         char *fullname = symtab_to_fullname (sal.symtab);
+
+         if (fullname)
+           ui_out_field_string (uiout, "fullname", fullname);
+       }
+      else
+       ui_out_field_skip (uiout, "fullname");
+
+      ui_out_field_int (uiout, "line", sal.line);
+    }
+  else
+    {
+      ui_out_field_skip (uiout, "fullname");
+      ui_out_field_skip (uiout, "line");
+    }
+
+  ui_out_text (uiout, "\n");
+  ui_out_text (uiout, extra_field_indent);
+  ui_out_text (uiout, _("Data: \""));
+  ui_out_field_string (uiout, "extra-data", marker->extra);
+  ui_out_text (uiout, "\"\n");
+
+  if (!VEC_empty (breakpoint_p, tracepoints))
+    {
+      struct cleanup *cleanup_chain;
+      int ix;
+      struct breakpoint *b;
+
+      cleanup_chain = make_cleanup_ui_out_tuple_begin_end (uiout,
+                                                          "tracepoints-at");
+
+      ui_out_text (uiout, extra_field_indent);
+      ui_out_text (uiout, _("Probed by static tracepoints: "));
+      for (ix = 0; VEC_iterate(breakpoint_p, tracepoints, ix, b); ix++)
+       {
+         if (ix > 0)
+           ui_out_text (uiout, ", ");
+         ui_out_text (uiout, "#");
+         ui_out_field_int (uiout, "tracepoint-id", b->number);
+       }
+
+      do_cleanups (cleanup_chain);
+
+      if (ui_out_is_mi_like_p (uiout))
+       ui_out_field_int (uiout, "number-of-tracepoints",
+                         VEC_length(breakpoint_p, tracepoints));
+      else
+       ui_out_text (uiout, "\n");
+    }
+  VEC_free (breakpoint_p, tracepoints);
+
+  do_cleanups (bkpt_chain);
+}
+
+static void
+info_static_tracepoint_markers_command (char *arg, int from_tty)
+{
+  VEC(static_tracepoint_marker_p) *markers;
+  struct cleanup *old_chain;
+  struct static_tracepoint_marker *marker;
+  struct ui_out *uiout = current_uiout;
+  int i;
+
+  /* We don't have to check target_can_use_agent and agent's capability on
+     static tracepoint here, in order to be compatible with older GDBserver.
+     We don't check USE_AGENT is true or not, because static tracepoints
+     don't work without in-process agent, so we don't bother users to type
+     `set agent on' when to use static tracepoint.  */
+
+  old_chain
+    = make_cleanup_ui_out_table_begin_end (uiout, 5, -1,
+                                          "StaticTracepointMarkersTable");
+
+  ui_out_table_header (uiout, 7, ui_left, "counter", "Cnt");
+
+  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)
+    ui_out_table_header (uiout, 10, ui_left, "addr", "Address");
+  else
+    ui_out_table_header (uiout, 18, ui_left, "addr", "Address");
+  ui_out_table_header (uiout, 40, ui_noalign, "what", "What");
+
+  ui_out_table_body (uiout);
+
+  markers = target_static_tracepoint_markers_by_strid (NULL);
+  make_cleanup (VEC_cleanup (static_tracepoint_marker_p), &markers);
+
+  for (i = 0;
+       VEC_iterate (static_tracepoint_marker_p,
+                   markers, i, marker);
+       i++)
+    {
+      print_one_static_tracepoint_marker (i + 1, marker);
+      release_static_tracepoint_marker (marker);
+    }
+
+  do_cleanups (old_chain);
+}
+
+/* The $_sdata convenience variable is a bit special.  We don't know
+   for sure type of the value until we actually have a chance to fetch
+   the data --- the size of the object depends on what has been
+   collected.  We solve this by making $_sdata be an internalvar that
+   creates a new value on access.  */
+
+/* Return a new value with the correct type for the sdata object of
+   the current trace frame.  Return a void value if there's no object
+   available.  */
+
+static struct value *
+sdata_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+                 void *ignore)
+{
+  LONGEST size;
+  gdb_byte *buf;
+
+  /* We need to read the whole object before we know its size.  */
+  size = target_read_alloc (&current_target,
+                           TARGET_OBJECT_STATIC_TRACE_DATA,
+                           NULL, &buf);
+  if (size >= 0)
+    {
+      struct value *v;
+      struct type *type;
+
+      type = init_vector_type (builtin_type (gdbarch)->builtin_true_char,
+                              size);
+      v = allocate_value (type);
+      memcpy (value_contents_raw (v), buf, size);
+      xfree (buf);
+      return v;
+    }
+  else
+    return allocate_value (builtin_type (gdbarch)->builtin_void);
+}
+
+#if !defined(HAVE_LIBEXPAT)
+
+struct traceframe_info *
+parse_traceframe_info (const char *tframe_info)
+{
+  static int have_warned;
+
+  if (!have_warned)
+    {
+      have_warned = 1;
+      warning (_("Can not parse XML trace frame info; XML support "
+                "was disabled at compile time"));
+    }
+
+  return NULL;
+}
+
+#else /* HAVE_LIBEXPAT */
+
+#include "xml-support.h"
+
+/* Handle the start of a <memory> element.  */
+
+static void
+traceframe_info_start_memory (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;
+  struct mem_range *r = VEC_safe_push (mem_range_s, info->memory, NULL);
+  ULONGEST *start_p, *length_p;
+
+  start_p = xml_find_attribute (attributes, "start")->value;
+  length_p = xml_find_attribute (attributes, "length")->value;
+
+  r->start = *start_p;
+  r->length = *length_p;
+}
+
+/* Discard the constructed trace frame info (if an error occurs).  */
+
+static void
+free_result (void *p)
+{
+  struct traceframe_info *result = p;
+
+  free_traceframe_info (result);
+}
+
+/* The allowed elements and attributes for an XML memory map.  */
+
+static const struct gdb_xml_attribute memory_attributes[] = {
+  { "start", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { "length", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, 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 },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element traceframe_info_elements[] = {
+  { "traceframe-info", NULL, traceframe_info_children, GDB_XML_EF_NONE,
+    NULL, NULL },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+/* Parse a traceframe-info XML document.  */
+
+struct traceframe_info *
+parse_traceframe_info (const char *tframe_info)
+{
+  struct traceframe_info *result;
+  struct cleanup *back_to;
+
+  result = XCNEW (struct traceframe_info);
+  back_to = make_cleanup (free_result, result);
+
+  if (gdb_xml_parse_quick (_("trace frame info"),
+                          "traceframe-info.dtd", traceframe_info_elements,
+                          tframe_info, result) == 0)
+    {
+      /* Parsed successfully, keep the result.  */
+      discard_cleanups (back_to);
+
+      return result;
+    }
+
+  do_cleanups (back_to);
+  return NULL;
+}
+
+#endif /* HAVE_LIBEXPAT */
+
+/* Returns the traceframe_info object for the current traceframe.
+   This is where we avoid re-fetching the object from the target if we
+   already have it cached.  */
+
+static struct traceframe_info *
+get_traceframe_info (void)
+{
+  if (traceframe_info == NULL)
+    traceframe_info = target_traceframe_info ();
+
+  return traceframe_info;
+}
+
+/* If the target supports the query, return in RESULT the set of
+   collected memory in the current traceframe, found within the LEN
+   bytes range starting at MEMADDR.  Returns true if the target
+   supports the query, otherwise returns false, and RESULT is left
+   undefined.  */
+
+int
+traceframe_available_memory (VEC(mem_range_s) **result,
+                            CORE_ADDR memaddr, ULONGEST len)
+{
+  struct traceframe_info *info = get_traceframe_info ();
+
+  if (info != NULL)
+    {
+      struct mem_range *r;
+      int i;
+
+      *result = NULL;
+
+      for (i = 0; VEC_iterate (mem_range_s, info->memory, i, r); i++)
+       if (mem_ranges_overlap (r->start, r->length, memaddr, len))
+         {
+           ULONGEST lo1, hi1, lo2, hi2;
+           struct mem_range *nr;
+
+           lo1 = memaddr;
+           hi1 = memaddr + len;
+
+           lo2 = r->start;
+           hi2 = r->start + r->length;
+
+           nr = VEC_safe_push (mem_range_s, *result, NULL);
+
+           nr->start = max (lo1, lo2);
+           nr->length = min (hi1, hi2) - nr->start;
+         }
+
+      normalize_mem_ranges (*result);
+      return 1;
+    }
+
+  return 0;
+}
+
+/* Implementation of `sdata' variable.  */
+
+static const struct internalvar_funcs sdata_funcs =
+{
+  sdata_make_value,
+  NULL,
+  NULL
+};
+
 /* module initialization */
 void
 _initialize_tracepoint (void)
 {
   struct cmd_list_element *c;
 
+  /* Explicitly create without lookup, since that tries to create a
+     value with a void typed value, and when we get here, gdbarch
+     isn't initialized yet.  At this point, we're quite sure there
+     isn't another convenience variable of the same name.  */
+  create_internalvar_type_lazy ("_sdata", &sdata_funcs, NULL);
+
   traceframe_number = -1;
   tracepoint_number = -1;
 
@@ -4134,10 +5231,15 @@ at the start of tracing."));
 Delete one or more trace state variables.\n\
 Arguments are the names of the variables to delete.\n\
 If no arguments are supplied, delete all variables."), &deletelist);
-  /* FIXME add a trace variable completer */
+  /* FIXME add a trace variable completer */
 
   add_info ("tvariables", tvariables_info, _("\
 Status of trace state variables and their values.\n\
+"));
+
+  add_info ("static-tracepoint-markers",
+           info_static_tracepoint_markers_command, _("\
+List target static tracepoints markers.\n\
 "));
 
   add_prefix_cmd ("tfind", class_trace, trace_find_command, _("\
@@ -4157,7 +5259,7 @@ Usage: tfind range addr1,addr2"),
 
   add_cmd ("line", class_trace, trace_find_line_command, _("\
 Select a trace frame by source line.\n\
-Argument can be a line number (with optional source file), \n\
+Argument can be a line number (with optional source file),\n\
 a function name, or '*' followed by an address.\n\
 Default argument is 'the next source line that was traced'."),
           &tfindlist);
@@ -4188,11 +5290,17 @@ De-select any trace frame and resume 'live' debugging."),
   add_com ("tstatus", class_trace, trace_status_command,
           _("Display the status of the current trace data collection."));
 
-  add_com ("tstop", class_trace, trace_stop_command,
-          _("Stop trace data collection."));
+  add_com ("tstop", class_trace, trace_stop_command, _("\
+Stop trace data collection.\n\
+Usage: tstop [ <notes> ... ]\n\
+Any arguments supplied are recorded with the trace as a stop reason and\n\
+reported by tstatus (if the target supports trace notes)."));
 
-  add_com ("tstart", class_trace, trace_start_command,
-          _("Start trace data collection."));
+  add_com ("tstart", class_trace, trace_start_command, _("\
+Start trace data collection.\n\
+Usage: tstart [ <notes> ... ]\n\
+Any arguments supplied are recorded with the trace as a note and\n\
+reported by tstatus (if the target supports trace notes)."));
 
   add_com ("end", class_trace, end_actions_pseudocommand, _("\
 Ends a list of commands or actions.\n\
@@ -4220,6 +5328,7 @@ Also accepts the following special arguments:\n\
     $regs   -- all registers.\n\
     $args   -- all function arguments.\n\
     $locals -- all variables local to the block/function scope.\n\
+    $_sdata -- static tracepoint data (ignored for non-static tracepoints).\n\
 Note: this command can only be used in a tracepoint \"actions\" list."));
 
   add_com ("teval", class_trace, teval_pseudocommand, _("\
@@ -4230,8 +5339,8 @@ Note: this command can only be used in a tracepoint \"actions\" list."));
 
   add_com ("actions", class_trace, trace_actions_command, _("\
 Specify the actions to be taken at a tracepoint.\n\
-Tracepoint actions may include collecting of specified data, \n\
-single-stepping, or enabling/disabling other tracepoints, \n\
+Tracepoint actions may include collecting of specified data,\n\
+single-stepping, or enabling/disabling other tracepoints,\n\
 depending on target's capabilities."));
 
   default_collect = xstrdup ("");
@@ -4266,6 +5375,27 @@ up and stopping the trace run."),
                           &setlist,
                           &showlist);
 
+  add_setshow_string_cmd ("trace-user", class_trace,
+                         &trace_user, _("\
+Set the user name to use for current and future trace runs"), _("\
+Show the user name to use for current and future trace runs"), NULL,
+                         set_trace_user, NULL,
+                         &setlist, &showlist);
+
+  add_setshow_string_cmd ("trace-notes", class_trace,
+                         &trace_notes, _("\
+Set notes string to use for current and future trace runs"), _("\
+Show the notes string to use for current and future trace runs"), NULL,
+                         set_trace_notes, NULL,
+                         &setlist, &showlist);
+
+  add_setshow_string_cmd ("trace-stop-notes", class_trace,
+                         &trace_stop_notes, _("\
+Set notes string to use for future tstop commands"), _("\
+Show the notes string to use for future tstop commands"), NULL,
+                         set_trace_stop_notes, NULL,
+                         &setlist, &showlist);
+
   init_tfile_ops ();
 
   add_target (&tfile_ops);
This page took 0.079519 seconds and 4 git commands to generate.