aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog43
-rw-r--r--gdb/NEWS35
-rw-r--r--gdb/breakpoint.c18
-rw-r--r--gdb/breakpoint.h4
-rw-r--r--gdb/doc/ChangeLog6
-rw-r--r--gdb/doc/gdb.texinfo82
-rw-r--r--gdb/gdbserver/ChangeLog17
-rw-r--r--gdb/gdbserver/tracepoint.c169
-rw-r--r--gdb/mi/mi-main.c4
-rw-r--r--gdb/remote.c94
-rw-r--r--gdb/target.c8
-rw-r--r--gdb/target.h13
-rw-r--r--gdb/testsuite/ChangeLog5
-rw-r--r--gdb/testsuite/gdb.trace/actions.c2
-rw-r--r--gdb/testsuite/gdb.trace/tstatus.exp172
-rw-r--r--gdb/testsuite/lib/gdbserver-support.exp1
-rw-r--r--gdb/tracepoint.c316
-rw-r--r--gdb/tracepoint.h38
18 files changed, 962 insertions, 65 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 4004235..cda1411 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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.
diff --git a/gdb/NEWS b/gdb/NEWS
index c4e59c4..93a799b 100644
--- 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
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index dc891c0..ab0d402 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -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;
}
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 8e03264..96cc96a 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -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;
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index f915110..4b3a99f 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -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
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 13e01bc..f4f68a3 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -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
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 844fb18..c556eeb 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -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>
diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
index b00df05..e6a5bbc 100644
--- a/gdb/gdbserver/tracepoint.c
+++ b/gdb/gdbserver/tracepoint.c
@@ -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
{
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index a9c7652..5270fe4 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -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);
}
diff --git a/gdb/remote.c b/gdb/remote.c
index 6ac5fc0..8fa5c1a 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -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;
diff --git a/gdb/target.c b/gdb/target.c
index 09be1ba..6358b00 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -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);
diff --git a/gdb/target.h b/gdb/target.h
index 87f0bb9..73c8f7c 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -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))
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 86aecc2..d407158 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -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.
diff --git a/gdb/testsuite/gdb.trace/actions.c b/gdb/testsuite/gdb.trace/actions.c
index ae3c1c3..270e1e1 100644
--- a/gdb/testsuite/gdb.trace/actions.c
+++ b/gdb/testsuite/gdb.trace/actions.c
@@ -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
index 0000000..36f925d
--- /dev/null
+++ b/gdb/testsuite/gdb.trace/tstatus.exp
@@ -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
diff --git a/gdb/testsuite/lib/gdbserver-support.exp b/gdb/testsuite/lib/gdbserver-support.exp
index aeeb585..ec88b66 100644
--- a/gdb/testsuite/lib/gdbserver-support.exp
+++ b/gdb/testsuite/lib/gdbserver-support.exp
@@ -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"
}
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 97ab633..9b0738e 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -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);
diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
index bf8fa44..b112352 100644
--- a/gdb/tracepoint.h
+++ b/gdb/tracepoint.h
@@ -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);