* NEWS: Mention tracepoint additions.
authorStan Shebs <shebs@codesourcery.com>
Sun, 20 Nov 2011 23:59:49 +0000 (23:59 +0000)
committerStan Shebs <shebs@codesourcery.com>
Sun, 20 Nov 2011 23:59:49 +0000 (23:59 +0000)
* breakpoint.h (struct tracepoint): New field traceframe_usage.
* breakpoint.c (print_one_breakpoint_location): Identify
tracepoints as such when reporting hit counts, report
trace buffer usage.
(create_tracepoint_from_upload): Copy status info.
* tracepoint.h (struct trace_status): Rename error_desc to stop_desc,
add fields user_name, notes, start_time, stop_time.
(struct uploaded_tp): Add fields hit_count, traceframe_usage.
* tracepoint.c (trace_user): New global.
(trace_notes): New global.
(trace_stop_notes): New global.
(start_tracing): Add argument and trace note handling.
(stop_tracing): Ditto.
(trace_start_command): Add notes argument.
(trace_stop_command): Ditto.
(trace_status_command): Report additional status info.
(trace_status_mi): Similarly.
(trace_save): Update, record tracepoint status.
(set_disconnected_tracing): Call target method directly.
(send_disconnected_tracing_value): Remove.
(set_trace_user): New function.
(set_trace_notes): New function.
(set_trace_stop_notes): New function.
(parse_trace_status): Handle additional status.
(parse_tracepoint_status): New function.
(parse_tracepoint_definition): Call it.
(tfile_get_tracepoint_status): New function.
(init_tfile_ops): Use it.
(_initialize_tracepoint): Add new setshows.
* target.h (struct target_ops): New methods to_get_tracepoint_status
and to_set_trace_notes.
(target_get_tracepoint_status): New macro.
(target_set_trace_notes): New macro.
* target.c (update_current_target): Add new methods.
* remote.c (remote_get_tracepoint_status): New function.
(remote_set_trace_notes): New function.
(init_remote_ops): Add them.
* mi/mi-main.c (mi_cmd_trace_start): Add argument to call.
(mi_cmd_trace_stop): Ditto.

* tracepoint.c (struct tracepoint): New field traceframe_usage.
(tracing_start_time): New global.
(tracing_stop_time): New global.
(tracing_user_name): New global.
(tracing_notes): New global.
(tracing_stop_note): New global.
(cmd_qtstart): Set traceframe_usage, start_time.
(stop_tracing): Set stop_time.
(cmd_qtstatus): Report additional status.
(cmd_qtp): New function.
(handle_tracepoint_query): Call it.
(cmd_qtnotes): New function.
(handle_tracepoint_general_set): Call it.
(get_timestamp): Rename from tsv_get_timestamp.

* gdb.texinfo (Starting and Stopping Trace Experiments): Document
note-related options and variables.
(Tracepoint Packets): Document packet changes.

* gdb.trace/tstatus.exp: New.
* gdb.trace/actions.c: Include string.h.

18 files changed:
gdb/ChangeLog
gdb/NEWS
gdb/breakpoint.c
gdb/breakpoint.h
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/gdbserver/ChangeLog
gdb/gdbserver/tracepoint.c
gdb/mi/mi-main.c
gdb/remote.c
gdb/target.c
gdb/target.h
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.trace/actions.c
gdb/testsuite/gdb.trace/tstatus.exp [new file with mode: 0644]
gdb/testsuite/lib/gdbserver-support.exp
gdb/tracepoint.c
gdb/tracepoint.h

index 4004235..cda1411 100644 (file)
@@ -1,3 +1,46 @@
+2011-11-20  Stan Shebs  <stan@codesourcery.com>
+
+       * NEWS: Mention tracepoint additions.
+       * breakpoint.h (struct tracepoint): New field traceframe_usage.
+       * breakpoint.c (print_one_breakpoint_location): Identify
+       tracepoints as such when reporting hit counts, report
+       trace buffer usage.
+       (create_tracepoint_from_upload): Copy status info.
+       * tracepoint.h (struct trace_status): Rename error_desc to stop_desc,
+       add fields user_name, notes, start_time, stop_time.
+       (struct uploaded_tp): Add fields hit_count, traceframe_usage.
+       * tracepoint.c (trace_user): New global.
+       (trace_notes): New global.
+       (trace_stop_notes): New global.
+       (start_tracing): Add argument and trace note handling.
+       (stop_tracing): Ditto.
+       (trace_start_command): Add notes argument.
+       (trace_stop_command): Ditto.
+       (trace_status_command): Report additional status info.
+       (trace_status_mi): Similarly.
+       (trace_save): Update, record tracepoint status.
+       (set_disconnected_tracing): Call target method directly.
+       (send_disconnected_tracing_value): Remove.
+       (set_trace_user): New function.
+       (set_trace_notes): New function.
+       (set_trace_stop_notes): New function.
+       (parse_trace_status): Handle additional status.
+       (parse_tracepoint_status): New function.
+       (parse_tracepoint_definition): Call it.
+       (tfile_get_tracepoint_status): New function.
+       (init_tfile_ops): Use it.
+       (_initialize_tracepoint): Add new setshows.
+       * target.h (struct target_ops): New methods to_get_tracepoint_status
+       and to_set_trace_notes.
+       (target_get_tracepoint_status): New macro.
+       (target_set_trace_notes): New macro.
+       * target.c (update_current_target): Add new methods.
+       * remote.c (remote_get_tracepoint_status): New function.
+       (remote_set_trace_notes): New function.
+       (init_remote_ops): Add them.
+       * mi/mi-main.c (mi_cmd_trace_start): Add argument to call.
+       (mi_cmd_trace_stop): Ditto.
+
 2011-11-20  Sanjoy Das  <sdas@igalia.com>
 
        * jit.c: Include regcache.h.
index c4e59c4..93a799b 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -133,6 +133,17 @@ collect[/s] EXPRESSIONS
   string.  An optional integer following the "/s" sets a bound on the
   number of bytes that will be collected.
 
+tstart [NOTES]
+  The trace start command now interprets any supplied arguments as a
+  note to be recorded with the trace run, with an effect similar to
+  setting the variable trace-notes.
+
+tstop [NOTES]
+  The trace stop command now interprets any arguments as a note to be
+  mentioned along with the tstatus report that the trace was stopped
+  with a command.  The effect is similar to setting the variable
+  trace-stop-notes.
+
 * Tracepoints can now be enabled and disabled at any time after a trace
   experiment has been started using the standard "enable" and "disable"
   commands.  It is now possible to start a trace experiment with no enabled
@@ -176,6 +187,22 @@ show basenames-may-differ
   If not set (the default), all source files are assumed to have just
   one base name, and gdb will do file name comparisons more efficiently.
 
+set trace-user
+show trace-user
+set trace-notes
+show trace-notes
+  Set a user name and notes for the current and any future trace runs.
+  This is useful for long-running and/or disconnected traces, to
+  inform others (or yourself) as to who is running the trace, supply
+  contact information, or otherwise explain what is going on.
+
+set trace-stop-notes
+show trace-stop-notes
+  Set a note attached to the trace run, that is displayed when the
+  trace has been stopped by a tstop command.  This is useful for
+  instance as an explanation, if you are stopping a trace run that was
+  started by someone else.
+
 * New remote packets
 
 QTEnable
@@ -186,6 +213,14 @@ QTDisable
 
   Dynamically disable a tracepoint in a started trace experiment.
 
+QTNotes
+
+  Set the user and notes of the trace run.
+
+qTP
+
+  Query the current status of a tracepoint.
+
 qTMinFTPILen
 
   Query the minimum length of instruction at which a fast tracepoint may
index dc891c0..ab0d402 100644 (file)
@@ -4879,6 +4879,8 @@ print_one_breakpoint_location (struct breakpoint *b,
       /* FIXME should make an annotation for this.  */
       if (ep_is_catchpoint (b))
        ui_out_text (uiout, "\tcatchpoint");
+      else if (is_tracepoint (b))
+       ui_out_text (uiout, "\ttracepoint");
       else
        ui_out_text (uiout, "\tbreakpoint");
       ui_out_text (uiout, " already hit ");
@@ -4903,6 +4905,18 @@ print_one_breakpoint_location (struct breakpoint *b,
       ui_out_text (uiout, " hits\n");
     }
 
+  if (!part_of_multiple && is_tracepoint (b))
+    {
+      struct tracepoint *tp = (struct tracepoint *) b;
+
+      if (tp->traceframe_usage)
+       {
+         ui_out_text (uiout, "\ttrace buffer usage ");
+         ui_out_field_int (uiout, "traceframe-usage", tp->traceframe_usage);
+         ui_out_text (uiout, " bytes\n");
+       }
+    }
+  
   l = b->commands ? b->commands->commands : NULL;
   if (!part_of_multiple && l)
     {
@@ -12904,6 +12918,10 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
               "have no source form, ignoring them"),
             utp->number);
 
+  /* Copy any status information that might be available.  */
+  tp->base.hit_count = utp->hit_count;
+  tp->traceframe_usage = utp->traceframe_usage;
+
   return tp;
 }
   
index 8e03264..96cc96a 100644 (file)
@@ -710,6 +710,10 @@ struct tracepoint
   /* The number of the tracepoint on the target.  */
   int number_on_target;
 
+  /* The total space taken by all the trace frames for this
+     tracepoint.  */
+  ULONGEST traceframe_usage;
+
   /* The static tracepoint marker id, if known.  */
   char *static_trace_marker_id;
 
index f915110..4b3a99f 100644 (file)
@@ -1,3 +1,9 @@
+2011-11-20  Stan Shebs  <stan@codesourcery.com>
+
+       * gdb.texinfo (Starting and Stopping Trace Experiments): Document
+       note-related options and variables.
+       (Tracepoint Packets): Document packet changes.
+
 2011-11-20  Sanjoy Das  <sdas@igalia.com>
 
        * gdb.texinfo (JIT Interface): Add documentation on writing and
index 13e01bc..f4f68a3 100644 (file)
@@ -10902,20 +10902,27 @@ Cnt ID         Enb Address            What
 @subsection Starting and Stopping Trace Experiments
 
 @table @code
-@kindex tstart
+@kindex tstart [ @var{notes} ]
 @cindex start a new trace experiment
 @cindex collected data discarded
 @item tstart
-This command takes no arguments.  It starts the trace experiment, and
-begins collecting data.  This has the side effect of discarding all
-the data collected in the trace buffer during the previous trace
-experiment.
-
-@kindex tstop
+This command starts the trace experiment, and begins collecting data.
+It has the side effect of discarding all the data collected in the
+trace buffer during the previous trace experiment.  If any arguments
+are supplied, they are taken as a note and stored with the trace
+experiment's state.  The notes may be arbitrary text, and are
+especially useful with disconnected tracing in a multi-user context;
+the notes can explain what the trace is doing, supply user contact
+information, and so forth.
+
+@kindex tstop [ @var{notes} ]
 @cindex stop a running trace experiment
 @item tstop
-This command takes no arguments.  It ends the trace experiment, and
-stops collecting data.
+This command stops the trace experiment.  If any arguments are
+supplied, they are recorded with the experiment as a note.  This is
+useful if you are stopping a trace started by someone else, for
+instance if the trace is interfering with the system's behavior and
+needs to be stopped quickly.
 
 @strong{Note}: a trace experiment and data collection may stop
 automatically if any tracepoint's passcount is reached
@@ -11019,6 +11026,33 @@ for instance if you are looking at frames from a trace file.
 
 @end table
 
+@table @code
+@item set trace-user @var{text}
+@kindex set trace-user
+
+@item show trace-user
+@kindex show trace-user
+
+@item set trace-notes @var{text}
+@kindex set trace-notes
+Set the trace run's notes.
+
+@item show trace-notes
+@kindex show trace-notes
+Show the trace run's notes.
+
+@item set trace-stop-notes @var{text}
+@kindex set trace-stop-notes
+Set the trace run's stop notes.  The handling of the note is as for
+@code{tstop} arguments; the set command is convenient way to fix a
+stop note that is mistaken or incomplete.
+
+@item show trace-stop-notes
+@kindex show trace-stop-notes
+Show the trace run's stop notes.
+
+@end table
+
 @node Tracepoint Restrictions
 @subsection Tracepoint Restrictions
 
@@ -35115,6 +35149,8 @@ the command by a @samp{,}, not a @samp{:}, contrary to the naming
 conventions above.  Please don't use this packet as a model for new
 packets.)
 
+@item QTNotes
+@item qTP
 @item QTSave
 @item qTsP
 @item qTsV
@@ -35697,8 +35733,11 @@ explanations as one of the optional fields:
 @item tnotrun:0
 No trace has been run yet.
 
-@item tstop:0
-The trace was stopped by a user-originated stop command.
+@item tstop[:@var{text}]:0
+The trace was stopped by a user-originated stop command.  The optional
+@var{text} field is a user-supplied string supplied as part of the
+stop command (for instance, an explanation of why the trace was
+stopped manually).  It is hex-encoded.
 
 @item tfull:0
 The trace stopped because the trace buffer filled up.
@@ -35754,6 +35793,22 @@ that the trace run will stop.
 
 @end table
 
+@item qTP:@var{tp}:@var{addr}
+@cindex tracepoint status, remote request
+@cindex @samp{qTP} packet
+Ask the stub for the current state of tracepoint number @var{tp} at
+address @var{addr}.
+
+Replies:
+@table @samp
+@item V@var{hits}:@var{usage}
+The tracepoint has been hit @var{hits} times so far during the trace
+run, and accounts for @var{usage} in the trace buffer.  Note that
+@code{while-stepping} steps are not counted as separate hits, but the
+steps' space consumption is added into the usage number.
+
+@end table
+
 @item qTV:@var{var}
 @cindex trace state variable value, remote request
 @cindex @samp{qTV} packet
@@ -35847,6 +35902,11 @@ available.
 This packet directs the target to use a circular trace buffer if
 @var{value} is 1, or a linear buffer if the value is 0.
 
+@item QTNotes:@r{[}@var{type}:@var{text}@r{]}@r{[};@var{type}:@var{text}@r{]}@dots{}
+This packet adds optional textual notes to the trace run.  Allowable
+types include @code{user}, @code{notes}, and @code{tstop}, the
+@var{text} fields are arbitrary strings, hex-encoded.
+
 @end table
 
 @subsection Relocate instruction reply packet
index 844fb18..c556eeb 100644 (file)
@@ -1,3 +1,20 @@
+2011-11-17  Stan Shebs  <stan@codesourcery.com>
+
+       * tracepoint.c (struct tracepoint): New field traceframe_usage.
+       (tracing_start_time): New global.
+       (tracing_stop_time): New global.
+       (tracing_user_name): New global.
+       (tracing_notes): New global.
+       (tracing_stop_note): New global.
+       (cmd_qtstart): Set traceframe_usage, start_time.
+       (stop_tracing): Set stop_time.
+       (cmd_qtstatus): Report additional status.
+       (cmd_qtp): New function.
+       (handle_tracepoint_query): Call it.
+       (cmd_qtnotes): New function.
+       (handle_tracepoint_general_set): Call it.
+       (get_timestamp): Rename from tsv_get_timestamp.
+
 2011-11-14  Stan Shebs  <stan@codesourcery.com>
            Kwok Cheung Yeung  <kcy@codesourcery.com>
 
index b00df05..e6a5bbc 100644 (file)
@@ -632,6 +632,9 @@ struct tracepoint
      Note that while-stepping steps are not counted as "hits".  */
   long hit_count;
 
+  /* Cached sum of the sizes of traceframes created by this point.  */
+  long traceframe_usage;
+
   CORE_ADDR compiled_cond;
 
   /* Link to the next tracepoint in the list.  */
@@ -1144,6 +1147,27 @@ static const char *tracing_stop_reason = "tnotrun";
 
 static int tracing_stop_tpnum;
 
+/* 64-bit timestamps for the trace run's start and finish, expressed
+   in microseconds from the Unix epoch.  */
+
+LONGEST tracing_start_time;
+LONGEST tracing_stop_time;
+
+/* The (optional) user-supplied name of the user that started the run.
+   This is an arbitrary string, and may be NULL.  */
+
+char *tracing_user_name;
+
+/* Optional user-supplied text describing the run.  This is
+   an arbitrary string, and may be NULL.  */
+
+char *tracing_notes;
+
+/* Optional user-supplied text explaining a tstop command.  This is an
+   arbitrary string, and may be NULL.  */
+
+char *tracing_stop_note;
+
 #endif
 
 /* Functions local to this file.  */
@@ -1266,6 +1290,8 @@ static void download_tracepoint (struct tracepoint *);
 static int install_fast_tracepoint (struct tracepoint *, char *errbuf);
 #endif
 
+static LONGEST get_timestamp (void);
+
 #if defined(__GNUC__)
 #  define memory_barrier() asm volatile ("" : : : "memory")
 #else
@@ -3027,6 +3053,7 @@ cmd_qtstart (char *packet)
     {
       /* Ensure all the hit counts start at zero.  */
       tpoint->hit_count = 0;
+      tpoint->traceframe_usage = 0;
 
       if (tpoint->type == trap_tracepoint)
        {
@@ -3103,6 +3130,7 @@ cmd_qtstart (char *packet)
   trace_buffer_is_full = 0;
   expr_eval_result = expr_eval_no_error;
   error_tracepoint = NULL;
+  tracing_start_time = get_timestamp ();
 
   /* Tracing is now active, hits will now start being logged.  */
   tracing = 1;
@@ -3172,6 +3200,7 @@ stop_tracing (void)
        fatal ("Error clearing tracing variable in lib");
     }
 
+  tracing_stop_time = get_timestamp ();
   tracing_stop_reason = "t???";
   tracing_stop_tpnum = 0;
   if (stopping_tracepoint)
@@ -3352,6 +3381,26 @@ static void
 cmd_qtstatus (char *packet)
 {
   char *stop_reason_rsp = NULL;
+  char *buf1, *buf2, *buf3, *str;
+  int slen;
+
+  /* Translate the plain text of the notes back into hex for
+     transmission.  */
+
+  str = (tracing_user_name ? tracing_user_name : "");
+  slen = strlen (str);
+  buf1 = (char *) alloca (slen * 2 + 1);
+  hexify (buf1, str, slen);
+
+  str = (tracing_notes ? tracing_notes : "");
+  slen = strlen (str);
+  buf2 = (char *) alloca (slen * 2 + 1);
+  hexify (buf2, str, slen);
+
+  str = (tracing_stop_note ? tracing_stop_note : "");
+  slen = strlen (str);
+  buf3 = (char *) alloca (slen * 2 + 1);
+  hexify (buf3, str, slen);
 
   trace_debug ("Returning trace status as %d, stop reason %s",
               tracing, tracing_stop_reason);
@@ -3368,7 +3417,7 @@ cmd_qtstatus (char *packet)
   stop_reason_rsp = (char *) tracing_stop_reason;
 
   /* The user visible error string in terror needs to be hex encoded.
-     We leave it as plain string in `tracepoint_stop_reason' to ease
+     We leave it as plain string in `tracing_stop_reason' to ease
      debugging.  */
   if (strncmp (stop_reason_rsp, "terror:", strlen ("terror:")) == 0)
     {
@@ -3384,19 +3433,58 @@ cmd_qtstatus (char *packet)
       convert_int_to_ascii ((gdb_byte *) result_name, p, strlen (result_name));
     }
 
+  /* If this was a forced stop, include any stop note that was supplied.  */
+  if (strcmp (stop_reason_rsp, "tstop") == 0)
+    {
+      stop_reason_rsp = alloca (strlen ("tstop:") + strlen (buf3) + 1);
+      strcpy (stop_reason_rsp, "tstop:");
+      strcat (stop_reason_rsp, buf3);
+    }
+
   sprintf (packet,
           "T%d;"
           "%s:%x;"
           "tframes:%x;tcreated:%x;"
           "tfree:%x;tsize:%s;"
           "circular:%d;"
-          "disconn:%d",
+          "disconn:%d;"
+          "starttime:%llx;stoptime:%llx;"
+          "username:%s:;notes:%s:",
           tracing ? 1 : 0,
           stop_reason_rsp, tracing_stop_tpnum,
           traceframe_count, traceframes_created,
           free_space (), phex_nz (trace_buffer_hi - trace_buffer_lo, 0),
           circular_trace_buffer,
-          disconnected_tracing);
+          disconnected_tracing,
+          tracing_start_time, tracing_stop_time,
+          buf1, buf2);
+}
+
+static void
+cmd_qtp (char *own_buf)
+{
+  ULONGEST num, addr;
+  struct tracepoint *tpoint;
+  char *packet = own_buf;
+
+  packet += strlen ("qTP:");
+
+  packet = unpack_varlen_hex (packet, &num);
+  ++packet; /* skip a colon */
+  packet = unpack_varlen_hex (packet, &addr);
+
+  /* See if we already have this tracepoint.  */
+  tpoint = find_tracepoint (num, addr);
+
+  if (!tpoint)
+    {
+      trace_debug ("Tracepoint error: tracepoint %d at 0x%s not found",
+                  (int) num, paddress (addr));
+      write_enn (own_buf);
+      return;
+    }
+
+  sprintf (own_buf, "V%lx:%lx", tpoint->hit_count, tpoint->traceframe_usage);
 }
 
 /* State variables to help return all the tracepoint bits.  */
@@ -3710,6 +3798,63 @@ cmd_bigqtbuffer (char *own_buf)
     write_enn (own_buf);
 }
 
+static void
+cmd_qtnotes (char *own_buf)
+{
+  size_t nbytes;
+  char *saved, *user, *notes, *stopnote;
+  char *packet = own_buf;
+
+  packet += strlen ("QTNotes:");
+
+  while (*packet)
+    {
+      if (strncmp ("user:", packet, strlen ("user:")) == 0)
+       {
+         packet += strlen ("user:");
+         saved = packet;
+         packet = strchr (packet, ';');
+         nbytes = (packet - saved) / 2;
+         user = xmalloc (nbytes + 1);
+         nbytes = unhexify (user, saved, nbytes);
+         user[nbytes] = '\0';
+         ++packet; /* skip the semicolon */
+         trace_debug ("User is '%s'", user);
+         tracing_user_name = user;
+       }
+      else if (strncmp ("notes:", packet, strlen ("notes:")) == 0)
+       {
+         packet += strlen ("notes:");
+         saved = packet;
+         packet = strchr (packet, ';');
+         nbytes = (packet - saved) / 2;
+         notes = xmalloc (nbytes + 1);
+         nbytes = unhexify (notes, saved, nbytes);
+         notes[nbytes] = '\0';
+         ++packet; /* skip the semicolon */
+         trace_debug ("Notes is '%s'", notes);
+         tracing_notes = notes;
+       }
+      else if (strncmp ("tstop:", packet, strlen ("tstop:")) == 0)
+       {
+         packet += strlen ("tstop:");
+         saved = packet;
+         packet = strchr (packet, ';');
+         nbytes = (packet - saved) / 2;
+         stopnote = xmalloc (nbytes + 1);
+         nbytes = unhexify (stopnote, saved, nbytes);
+         stopnote[nbytes] = '\0';
+         ++packet; /* skip the semicolon */
+         trace_debug ("tstop note is '%s'", stopnote);
+         tracing_stop_note = stopnote;
+       }
+      else
+       break;
+    }
+
+  write_ok (own_buf);
+}
+
 int
 handle_tracepoint_general_set (char *packet)
 {
@@ -3774,6 +3919,11 @@ handle_tracepoint_general_set (char *packet)
       cmd_bigqtbuffer (packet);
       return 1;
     }
+  else if (strncmp ("QTNotes:", packet, strlen ("QTNotes:")) == 0)
+    {
+      cmd_qtnotes (packet);
+      return 1;
+    }
 
   return 0;
 }
@@ -3786,6 +3936,11 @@ handle_tracepoint_query (char *packet)
       cmd_qtstatus (packet);
       return 1;
     }
+  else if (strncmp ("qTP:", packet, strlen ("qTP:")) == 0)
+    {
+      cmd_qtp (packet);
+      return 1;
+    }
   else if (strcmp ("qTfP", packet) == 0)
     {
       cmd_qtfp (packet);
@@ -8049,8 +8204,12 @@ initialize_tracepoint_ftlib (void)
 
 #endif /* IN_PROCESS_AGENT */
 
+/* Return a timestamp, expressed as microseconds of the usual Unix
+   time.  (As the result is a 64-bit number, it will not overflow any
+   time soon.)  */
+
 static LONGEST
-tsv_get_timestamp (void)
+get_timestamp (void)
 {
    struct timeval tv;
 
@@ -8074,7 +8233,7 @@ initialize_tracepoint (void)
      variable numbered 1, it will be renumbered.)  */
   create_trace_state_variable (1, 0);
   set_trace_state_variable_name (1, "trace_timestamp");
-  set_trace_state_variable_getter (1, tsv_get_timestamp);
+  set_trace_state_variable_getter (1, get_timestamp);
 
 #ifdef IN_PROCESS_AGENT
   {
index a9c7652..5270fe4 100644 (file)
@@ -2490,7 +2490,7 @@ mi_cmd_trace_save (char *command, char **argv, int argc)
 void
 mi_cmd_trace_start (char *command, char **argv, int argc)
 {
-  start_tracing ();
+  start_tracing (NULL);
 }
 
 void
@@ -2502,7 +2502,7 @@ mi_cmd_trace_status (char *command, char **argv, int argc)
 void
 mi_cmd_trace_stop (char *command, char **argv, int argc)
 {
-  stop_tracing ();
+  stop_tracing (NULL);
   trace_status_mi (1);
 }
 
index 6ac5fc0..8fa5c1a 100644 (file)
@@ -10214,6 +10214,53 @@ remote_get_trace_status (struct trace_status *ts)
   return ts->running;
 }
 
+void
+remote_get_tracepoint_status (struct breakpoint *bp,
+                             struct uploaded_tp *utp)
+{
+  struct remote_state *rs = get_remote_state ();
+  char addrbuf[40];
+  char *reply;
+  struct bp_location *loc;
+  struct tracepoint *tp = (struct tracepoint *) bp;
+
+  if (tp)
+    {
+      tp->base.hit_count = 0;
+      tp->traceframe_usage = 0;
+      for (loc = tp->base.loc; loc; loc = loc->next)
+       {
+         /* If the tracepoint was never downloaded, don't go asking for
+            any status.  */
+         if (tp->number_on_target == 0)
+           continue;
+         sprintf_vma (addrbuf, loc->address);
+         sprintf (rs->buf, "qTP:%x:%s", tp->number_on_target, addrbuf);
+         putpkt (rs->buf);
+         reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
+         if (reply && *reply)
+           {
+             if (*reply == 'V')
+               parse_tracepoint_status (reply + 1, bp, utp);
+           }
+       }
+    }
+  else if (utp)
+    {
+      utp->hit_count = 0;
+      utp->traceframe_usage = 0;
+      sprintf_vma (addrbuf, (long unsigned int) utp->addr);
+      sprintf (rs->buf, "qTP:%x:%s", utp->number, addrbuf);
+      putpkt (rs->buf);
+      reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
+      if (reply && *reply)
+       {
+         if (*reply == 'V')
+           parse_tracepoint_status (reply + 1, bp, utp);
+       }
+    }
+}
+
 static void
 remote_trace_stop (void)
 {
@@ -10485,6 +10532,51 @@ remote_get_min_fast_tracepoint_insn_len (void)
     }
 }
 
+static int
+remote_set_trace_notes (char *user, char *notes, char *stop_notes)
+{
+  struct remote_state *rs = get_remote_state ();
+  char *reply;
+  char *buf = rs->buf;
+  char *endbuf = rs->buf + get_remote_packet_size ();
+  int nbytes;
+
+  buf += xsnprintf (buf, endbuf - buf, "QTNotes:");
+  if (user)
+    {
+      buf += xsnprintf (buf, endbuf - buf, "user:");
+      nbytes = bin2hex (user, buf, 0);
+      buf += 2 * nbytes;
+      *buf++ = ';';
+    }
+  if (notes)
+    {
+      buf += xsnprintf (buf, endbuf - buf, "notes:");
+      nbytes = bin2hex (notes, buf, 0);
+      buf += 2 * nbytes;
+      *buf++ = ';';
+    }
+  if (stop_notes)
+    {
+      buf += xsnprintf (buf, endbuf - buf, "tstop:");
+      nbytes = bin2hex (stop_notes, buf, 0);
+      buf += 2 * nbytes;
+      *buf++ = ';';
+    }
+  /* Ensure the buffer is terminated.  */
+  *buf = '\0';
+
+  putpkt (rs->buf);
+  reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
+  if (*reply == '\0')
+    return 0;
+
+  if (strcmp (reply, "OK") != 0)
+    error (_("Bogus reply from target: %s"), reply);
+
+  return 1;
+}
+
 static void
 init_remote_ops (void)
 {
@@ -10565,6 +10657,7 @@ Specify the serial device it is connected to\n\
   remote_ops.to_trace_set_readonly_regions = remote_trace_set_readonly_regions;
   remote_ops.to_trace_start = remote_trace_start;
   remote_ops.to_get_trace_status = remote_get_trace_status;
+  remote_ops.to_get_tracepoint_status = remote_get_tracepoint_status;
   remote_ops.to_trace_stop = remote_trace_stop;
   remote_ops.to_trace_find = remote_trace_find;
   remote_ops.to_get_trace_state_variable_value
@@ -10577,6 +10670,7 @@ Specify the serial device it is connected to\n\
   remote_ops.to_get_min_fast_tracepoint_insn_len = remote_get_min_fast_tracepoint_insn_len;
   remote_ops.to_set_disconnected_tracing = remote_set_disconnected_tracing;
   remote_ops.to_set_circular_trace_buffer = remote_set_circular_trace_buffer;
+  remote_ops.to_set_trace_notes = remote_set_trace_notes;
   remote_ops.to_core_of_thread = remote_core_of_thread;
   remote_ops.to_verify_memory = remote_verify_memory;
   remote_ops.to_get_tib_address = remote_get_tib_address;
index 09be1ba..6358b00 100644 (file)
@@ -682,6 +682,7 @@ update_current_target (void)
       INHERIT (to_trace_set_readonly_regions, t);
       INHERIT (to_trace_start, t);
       INHERIT (to_get_trace_status, t);
+      INHERIT (to_get_tracepoint_status, t);
       INHERIT (to_trace_stop, t);
       INHERIT (to_trace_find, t);
       INHERIT (to_get_trace_state_variable_value, t);
@@ -692,6 +693,7 @@ update_current_target (void)
       INHERIT (to_get_min_fast_tracepoint_insn_len, t);
       INHERIT (to_set_disconnected_tracing, t);
       INHERIT (to_set_circular_trace_buffer, t);
+      INHERIT (to_set_trace_notes, t);
       INHERIT (to_get_tib_address, t);
       INHERIT (to_set_permissions, t);
       INHERIT (to_static_tracepoint_marker_at, t);
@@ -873,6 +875,9 @@ update_current_target (void)
   de_fault (to_get_trace_status,
            (int (*) (struct trace_status *))
            return_minus_one);
+  de_fault (to_get_tracepoint_status,
+           (void (*) (struct breakpoint *, struct uploaded_tp *))
+           tcomplain);
   de_fault (to_trace_stop,
            (void (*) (void))
            tcomplain);
@@ -903,6 +908,9 @@ update_current_target (void)
   de_fault (to_set_circular_trace_buffer,
            (void (*) (int))
            target_ignore);
+  de_fault (to_set_trace_notes,
+           (int (*) (char *, char *, char *))
+           return_zero);
   de_fault (to_get_tib_address,
            (int (*) (ptid_t, CORE_ADDR *))
            tcomplain);
index 87f0bb9..73c8f7c 100644 (file)
@@ -713,6 +713,9 @@ struct target_ops
     /* Get the current status of a tracing run.  */
     int (*to_get_trace_status) (struct trace_status *ts);
 
+    void (*to_get_tracepoint_status) (struct breakpoint *tp,
+                                     struct uploaded_tp *utp);
+
     /* Stop a trace run.  */
     void (*to_trace_stop) (void);
 
@@ -749,6 +752,10 @@ struct target_ops
     void (*to_set_disconnected_tracing) (int val);
     void (*to_set_circular_trace_buffer) (int val);
 
+    /* Add/change textual notes about the trace run, returning 1 if
+       successful, 0 otherwise.  */
+    int (*to_set_trace_notes) (char *user, char *notes, char* stopnotes);
+
     /* Return the processor core that thread PTID was last seen on.
        This information is updated only when:
        - update_thread_list is called
@@ -1508,6 +1515,9 @@ extern int target_search_memory (CORE_ADDR start_addr,
 #define target_get_trace_status(ts) \
   (*current_target.to_get_trace_status) (ts)
 
+#define target_get_tracepoint_status(tp,utp)           \
+  (*current_target.to_get_tracepoint_status) (tp, utp)
+
 #define target_trace_stop() \
   (*current_target.to_trace_stop) ()
 
@@ -1538,6 +1548,9 @@ extern int target_search_memory (CORE_ADDR start_addr,
 #define        target_set_circular_trace_buffer(val)   \
   (*current_target.to_set_circular_trace_buffer) (val)
 
+#define        target_set_trace_notes(user,notes,stopnotes)            \
+  (*current_target.to_set_trace_notes) ((user), (notes), (stopnotes))
+
 #define target_get_tib_address(ptid, addr) \
   (*current_target.to_get_tib_address) ((ptid), (addr))
 
index 86aecc2..d407158 100644 (file)
@@ -1,3 +1,8 @@
+2011-11-20  Stan Shebs  <stan@codesourcery.com>
+
+       * gdb.trace/tstatus.exp: New.
+       * gdb.trace/actions.c: Include string.h.
+
 2011-11-18  Yao Qi  <yao@codesourcery.com>
 
        * gdb.trace/pending.exp: New.
index ae3c1c3..270e1e1 100644 (file)
@@ -2,6 +2,8 @@
  * Test program for trace action commands
  */
 
+#include <string.h>
+
 static char   gdb_char_test;
 static short  gdb_short_test;
 static long   gdb_long_test;
diff --git a/gdb/testsuite/gdb.trace/tstatus.exp b/gdb/testsuite/gdb.trace/tstatus.exp
new file mode 100644 (file)
index 0000000..36f925d
--- /dev/null
@@ -0,0 +1,172 @@
+# Copyright 2011 Free Software Foundation, Inc.
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+load_lib "trace-support.exp"
+
+set testfile "actions"
+set executable $testfile
+set srcfile $testfile.c
+set binfile $objdir/$subdir/$testfile
+set expfile tstatus.exp
+
+if [prepare_for_testing $expfile $executable $srcfile \
+       [list debug]] {
+    untested "failed to prepare for trace tests"
+    return -1
+}
+
+if ![runto_main] {
+    fail "Can't run to main to check for trace support"
+    return -1
+}
+
+if ![gdb_target_supports_trace] {
+    unsupported "target does not support trace"
+    return -1
+}
+
+set libipa $objdir/../gdbserver/libinproctrace.so
+gdb_load_shlibs $libipa
+
+# Can't use prepare_for_testing, because that splits compiling into
+# building objects and then linking, and we'd fail with "linker input
+# file unused because linking not done" when building the object.
+
+if { [gdb_compile "$srcdir/$subdir/$srcfile" $binfile \
+         executable [list debug shlib=$libipa] ] != "" } {
+    untested "failed to compile ftrace tests"
+    return -1
+}
+clean_restart ${executable}
+
+if ![runto_main] {
+    fail "Can't run to main for ftrace tests"
+    return 0
+}
+
+proc run_trace_experiment {} {
+
+#    gdb_test_no_output "set debug remote 1" ""
+
+    gdb_test "continue" \
+       ".*Breakpoint \[0-9\]+, begin .*" \
+       "advance to trace begin"
+
+    gdb_test_no_output "tstart my tracing note" "start trace experiment"
+
+    gdb_test "continue" \
+       ".*Breakpoint \[0-9\]+, end .*" \
+       "advance through tracing"
+
+    # Now play with tstatus a bit.
+    # Since note support is optional, we need to match both with and without
+    # cases.
+
+    gdb_test_multiple "tstatus" "check on trace status" {
+       -re "Trace is running.*Trace will stop if GDB disconnects\.\[\r\n\]+Trace notes: my tracing note\.\[\r\n\]+Not looking at any trace frame\..*" {
+           pass "tstatus reports trace note"
+       }
+       -re "Trace is running.*Trace will stop if GDB disconnects\.\[\r\n\]+Not looking at any trace frame.*" {
+           pass "tstatus does not report any trace note"
+       }
+    }
+
+    gdb_test "set trace-notes different note" "" "change tracing note"
+
+    gdb_test_multiple "tstatus" "check on trace status with diff note" {
+       -re "Trace is running.*Trace will stop if GDB disconnects\.\[\r\n\]+Trace notes: different note\.\[\r\n\]+Not looking at any trace frame\..*" {
+           pass "tstatus reports different trace note"
+       }
+       -re "Trace is running.*Trace will stop if GDB disconnects\.\[\r\n\]+Not looking at any trace frame.*" {
+           pass "tstatus does not report any different trace note"
+       }
+    }
+
+    gdb_test "set trace-user me me me" "" "change tracing user"
+
+    gdb_test_multiple "tstatus" "check on trace status with diff note" {
+       -re "Trace is running.*Trace will stop if GDB disconnects\.\[\r\n\]+Trace user is me me me\.\[\r\n\]+Trace notes: different note\.\[\r\n\]+Not looking at any trace frame\..*" {
+           pass "tstatus reports trace user"
+       }
+       -re "Trace is running.*Trace will stop if GDB disconnects\.\[\r\n\]+Not looking at any trace frame.*" {
+           pass "tstatus does not report trace user"
+       }
+    }
+
+    gdb_test_no_output "tstop because I can" "trace stopped with note"
+
+    gdb_test_multiple "tstatus" "check on trace status after stop" {
+       -re "Trace stopped by a tstop command (because I can)\..*Trace will stop if GDB disconnects\.\[\r\n\]+Trace user is me me me\.\[\r\n\]+Trace notes: different note\.\[\r\n\]+Not looking at any trace frame\..*" {
+           pass "tstatus reports trace stop reason"
+       }
+       -re "Trace stopped by a tstop command\..*" {
+           pass "tstatus does not report trace stop reason"
+       }
+    }
+
+    # Tracepoint hit count is optional, so pass it either way.
+
+    gdb_test_multiple "info trace" "show tracepoint state" {
+       -re "actions\.c:\[0-9\]+\[\r\n\]+\[\t ]+tracepoint already hit 1 time\[\r\n\]+\[\t ]+collect parm" {
+           pass "info trace reports tracepoint hit count"
+       }
+       -re "actions\.c:\[0-9\]+\[\r\n\]+\[\t ]+collect parm" {
+           pass "info trace does not report tracepoint hit count"
+       }
+    }
+}
+
+proc test_tracepoints {} {
+
+    gdb_test "break begin" ".*" ""
+
+    gdb_test "break end" ".*" ""
+
+    gdb_test "trace gdb_c_test" "Tracepoint .*" \
+       "tracepoint at gdb_c_test"
+
+    gdb_trace_setactions "collect at set_point: define actions" \
+       "" \
+       "collect parm" "^$"
+    set fastgood 0
+
+    gdb_test_multiple "ftrace gdb_recursion_test" "set fast tracepoint" {
+       -re "May not have a fast tracepoint at .*" {
+           pass "4-byte fast tracepoint could not be set"
+       }
+       -re "Fast tracepoint .*" {
+           pass "4-byte fast tracepoint is set"
+           set fastgood 1
+       }
+    }
+
+    if { $fastgood } {
+
+       gdb_trace_setactions "collect at four_byter: define actions" \
+           "" \
+           "collect globvar, anarg" "^$"
+    }
+
+    run_trace_experiment
+
+}
+
+gdb_reinitialize_dir $srcdir/$subdir
+
+if { [gdb_test "info sharedlibrary" ".*libinproctrace\.so.*" "IPA loaded"] != 0 } {
+    untested "Could not find IPA lib loaded"
+    return 1
+}
+
+test_tracepoints
index aeeb585..ec88b66 100644 (file)
@@ -224,6 +224,7 @@ proc gdbserver_start { options arguments } {
        global gdbserver_reconnect_p
        if {![info exists gdbserver_reconnect_p] || !$gdbserver_reconnect_p} {
            # GDB client could accidentally connect to a stale server.
+           # append gdbserver_command " --debug --once"
            append gdbserver_command " --once"
        }
 
index 97ab633..9b0738e 100644 (file)
@@ -178,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);
@@ -199,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);
 
@@ -1686,14 +1696,15 @@ process_tracepoint_on_disconnect (void)
 
 
 void
-start_tracing (void)
+start_tracing (char *notes)
 {
   VEC(breakpoint_p) *tp_vec = NULL;
   int ix;
   struct breakpoint *b;
   struct trace_state_variable *tsv;
   int any_enabled = 0, num_to_download = 0;
-  
+  int ret;
+
   tp_vec = all_tracepoints ();
 
   /* No point in tracing without any tracepoints...  */
@@ -1779,6 +1790,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 ();
 
@@ -1790,12 +1808,11 @@ start_tracing (void)
   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)
@@ -1809,23 +1826,37 @@ 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;
+
   target_trace_stop ();
+
+  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;
 }
@@ -1835,7 +1866,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);
 
@@ -1866,7 +1899,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"));
@@ -1882,10 +1919,10 @@ trace_status_command (char *args, int from_tty)
          if (ts->stopping_tracepoint)
            printf_filtered (_("Trace stopped by an "
                               "error (%s, tracepoint %d).\n"),
-                            ts->error_desc, ts->stopping_tracepoint);
+                            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"));
@@ -1936,12 +1973,46 @@ 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"),
+                          ts->start_time / 1000000, ts->start_time % 1000000,
+                          run_time / 1000000, run_time % 1000000);
+       }
+      else
+       printf_filtered (_("Trace started at %ld.%06ld secs.\n"),
+                        ts->start_time / 1000000, ts->start_time % 1000000);
+    }
+  else if (ts->stop_time)
+    printf_filtered (_("Trace stopped at %ld.%06ld secs.\n"),
+                    ts->stop_time / 1000000, 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
@@ -2024,7 +2095,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);
            }
        }
     }
@@ -2040,6 +2111,20 @@ 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",
+              ts->start_time / 1000000, ts->start_time % 1000000);
+    ui_out_field_string (uiout, "start-time", buf);
+    xsnprintf (buf, sizeof buf, "%ld.%06ld",
+              ts->stop_time / 1000000, ts->stop_time % 1000000);
+    ui_out_field_string (uiout, "stop-time", buf);
+  }
 }
 
 /* This function handles the details of what to do about an ongoing
@@ -2881,9 +2966,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);
+      char *buf = (char *) alloca (strlen (ts->stop_desc) * 2 + 1);
 
-      bin2hex ((gdb_byte *) ts->error_desc, buf, 0);
+      bin2hex ((gdb_byte *) ts->stop_desc, buf, 0);
       fprintf (fp, ":%s", buf);
     }
   fprintf (fp, ":%x", ts->stopping_tracepoint);
@@ -2936,6 +3021,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",
               utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
@@ -2971,6 +3059,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);
@@ -3041,17 +3134,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
@@ -3061,6 +3148,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
@@ -3638,20 +3761,26 @@ tfile_interp_line (char *line,
 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++)
     {
@@ -3659,6 +3788,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);
@@ -3678,7 +3810,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)
@@ -3691,14 +3838,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;
@@ -3734,6 +3879,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.  */
@@ -3747,6 +3918,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".  */
 
@@ -3848,6 +4039,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
@@ -3923,6 +4120,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
@@ -4464,6 +4668,7 @@ init_tfile_ops (void)
   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;
@@ -5008,11 +5213,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\
@@ -5087,6 +5298,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);
index bf8fa44..b112352 100644 (file)
@@ -79,6 +79,7 @@ struct trace_status
   /* This is true if the value of the running field is known.  */
   int running_known;
 
+  /* This is true when the trace experiment is actually running.  */
   int running;
 
   enum trace_stop_reason stop_reason;
@@ -88,9 +89,11 @@ struct trace_status
      stop.  */
   int stopping_tracepoint;
 
-  /* If stop_reason is tracepoint_error, this is a human-readable
-     string that describes the error that happened on the target.  */
-  char *error_desc;
+  /* If stop_reason is tstop_command or tracepoint_error, this is an
+     arbitrary string that may describe the reason for the stop in
+     more detail.  */
+
+  char *stop_desc;
 
   /* Number of traceframes currently in the buffer.  */
 
@@ -117,6 +120,22 @@ struct trace_status
      target does not report a value, assume 0.  */
 
   int circular_buffer;
+
+  /* The "name" of the person running the trace.  This is an
+     arbitrary string.  */
+
+  char *user_name;
+
+  /* "Notes" about the trace.  This is an arbitrary string not
+     interpreted by GDBserver in any special way.  */
+
+  char *notes;
+
+  /* The calendar times at which the trace run started and stopped,
+     both expressed in microseconds of Unix time.  */
+
+  LONGEST start_time;
+  LONGEST stop_time;
 };
 
 struct trace_status *current_trace_status (void);
@@ -154,6 +173,12 @@ struct uploaded_tp
   /* List of original strings defining the tracepoint's actions.  */
   VEC(char_ptr) *cmd_strings;
 
+  /* The tracepoint's current hit count.  */
+  int hit_count;
+
+  /* The tracepoint's current traceframe usage.  */
+  ULONGEST traceframe_usage;
+
   struct uploaded_tp *next;
 };
 
@@ -229,6 +254,9 @@ extern int encode_source_string (int num, ULONGEST addr,
 
 extern void parse_trace_status (char *line, struct trace_status *ts);
 
+extern void parse_tracepoint_status (char *p, struct breakpoint *tp,
+                                    struct uploaded_tp *utp);
+
 extern void parse_tracepoint_definition (char *line,
                                         struct uploaded_tp **utpp);
 extern void parse_tsv_definition (char *line, struct uploaded_tsv **utsvp);
@@ -241,8 +269,8 @@ extern void merge_uploaded_trace_state_variables (struct uploaded_tsv **utsvp);
 
 extern void disconnect_tracing (int from_tty);
 
-extern void start_tracing (void);
-extern void stop_tracing (void);
+extern void start_tracing (char *notes);
+extern void stop_tracing (char *notes);
 
 extern void trace_status_mi (int on_stop);